51寻找数组中出现次数超一半的数
一看题目就想用hash表,但是要求空间复杂度为1,说明不可以用哈希表去存。一直在原地数组上思考,类似桶排序,可是这取决于数值的大小,最后还是看了题解,学到了。
思想是:出现不一致的数据就一起消去,因为众数一定超过数组长度的一半,所以最差情况下,所有数据都和它消一次,它还是可以最后剩下。
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
int cond=-1;//候选值
int count=0;//选票
for(int i=0;i<array.length;i++){
if(count==0){//没候选 则当前值作为候选
cond=array[i];
count++;
}
else{
if(cond==array[i]) count++;//当前值刚好是候选人 选票加1
else count--;//当前值不是后续,一起消去,选票-1;
}
}
return cond;
}
}
这样空间复杂度为O(1),时间复杂度为o(N)
52 数组中只出现一次的两个数字
因为要求空间复杂度为1,不能用哈希去存,只能用其他方法。
这题要用到异或运算的性质
第4点是重点。
1.总体思路:有一道和它类似的题,它所指的数组中只有一个出现一次的数,而解法就是从头开始不断地异或下去,由于相同的两个数异或值为0,因此最终的异或结果就是答案
2.而本题有两个只出现一次的数a和b,我们按异或方法最终只能得到a异或b的值,就需要思考一下这两个数异或的结果有何特点
3.我们可以发现,首先这两个数一定不同,故异或结果一定不为0,那么a异或b的结果中一定有一位为1,假设是第x位,那么就说明了a和b的二进制的第x位是不同,根据这一特点,我们可以将数组分为两个集合,即第x位为1的数和第x位为0的数,两部分的异或和即为a和b的值
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型一维数组
* @return int整型一维数组
*/
public int[] FindNumsAppearOnce (int[] array) {
// write code here
int res1 = 0;
int res2=0;
int tmp=0;
for(int i=0;i<array.length;i++){//得到a异或b的结果
tmp ^=array[i];
}
int k=1;
while((k&tmp)==0) k<<=1;//找到左边第一个不同的位 左移等价于*2
for(int i=0;i<array.length;i++){
if((array[i]&k)==0) res1^=array[i];
else res2^=array[i];
}
if(res1>res2) return new int[]{res2,res1};
else return new int[]{res1,res2};
}
}
时间复杂度为O(n),空间复杂度为O(1)
53 缺失的第一个正整数
用set或者哈希表就太简单
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @return int整型
*/
public int minNumberDisappeared (int[] nums) {
// write code here
Set<Integer> set = new HashSet<>();
for(int i=0;i<nums.length;i++){
set.add(nums[i]);
}
for(int i=1;i<set.size()+1;i++){
if(!set.contains(i)) return i;
}
return set.size()+1;
}
}
要求空间复杂度为1的话还需要再思考
思路:
前面提到了数组要么缺失1~n1~n1~n中的某个数字,要么缺失n+1n+1n+1,而数组正好有下标0~n−10 ~ n-10~n−1可以对应数字1~n1~n1~n,因此只要数字1~n1~n1~n中某个数字出现,我们就可以将对应下标的值做一个标记,最后没有被标记的下标就是缺失的值。
具体做法:
step 1:我们可以先遍历数组将所有的负数都修改成n+1。
step 2:然后再遍历数组,每当遇到一个元素绝对值不超过n时,则表示这个元素是1~n中出现的元素,我们可以将这个数值对应的下标里的元素改成负数,相当于每个出现过的正整数,我们把与它值相等的下标都指向一个负数,这就是类似哈希表的实现原理的操作。
step 3:最后遍历数组的时候碰到的第一个非负数,它的下标就是没有出现的第一个正整数,因为它在之前的过程中没有被修改,说明它这个下标对应的正整数没有出现过。
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @return int整型
*/
public int minNumberDisappeared (int[] nums) {
// write code here
for(int i=0;i<nums.length;i++){
if(nums[i]<=0) nums[i]=nums.length+2;//负数记为n+1
}
for(int i=0;i<nums.length;i++){
//对于1-n的数字 判断条件内要绝对值!!!dubug了很久
if(Math.abs(nums[i])<=nums.length){
nums[Math.abs(nums[i])-1] = Math.abs(nums[Math.abs(nums[i])-1])*(-1);//这里也要绝对值,确保乘几次都是负的
}}
for(int i=0;i<nums.length;i++){
//找到第一个元素不为负数的下标
if(nums[i]>0) return i+1;
}
return nums.length+1;
}
}