• 287. 寻找重复数


    287. 寻找重复数

    题意

    在这里插入图片描述


    解一

    • 二分答案

    简单解释,官解也很详细。

    定义 d p [ i ] {dp[i]} dp[i] 表示 n u m s [ i ] nums[i] nums[i] < = i <=i <=i 的数的个数。

    看这样一个序列:
    nums:3 1 3 4 2
    dp: 1 2 4 5

    性质:自重复的数起,之后所有 d p [ i ] dp[i] dp[i] > i >i >i ,之前都 < = i <=i <=i

    在看这样一个序列:
    nums:3 1 3 4 3
    dp: 1 1 4 5

    尽管重复了多次,但是还是满足上面的性质。

    那么我们二分答案,统计 < = m i d <=mid <=mid 的数的个数,如果个数 > m i d >mid >mid ,说明是在右侧,可能是答案, r = m i d r=mid r=mid,否则 l = m i d + 1 l=mid+1 l=mid+1

    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int n = nums.size();
            int l = 1, r = n;
            while(l < r) {
                int mid = (l + r) >> 1;
                auto f = [=](int x){
                    int res = 0;
                    for (int i = 0; i < n; i++)
                        if(nums[i] <= x) res += 1;
                    return res <= x;
                };
                if(f(mid)) l = mid + 1;
                else r = mid;
            }
            return r;
        }
    };
    /* 一旦加上了重复的数,那么之后一定更大
    // 二分check,更小就不要,说明在答案左,l向右调整。
        nums: 1 3 2 4 2
    
        [1234]: 1 3 4 5
            mid: 3 -> res = 4, r = 3
            mid: 2 -> res = 3, r = 2
            mid: 1 -> res = 1, l = 2
            l == r = 2
        
        nums: 1 3 2 3 4 3
    
        [1234]: 1 2 5 6
            mid: 3 -> res = 5, r = 3
            mid: 2 -> res = 2, l = 3
            l == r = 3
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    解二

    • 二进制

    • 重复一次

      • 重复的数为 x x x [ 1 , n ] [1,n] [1,n] 都各出现一次,外加 x x x 多出现一次。
      • 统计二进制下 1 1 1 的个数,原序列相比 [ 1 , n ] [1,n] [1,n] 序列,多出的 1 1 1 都是由 x x x 产生。
    • 重复多次

      • 重复的数为 x x x x x x 代替 [ 1 , n ] [1,n] [1,n] 中没出现的数 y y y,外加 x x x 多出现一次。

      • 四种情况:00、01、10、11(以下x,y表示某一位为1或0)

        • x = 0 , y = 0 x=0,y=0 x=0,y=0:<=
        • x = 0 , y = 1 x=0,y=1 x=0,y=1:<=
        • x = 1 , y = 0 x=1,y=0 x=1,y=0:>
        • x = 1 , y = 1 x=1,y=1 x=1,y=1:>

    所以,对于 > > > 的情况,将该位 1 1 1 加上即可。

    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int n = nums.size();
            int res = 0;
            for (int i = 0; i < 31; i++) {
                int x = 0, y = 0;
                for (int j = 0; j < n; j++) {
                    if(nums[j] & (1 << i)) x += 1;
                }
                for (int j = 1; j < n; j++) {
                    if(j & (1 << i)) y += 1;
                }
                if(x > y) res |= (1 << i);
            }
            return res;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    解三

    • 快慢指针

    n + 1 n + 1 n+1个数, [ 1 , n ] [1,n] [1,n] 范围内。每个位置 i i i 连边 i − i- i> n u m s [ i ] nums[i] nums[i]

    3 1 3 4 2
    0 1 2 3 4

    建边:0->3, 1->1, 2->3, 3->4, 4->2

    在这里插入图片描述
    明显重复的 3 3 3 是环的入口。

    又点 0 0 0 只可能有出边,不可能自环。所以定义快慢指针 l , r l,r l,r 都从 0 0 0 开始。

    然后就是环形链表找入口的常规解法:

    • 慢一步、快二步
    • 慢置为 0 0 0
    • 慢一步、快一步
    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int l = 0, r = 0;
            do {
                l = nums[l];
                r = nums[nums[r]];
            } while(l != r);
            l = 0;
            while(l != r) {
                l = nums[l];
                r = nums[r];
            }
            return l;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    MySQL4(多表查询)
    1、Spring简介
    前端自动化构建-Gulp实现前端插件开发
    机器学习泛化误差
    MySQL学习笔记(九)MVCC
    Linux 查看属于某个组(例如docker组)的所有用户
    Polygon zkEVM协议治理、升级及其流程
    主页整理:8月1日---9月10日
    实体链指(1)Entity Linking 综述
    c语言中链栈的基本操作
  • 原文地址:https://blog.csdn.net/qq_52678569/article/details/125580635