加载中...

[leetcode]第 4 天 查找算法(简单)

03. 数组中重复的数字

思路

去重,很容易想到用HashSet

class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> s = new HashSet<>();
        for(int num : nums){
            if(s.contains(num)) return num;
            s.add(num);
        }
        return -1;
    }
}

其他解法:
数组元素的 索引 和 值 是 一对多 的关系。
因此,可遍历数组并通过交换操作,使元素的 索引 与 值 一一对应(即 nums[i] = inums[i]=i )

class Solution {
    public int findRepeatNumber(int[] nums) {
        int i = 0;
        while(i < nums.length) {
            if(nums[i] == i) {
                i++;
                continue;
            }
            if(nums[nums[i]] == nums[i]) return nums[i];
            int tmp = nums[i];
            nums[i] = nums[tmp];
            nums[tmp] = tmp;
        }
        return -1;
    }
}

53.I. 在排序数组中查找数字 I

思路

很简单的题,就是循环比较num和target

class Solution {
    public int search(int[] nums, int target) {
        int count = 0;
        for(int num : nums){
            if(num == target) count++;
        }
        return count;
    }
}

遂至评论区看其他解法,然后发现,喔!二分查找
排序数组的搜索问题,首先想到二分法解决
本题要求统计排序数组nums种target的出现次数,可以转化为使用二分法找到左边界left和右边界right,target的数量=right-left - 1
流程:
1. 初始化:左边界i = 0,右边界j = len(nums) - 1
2. 循环二分:闭区间[i, j]无元素时跳出

  1. 计算中点m = (i + j)/2
  2. nums[m] < target,则target在闭区间[m + 1, j]中,i = m + 1;
  3. nums[m] > target,则target在闭区间[i, m - 1]中,j = m - 1;
  4. nums[m] = target, 右边界right在[m + 1, j]中,left在[i, m - 1]中,分两种情况:
    1. 查找右边界right,i = m + 1;
    2. 查找左边界left,j = m - 1;
    3. 返回:right - left - 1

简化:
由于数组中全为整数,可以二分查找target和target - 1的右边界

class Solution {
    public int search(int[] nums, int target) {
        return helper(nums, target) - helper(nums, target - 1);
    }

    int helper(int[] nums, int tar){
        int i = 0, j = nums.length - 1;
        while(i <= j){
            int m = (i + j)/2;
            if(nums[m] <= tar) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}

这个简化实在是太迷人了!

53 - II. 0~n-1中缺失的数字 II

思路

二分查找!分左右子组
流程:
1. 初始化:左边界i = 0,右边界j = len(nums) - 1
2. 循环二分:闭区间[i, j]无元素时跳出

  1. 计算中点m = (i + j)//2
  2. nums[m] = m,则右子组的首位元素一定在[m + 1, j]中,因此i = m + 1;
  3. nums[m] ≠ m,则左子组的末位元素一定在[i, m - 1]中,j = m - 1;
    3. 返回:最后i指向右子组的首位元素,j指向左子组的末位元素,所以返回i即可
class Solution {
    public int missingNumber(int[] nums) {
        int i = 0, j = nums.length - 1;
        while(i <= j){
            int m = (i + j)/2;
            if(nums[m] == m) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}

好像跟上一题没什么区别……

posted @ 2022-12-20 16:59  Vincy9501  阅读(11)  评论(0编辑  收藏  举报