LeetCode——桶的思想

桶的思想

考虑使用情况

  • 在数组内数据不是很大
  • a[i] ≤ a[i].lena[i] ≥ 0时可以考虑使用
  • 数组中元素都为正或都为负

Easy

剑指Offer03. 数组中重复的数字

题目描述

image.png

思路
  • 把数组想象成一排座位,数组下标表示座位号,数组中的元素值想象成小朋友的名字(根据题意,会有重名),一开始小朋友们随意坐在椅子上。
  • 我们的目标是让小朋友i要坐在i号椅子上(如:元素3要坐在num[3]上)
  • 遍历数组只要i号椅子上坐的不是iif(num[i] != i)),那么去看看i号椅子上坐的是谁
    • 如果i号椅子上坐的也是i(即出现同名情况),跳出循环即可
    • 如果i号椅子上坐的不是i,那么将i与i号椅子上的元素交换(exch()
代码
public int findRepeatNumber(int[] nums) {
        int result = 0;
        for (int i = 0; i < nums.length; i++) {
            while(nums[i] != i){
                if (nums[i] == nums[nums[i]]){
                    result =  nums[i];
                    break;
                }
                exch(nums,i,nums[i]);
            }
        }
        return result;
    }

    private void exch(int[] nums, int a, int b){
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }

448. 找到所有数组中消失的数字


Medium

442. 数组中重复的数据

题目描述

image.png

思路
  • 对于数组中的元素,因为所有元素都大于0(nums[1] > 1 > 0),所以可以使用正负来表示出现的次数,表示还没出现过,表示出现过一次,因为nums[1] > 1 > 0,所以Math.abs(nums[i])为元素原值,下文使用absx来表示元素真正的值
    • 对于大部分的元素(absx != len),nums[absx]的正负可以表示x出现的次数
    • x == nums.length时数组会越界,此时将元素x的出现次数在num[0]中表示
  • 由题意:元素可能出现两次或一次
    • 当元素x第一次出现时将num[i]取负数
    • 如果已经为负则表示,元素i已出现过,此次为第二次出现,将元素i加入list
代码
class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> list = new ArrayList<>();
        int len = nums.length;
        for (int i = 0; i < len; i++){
            int absx = Math.abs(nums[i]);

            if (absx == len){
                if (nums[0] < 0){
                    list.add(len);
                } else{
                    nums[0] = - nums[0];
                }
            }else{
                if (nums[absx] < 0){
                    list.add(absx);
                } else{
                    nums[absx] = - nums[absx];
                }
            }
        }

        return list;
    }
}

Hard

41.缺失的第一个正数

题目描述

image.png

思路
  • 遍历数组若数组中没有1,那么1就是没有出现的最小的正整数。
  • 如果有1
    • 数据整理
      • 数组中a[i] <= 0的数不会对结果造成影响。
      • 当数组中的元素从1递增至nums.length时,可以得到最大的结果为nums.length + 1,如当nums[] == {1,2,3,4,5}时,缺失的第一个正数为6。所以a[i] > nums.length + 1的数不会对结果造成影响。
      • 由于数组容量的关系,我们把num.length+1单独讨论,即也将数组中的num.length+1当做不会对结果造成影响的数据
      • 将不会对结果造成影响的数据全部置为1
    • 至此数组中元素全部为正,且1 <= nums[i] <= num.length
    • 此后我们用num[1..num.length-1]的正负来表示[1…nums.length-1]的是否出现;使用num[0]的正负来表示num.length-1
      • 正(初始状态)表示没有出现过
      • 负表示出现过
    • 最后按照num[1…num.length-1],num[0]的顺序遍历数组,遇到的第一个大于0的数即为没有出现的最小的正整数,若全部小于0,则答案为nums.length + 1;
代码
class Solution {
    public int firstMissingPositive(int[] nums) {
        //如果没有1,那么1就是没有出现的最小的正整数
        int count1 = 0;
        for (int i = 0; i < nums.length; i++){
            if (nums[i] == 1){
                count1++;
            }
        }
        if (count1 == 0) {
            return 1;
        }

        //如果有1
            //数组中小于等于0的元素没有意义
            //数组中最大的有意义的元素与数组长度有关,如:len==5 时,按数组中元素从1开始递增nums[] == {1,2,3,4,5}
            //把没有意义的元素全部变成1
        for (int i = 0; i < nums.length; i++){
            if (nums[i] <= 0 || nums[i] > nums.length){
                nums[i] = 1;
            }
        }
            //此时数组中元素全部为正
            //此时数组中元素,0 < a[i] <= num.length
            //使用num[i]的正负来表示i是否出现过,为正(初始状态)表示没有出现过,为负表示出现过,如num[3] == -x,表示3在数组中出现过
                //由于a[num.length]会导致数组越界,且数组中不包含0(所以a[0]未被使用),所以将num.length的是否出现在a[0]中表示
        for (int i = 0; i < nums.length; i++) {
            int x = Math.abs(nums[i]);
            if (x == nums.length){
                nums[0] = - Math.abs(nums[0]);
            } else {
                nums[x] = - Math.abs(nums[x]);
            }
        }

        //判断从[1,nums.length-1]的正负
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] > 0){
                return i;
            }
        }
        //判断从nums.length-1的正负
        if (nums[0] > 0){
            return nums.length;
        }

        return nums.length+1;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值