287. 寻找重复数

177 阅读1分钟

题目描述

要求:

  • 时间复杂度小于O(n^2)
  • 空间复杂度为O(1),set就别想了
  • 不修改数组 nums

方法1: 快慢指针floyd判圈算法,不修改原数组

image.png

image.png

class Solution {
    public int findDuplicate(int[] nums) {
        int slow = 0, fast = 0;
        do {
            slow = nums[slow];
            fast = nums[nums[fast]];
        } while (slow != fast);
        // 相遇了
        
        // 找入口
        int cur = 0;
        while (cur != slow) {
            slow = nums[slow];
            cur = nums[cur];
        }
        
        return cur;
        
        
        //这么写上来就进不了循环
        // while (slow != fast) {
        //     slow = nums[slow];
        //     fast = nums[nums[fast]];
        // }
        // return nums[cur]; //错误写法,相当于return node.next

    }
}

方法2:原地hash,但是修改了nums

思路同 剑指 Offer 03. 数组中重复的数字

  • 这个题里的归位是指 nums[index] = index + 1
  • 如果数组中有重复数字,那么在归位的过程中会遇到重复,因为有相同的数字来抢占对应的index
    • 比如:[1,2,3,4,5,5], 两个数字5如果都要归位的话,他们对应的index都是4,当一个5先归位到index=4的格子,另一个5在归位时发现index = 4上已经有一个5了,说明有重复的两个5。
  • 这种原地哈希只适用于数字范围和数组大小有限定关系。像[1,2,554,452,9,452] 就不能用了。 3E324479B6D4C0218086031F38ADC455.png
class Solution {
    public int findDuplicate(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            //如果没有归位
            while (nums[i] != i + 1) {
                //当前数字对应的正确的index上已经被相同的数字抢占,说明遇到重复数
                if (nums[i] == nums[nums[i] - 1]) {
                    return nums[i];
                }
                swap(nums, i, nums[i] - 1);
            }
        }
        return -1;
    }

    public void swap(int[] nums, int m, int n) {
        int tmp = nums[m];
        nums[m] = nums[n];
        nums[n] = tmp;
    }
}