Leetcode刷题65-287. 寻找重复数(C++详细解法!!!)

题目来源:链接: [https://leetcode-cn.com/problems/find-the-duplicate-number/]

从今天(2019-4-25)开始使用纯英文题目(开始先中英文对照),慢慢适应。有两个原因:

  1. 提高英文能力
  2. 为接下来的秋招最准备(昨天被思杰的纯英文面试题虐哭了。。。)

1.Describe

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Example 1:

Input: [1,3,4,2,2]
Output: 2

Example 2:

Input: [1,3,4,2,2]
Output: 2

Note:

1. You must not modify the array (assume the array is read only).
2. You must use only constant, O(1) extra space.
3. Your runtime complexity should be less than O(n2).
4. There is only one duplicate number in the array, but it could be repeated more than once.

2.我的解决方案

medium 类型题目。
//只能使用额外的 O(1) 的空间 : 表示该程序所占用的空间和所用数据量无关。
不满足题目条件但是 AC的代码:

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int tmp[nums.size()] = {0};
        int res = 0;
        for(int i = 0; i < nums.size(); ++i)
        {
            ++tmp[nums[i]];
        }
        for(int i = 0; i < nums.size(); ++i)
        {
            if(tmp[nums[i]] > 1)
            {
                res = nums[i];
                break;
            }
        }
        return res;
    }
};

3.大神们的解决方案

详细解释见:[LeetCode]Find the Duplicate Number
方法:
快慢指针思想, fast 和 slow 是指针, nums[slow] 表示取指针对应的元素
注意 :nums 数组中的数字都是在 1 到 n 之间的(在数组中进行游走不会越界),
因为有重复数字的出现, 所以这个游走必然是成环的, 环的入口就是重复的元素,
即按照寻找链表环入口的思路来做。

【笔记】这道题(据说)花费了计算机科学界的传奇人物Don Knuth 24小时才解出来。并且我只见过一个人(注:Keith Amling)用更短时间解出此题。

快慢指针,一个时间复杂度为O(N)的算法。

其一,对于链表问题,使用快慢指针可以判断是否有环。

其二,本题可以使用数组配合下标,抽象成链表问题。但是难点是要定位环的入口位置。

举个例子:nums = [2,5, 9 ,6,9,3,8, 9 ,7,1],构造成链表就是:2->[9]->1->5->3->6->8->7->[9],也就是在[9]处循环。

其三,快慢指针问题,会在环内的[9]->1->5->3->6->8->7->[9]任何一个节点追上,不一定是在[9]处相碰,事实上会在7处碰上。

其四,必须另起一个for循环定位环入口位置[9]。这里需要数学证明。

http://bookshadow.com/weblog/2015/09/28/leetcode-find-duplicate-number/

对“其四”简单说明一下,既然快慢指针在环内的某处已经相碰了。那么,第二个for循环遍历时,res指针还是在不停的绕环走,但是必定和i指针在环入口处相碰。


理解代码,但是没有AC,原因见下面

class Solution {
    public int findDuplicate(int[] nums) {
        /**
        快慢指针思想, fast 和 slow 是指针, nums[slow] 表示取指针对应的元素
        注意 nums 数组中的数字都是在 1 到 n 之间的(在数组中进行游走不会越界),
        因为有重复数字的出现, 所以这个游走必然是成环的, 环的入口就是重复的元素, 
        即按照寻找链表环入口的思路来做
        **/
        int fast = 0, slow = 0;
        while(true) {
            fast = nums[nums[fast]];
            slow = nums[slow];
            if(slow == fast) {
                fast = 0;
                while(nums[slow] != nums[fast]) {
                    fast = nums[fast];
                    slow = nums[slow];
                }
                return nums[slow];
            }
        }
    }
}

4.我的收获

  1. 参考维基百科关于鸽笼原理的词条链接

继续加油。。。

2019/4/25 胡云层 于南京 65

猜你喜欢

转载自blog.csdn.net/qq_40858438/article/details/89512053
今日推荐