数学与数字6:LeetCode268. 丢失的数字

算法学习的一个原则是”复杂问题简单做,简单问题深入做“,这是一道简单的问题,但是可以深入分析。我们参考宫水三叶等的文章,发现这个题竟然有5种做法。

先看题意:

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

示例:
输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。

题目没有说数组是否为排序的,那我们就要按照无序来处理。

首先想到的是排序一下再找nums[i]==i,不相等的地方就是答案。

class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
        for (int i = 0; i < n; i++) {
            if (nums[i] != i) return i;
        }
        return n;
    }
}

第二种自然是hash,利用 nums 的数值范围为 [0,n],且只有一个值缺失,我们可以直接开一个大小为 n+1 的数组充当哈希表,进行计数,没被统计到的数值即是答案。

class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length;
        boolean[] hash = new boolean[n + 1];
        for (int i = 0; i < n; i++) hash[nums[i]] = true;
        for (int i = 0; i < n; i++) {
            if (!hash[i]) return i;
        }
        return n;
    }
}

第三种是算出总和再作差,这种思想在解决很多无序的数字问题时都可以用到。

利用 nums 的数值范围为 [1,n],我们可以先计算出 [1,n] 的总和sum(利用等差数列求和公式),再计算nums 的总和cur,两者之间的差值即是nums 中缺失的数字。

class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length;
        int cur = 0, sum = n * (n + 1) / 2;
        for (int i : nums) cur += i;
        return sum - cur;
    }
}

 第四种方式是异或,找缺失数、找出现一次数都是异或的经典应用。这种思想在找重复数字时也会遇到的。

我们可以先求得 [1,n] 的异或和 ans,然后用 ans 对各个 nums[i] 进行异或。

这样最终得到的异或和表达式中,只有缺失元素出现次数为 1 次,其余元素均出现两次(x ⊕x = 0),即最终答案 ans 为缺失元素。

class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length;
        int ans = 0;
        for (int i = 0; i <= n; i++) ans ^= i;
        for (int i : nums) ans ^= i;
        return ans;
    }
}

第五种,其实上面第一种我们可以进一步深入做,那就是将上面的for循环该成二分查找,根据nums[i]与i的大小情况来决定向左还是向右折半。感兴趣的同学可以研究一下。

你可能感兴趣的:(算法,排序算法,算法)