牛客春招刷题训练营 算法 Java 3月28日 不要三句号的歪 尼科彻斯定理 隐匿社交网络
#牛客春招刷题训练营# + https://www.nowcoder.com/discuss/726480854079250432
题目地址
https://www.nowcoder.com/practice/7cbb7d96fb354f7995d9af1ccf8906b4?channelPut=w25springcamp
https://www.nowcoder.com/practice/dbace3a5b3c4480e86ee3277f3fe1e85?channelPut=w25springcamp
https://www.nowcoder.com/practice/2870f9db6aeb4eb08fbd6460397f9bf4?channelPut=w25springcamp
1.不要三句号的歪
这是我们写的第一个方法
先用指针寻址
然后往回找
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); String str=in.next(); str=str.replace("."," "); str=str.replace(" ",""); // System.out.println(str); int qian=-1; int hou=-1; for(int i=0;i<str.length()-1;i++){ if(str.charAt(i)==','&&str.charAt(i+1)==','){ qian=i-1; hou=i+2; break; } } // System.out.println(qian+" "+hou); StringBuilder sb1=new StringBuilder(); sb1.append(str.charAt(qian)); qian--; while(qian>0&&str.charAt(qian)!=','){ sb1.append(str.charAt(qian)); qian--; } String str1=sb1.reverse().toString(); // System.out.println(str1); StringBuilder sb2=new StringBuilder(); sb2.append(str.charAt(hou)); hou++; while(hou<str.length()&&str.charAt(hou)!=','){ sb2.append(str.charAt(hou)); hou++; } String str2=sb2.toString(); // System.out.println(str2); System.out.print(Long.parseLong(str2)-Long.parseLong(str1)-1); } }
这是我看答案的写法
顿悟
我们做三次切割即可 具体逻辑就两次
第一次切割 我们将字符串切割成左右两部分 切割字符串 ",...,"
第二次切割 我们将左边的字符串按 "," 切割
第三次切割 我们将右边的字符串按 "," 切割
然后 后面那个数组的第一部分 减去前面数组的最后一部分
最后将答案减去 1 就行
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); String str=in.next(); String[] arr=str.split(",...,"); String[] arr1=arr[0].split(","); String[] arr2=arr[1].split(","); System.out.println(Long.parseLong(arr2[0])-Long.parseLong(arr1[arr1.length-1])-1); } }
2.尼科彻斯定理
依旧是找规律
我们发现中间那个数等于 n*n
然后再推出两边的元素
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); // 注意 hasNext 和 hasNextLine 的区别 int n=in.nextInt(); long middle = n*n; long k=middle-n+1; for(int i=0;i<n;i++){ System.out.print(k); if(i!=n-1){ System.out.print("+"); } k+=2; } } }
3.隐匿社交网络
很显然这题的处理查找问题上 子集元素最多问题 我们可以使用并查集
然后就是什么时候合并
按位与操作运算得到的结果是 0 的两个数不能合并
两个二进制的表示在每一位上不能同时为 1 的两个数按位与运算是 0
所以我们找到了每一位的数
只要是有某一位上的数都是 1 就进行合并
合并后 看一下最大的子集的元素个数 就得出了我们需要的答案
import java.util.Scanner; public class Main { // 定义常量 N static final int N = 100006; // 二维数组 ejz 用于存储每个数的二进制形式 static int[][] ejz = new int[N][1000]; // 数组 arr 用于存储输入的数 static long[] arr = new long[N]; // p 数组用于维护集合,si 数组用于维护集合中的个数 static int[] p = new int[N]; static int[] si = new int[N]; // 查找元素所在集合的根节点 static int find(int a) { if (p[a] != a) { p[a] = find(p[a]); } return p[a]; } // 合并两个元素所在的集合 static void merge(int a, int b) { int pa = find(a); int pb = find(b); if (pa != pb) { p[pa] = pb; si[pb] += si[pa]; } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int T = scanner.nextInt(); while (T-- > 0) { int n = scanner.nextInt(); int ma_idx = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < 1000; j++) { ejz[i][j] = 0; } } for (int i = 0; i < n; i++) { arr[i] = scanner.nextLong(); long x = arr[i]; int idx = 0; while (x > 0) { ejz[i][idx] = (int) (x % 2); idx++; x /= 2; } ma_idx = Math.max(ma_idx, idx); } for (int i = 0; i < n; i++) { p[i] = i; si[i] = 1; } for (int i = 0; i < ma_idx; i++) { int j = 0; while (j < n && ejz[j][i] == 0) { j++; } for (int k = j + 1; k < n; k++) { if (ejz[k][i] == 1) { merge(k, j); } } } // 找出最大的集合大小 int ans = 1; for (int i = 0; i < n; i++) { ans = Math.max(ans, si[i]); } // 输出结果 System.out.println(ans); } scanner.close(); } }#牛客春招刷题训练营#
Java写算法