牛客-NC156-数组中只出现一次的数(其它数出现k次)
NC156. 数组中只出现一次的数(其它数出现k次)(easy)
方法一:HashMap法
思路:这个解法是暴力解,直接统计每个数字出现的次数,再遍历返回出现一次的那个数即可。于是,可以写出以下代码:
import java.util.*;
public class Solution {
/** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param arr int一维数组 * @param k int * @return int */
public int foundOnceNumber (int[] arr, int k) {
// write code here
HashMap<Integer, Integer> ret = new HashMap<>();
for (int i = 0; i < arr.length; i++) {
if (!ret.containsKey(arr[i])) {
ret.put(arr[i], 1);
} else {
ret.put(arr[i], ret.get(arr[i]) + 1);
}
}
Set<Map.Entry<Integer, Integer>> entries = ret.entrySet();
Iterator<Map.Entry<Integer, Integer>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, Integer> next = iterator.next();
if (next.getValue() == 1) {
return next.getKey();
}
}
return -1;
}
}
时间复杂度: O(N),N表示数组arr的长度。
空间复杂度: O(N),需要使用HashMap来对数字出现的次数进行存储。
方法二:位运算法
思路:出现k次我们不能再使用之前的异或方法进行解决,但仍可以利用位运算的思想去做。因为出现k(奇数)次的数字每个位(0或者1)也是出现k(奇数)次,因此可以每一位的和能够被k整除(对k取余为0)。所以如果把每个数的二进制表示的每一位加起来,对于每一位的和,如果能被k整除,那对应那个只出现一次的数字的那一位就是0,否则对应的那一位是1。我们需要用一个长度为32(int型二进制表示最多为32位,4字节)的数组bisum保存每一位的和。
具体来讲实现过程是,先初始化为0,然后对于每个数字,遍历它二进制表示的每一位,如果这一位是1,bisum对应的那一位就加1。得到bisum后,我们再次遍历bisum,如果某个二进制位不能被k整除,即 bisum[i] % k != 0
,那么只出现一次的这个数字在当前二进制位上为1,此时要进行左移恢复,即1<<i
。
import java.util.*;
public class Solution {
/** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param arr int一维数组 * @param k int * @return int */
public int foundOnceNumber (int[] arr, int k) {
// write code here
// 对所有数字的第i位,如果它们的和对k取余是0,则只出现一次的数字为0,否则为1。
int[] bisum = new int[32];
int n = arr.length;
for (int i = 0; i < 32; i++) {
int sum = 0;
for (int j = 0; j < n; j++) {
sum += (arr[j] & 1); // 统计当前数组元素的1的个数
arr[j] = (arr[j] >> 1); // 让当前数组元素右移一位
}
bisum[i] = sum;
}
int ret = 0;
for (int i = 0; i < 32; i++) {
if (bisum[i] % k != 0) ret += (1<<i);
}
return ret;
}
}
时间复杂度: O(N),N表示数组array的长度。
空间复杂度: O(1),额外空间不包含返回所需的空间ret。