51寻找数组中出现次数超一半的数

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;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值