一定要保证,数组中其余数都出现了M次,只有一种数出现了K次。并且1<= K <M。
分析:
- 因为int类型共有32位,所以可申请一个32位长度 int[32] help来辅助完成这个功能
- 将传进来的 int[ ] 进行遍历,每个数循环32次,循环中将数组中元素进行右移 并且 &1的处理,如果 &1后,结果不为0,就可以得到该元素在32位二进制中什么位置上有1, 将得到的结果在help数组对应下标位置进行累加。
- 第一次遍历完成后, help数组已经构建完成,接下来遍历help数组
- 将help数组每个元素 % m,假设:元素1,在老数组中出现了5次(m),那根据1的二进制位 0001的情况,在help数组中下标0的位置就应该是5,所以% m的得数如果不为0,就说明出现k次的数,在对应的二进制位置的值是1,以此类推,就可以得到出现k次的数具体是什么。
代码实现:
public static int findKTimeNum(int[] arr, int m, int k) {
int[] help = new int[32];
for (int num : arr) {
for (int i = 0; i < 32; i++) {
//num右移,看哪个位置有1,help数组在对应位置累加1.
help[i] += (num >> i) & 1;
}
}
int target = 0;
for (int i = 0; i < help.length; i++) {
//不为0,说明出现k次的数在此处有值
if (help[i] % m != 0) {
target |= (1 << i);
}
}
return target;
}
对数器(帮助测试)
public static int[] randomArray(int k, int m, int range, int kinds) {
int time = k;
int kNum = generatorNum(range);
//一共有多少类数,至少应该有2种。
int maxKindsTimes = (int) (kinds * Math.random()) + 2;
int[] arr = new int[time + m * (maxKindsTimes - 1)];
//将出现k次的数先填充进数组
for (int i = 0; i < time; i++) {
arr[i] = kNum;
}
//总种类 - 1,去掉K的种类
maxKindsTimes--;
//将生成的数放在Set中,确保每种类型的数不相同
HashSet set = new HashSet();
set.add(kNum);
//如果种类不为0
while (maxKindsTimes != 0) {
int mNum;
do {
mNum = generatorNum(range);
//如果随机出来的数和之前的相等。重新random
} while (set.contains(mNum));
set.add(mNum);
//总种类--
maxKindsTimes--;
for (int i = 0; i < m; i++) {
arr[time++] = mNum;
}
}
return arr;
}
public static int generatorNum(int range) {
return (int) (Math.random() * (range + 1)) - (int) (Math.random() * (range + 1));
}
public static int test(int[] arr, int k, int m) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int num : arr) {
if (map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
int ans = 0;
for (int num : map.keySet()) {
if (map.get(num) == k) {
ans = num;
break;
}
}
return ans;
}
测试代码
public static void main(String[] args) {
int range = 5;
int kinds = 3;
int max = 5;
int timesNum = 100000;
for (int i = 0; i < timesNum; i++) {
int a = (int) (Math.random() * max) + 1;
int b = (int) (Math.random() * max) + 1;
int k = Math.min(a, b);
int m = Math.max(a, b);
if (m == k) {
m += 1;
}
int[] arr = randomArray(k, m, range, kinds);
int kTimeNum = findKTimeNum(arr, m, k);
int test = test(arr, k, m);
if (kTimeNum != test) {
System.out.println("测试错误");
}
}
}