LeetCode之路:268. Missing Number

一、引言

这是一道非常简单的题目,我们做这道题的目的只有一个:尽量用更多的方法做出这道题:)

先看看题目吧:

Given an array containing n distinct numbers taken form 0, 1, 2, ..., n , find the one that is missing from the array.

For example.
Given nums = [0, 1, 3] return 2.

Note:
Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?

简单翻译下:

给定一个含有 n 个唯一的数字的数组,其中数字从 0, 1, 2,.., n 中取,请找到其中消失的那个数字。

注意:
你的算法应该是线性时间复杂度。你能在常数空间复杂度下完成这道题吗?

让我们抛开这道题的限制,我们来看看,我们一共能够想出多少个解法?

二、遍历:返回消失的数字

首先,我想到了这么一个思路:

首先排序,然后遍历这个数组,将当前位置应该显示的数字与当前数组中对应位置数字比较,如果不同则返回这个应该显示的数字

代码如下:

// my solution 1 , runtime = 39 ms
class Solution1 {
public:
    int missingNumber(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); ++i) {
            if (i != nums[i]) return i;
        }
        return nums[nums.size() - 1] + 1;
    }
};

这个方法需要注意的是,万一消失的数字是最后一个数字 n ,那么需要手动返回(因为最后一个数字 n 在数组中无法被遍历到)。

这个方法使用了 std::sort,并且多了一次遍历,时间复杂度不高,并且使用了与数组同长度的空间复杂度。

三、数学公式:n(n + 1)/2

我们还可以使用数学公式,可以说这个方法是非常妙的:

计算出从 0 到 n 的和,然后减去当前数组的和即可

代码如下:

// my solution 2 , runtime = 29 ms
// n ( n + 1) / 2
class Solution2 {
public:
    int missingNumber(vector<int>& nums) {
        int total = 0;
        for (auto i : nums) total += i;
        return nums.size() * (nums.size() + 1) / 2 - total;
    }
};

这个方法,只有一次遍历,因此是 O(n) 的线性时间复杂度,空间复杂度只有 O(1),可以说是完美达标。

四、BitManipulation:位操作

如果对于位操作熟悉的话,你可能会想到使用异或操作:

遍历数组,将所有元素异或,同时将当前位置应该显示的数字异或,最后的结果即为那个消失的数字

代码如下:

// my solution 4 , runtime = 26 ms
class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int result = 0;
        for (int i = 0; i < nums.size(); ++i) {
            result ^= nums[i];
            result ^= i;
        }
        return result ^= nums.size();
    }
};

这个方法同样需要注意,在对数组的遍历过程中,遍历不到数字 n,因此最后需要再异或一个数字 n(即 nums.size())。

同样的,这个方法的时间复杂度为 O(n),空间复杂度为 O(1),可以说是完美切合题意的方法。

五、总结

这是一道比较有趣的题目,在使用多个方法解题的过程中,我们使用了不同的思路,这也是一种锤炼。

最后,以许嵩的《通关》这首歌的歌词结尾:

我感谢自己平凡
敢爱敢恨没负担
湖面穿行的谬赞和妄断
不过是通关之夜的辗转

共勉!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值