数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字
例如:
输入:{1,2, 3, 2, 2, 2, 5, 4, 2}
输出:2
用排序可以解决,一个数字出现次数超过数组长度一半,那肯定是中位数。但是排序的代价太高了,所以不用此方法
Hash
使用hashMap将key存储为数字,value是出现的次数。然后判断value是否大于len/2即可
public static int moreThanHalfNum(int[] array) {
if (array == null) {
return 0;
}
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < array.length; i++) {
map.put(array[i], map.getOrDefault(array[i], 0) + 1);
if (map.get(array[i]) > array.length / 2) {
return array[i];
}
}
return 0;
}
巧妙解法
-
记录两个变量,一个result表示数字,另一个times表示出现的次数
-
result和它下一个值比较,若相等则次数+1,否则-1
-
当times等于零就将result设置为下一个值
public static int moreThanHalfNum2(int [] array) {
if(array==null||array.length==0)
return 0;
int len = array.length;
int result = array[0];
int times = 1;
for (int i = 1; i < len; i++) {
if (times == 0) {
result = array[i];
times = 1;
continue;
}
if (result == array[i]) {
times++;
} else {
times--;
}
}
return times == 0 ? 0 : result;
}
数组中只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次,找出那个只出现了一次的元素。
输入:[4,1,2,1,2] 输出:4
Set解决
Set集合不允许重复值,可以利用这一特性解决
public static Integer findOneNum(int[] arr) {
Set<Integer> set = new HashSet<Integer>();
for(int i : arr) {
if(!set.add(i))//添加不成功返回false,前加上!运算符变为true
set.remove(i);//移除集合中与这个要添加的数重复的元素
}
//注意边界条件的处理
if(set.size() == 0)
return null;
//如果Set集合长度为0,返回null表示没找到
return set.toArray(new Integer[set.size()])[0];
}
位运算
异或运算的几个规则是:
0^0 = 0; 0^a = a; a^a = 0; a ^ b ^ a = b.
只有一个数字出现一次,其他都是两次。只需要利用位运算规则遍历一边就可以得出结果
public static int findOneNum(int[] arr) {
int flag = 0;
for(int i : arr) {
flag ^= i;
}
return flag;
}
颜色分类问题(荷兰国旗)
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
双指针解决
先将0移动到前面..再将1移动到2前面...
public static void sortColors(int[] nums) {
int len = nums.length;
int slow = 0, fast = 0;
//将所有0交换到前面
while (fast < len){
if (nums[fast] == 0) {
int temp = nums[fast];
nums[fast] = nums[slow];
nums[slow] = temp;
slow++;
}
fast++;
}
//将两个指针位置同步
fast = slow;
//将所有1交换到2前面
while (fast < len) {
if (nums[fast] == 1) {
int temp = nums[fast];
nums[fast] = nums[slow];
nums[slow] = temp;
slow++;
}
fast++;
}
}
三个指针
-
创建三个指针left代表左边(0)right代表右边(2)index是自由指针(向前移动)
-
index遇到0就与left交换,并且这两个指针各向前一步
-
index遇到2就与right交换,right向前一步,index不动(因为不确定交换过来的值是什么,万一换过来的是2呢...)
-
index没遇到0或2就向前一步
public static void sortColorsByThreePoints(int[] nums) {
int left = 0, right = nums.length-1;
int index = 0;
//等于的情况参考220011
while (index <= right) {
if (nums[index] == 0) {
swap(nums, index++, left++);
} else if (nums[index] == 2) {
swap(nums, index, right--);
}else {
index++;
}
}
}
private static void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
单调数组元素都不要
在单调数组中,将出现的重复元素一个都不要
示例1: 原始数组为[1,1,2,2,3,4,5],由于1,2存在重复,所以数组变成[3,4,5] 示例2: 原始数组为[0,2,2,2,2,2,5],由于2存在重复,所以返回[0,5]
三个指针
public static int clearElements(int[] arr){
int slow = 0, fast = 0, index = 0;
int len = arr.length;
while (fast < len) {
if (fast == len-1 || arr[fast] != arr[fast + 1]) {
if (slow == len-1 || arr[slow] != arr[slow + 1]) {
arr[index++] = arr[slow];
}
slow = ++fast;
}else {
fast++;
}
}
return index;
}