• 【LeetCode】Day137-寻找消失&重复数


    题目1、找到所有数组中消失的数字

    448. 找到所有数组中消失的数字【简单】

    题解

    如果用一个哈希表对数字进行计数,之后统计出现次数为0的数字是很容易的,但是如何用O(n)时间复杂度不使用额外空间来解决此题呢?
    提示里说利用输入数组完成,还是没想到怎么做,于是看了官解。

    由于nums的数字范围都在[1,n]中,我们可以利用这一范围之外的数字,来表示该数是够存在。

    具体做法就是遍历nums,每遇到一个数字x,就让nums[x-1]增加n,最后找谁没大于n,就是没存在过。

    至于为什么让x-1下标+n而不是x下标呢?因为nums数组中数组范围在1~n,而数字%n的余数范围在0~n-1,所以需要让下标映射上

    class Solution {
        public List<Integer> findDisappearedNumbers(int[] nums) {
            List<Integer>res=new ArrayList<>();
            int n=nums.length;
            for(int i=0;i<n;i++){
                int x=(nums[i]-1)%n;
                nums[x]+=n;
            }
            for(int i=0;i<n;i++){
                if(nums[i]<=n)
                    res.add(i+1);
            }
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    时间复杂度: O ( n ) O(n) O(n)

    空间复杂度 O ( 1 ) O(1) O(1)

    题目2、寻找重复数

    287. 寻找重复数【中等】

    题解

    和上一题类似,如果用一个哈希表对数字进行计数,之后统计出现次数为0的数字是很容易的,但是如何不修改数组 nums不使用额外空间来解决此题呢?

    二分法

    定义cnt[i] 为nums数组中<=i 的数有多少个,以[1,3,4,2,2]为例,列出每个数字的cnt值:
    在这里插入图片描述
    可以发现cnt是单调递增的,因此我们可以利用二分法来解题,对1~n进行二分法查找,找到cnt[i]>nums[i]的最小 i

    class Solution {
        public int findDuplicate(int[] nums) {
            int n=nums.length;
            int l=1,r=n,res=-1;
            //二分法遍历数字1~n
            while(l<=r){
                int cnt=0,mid=(l+r)/2;
                //找小于mid的数
                for(int i=0;i<n;i++){
                    if(nums[i]<=mid)
                        cnt++;
                }
                if(cnt<=mid)
                    l=mid+1;
                else{
                    r=mid-1;
                    res=mid;
                }
            }
            return res;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

    空间复杂度: O ( 1 ) O(1) O(1)

    快慢指针法

    对nums数组建图,每个位置 i 连一条 i->nums[i]边,如下图所示:
    在这里插入图片描述
    由于存在重复数字,那么这个位置一定至少有两条指向他的边,因此一定存在环,我们要找到的就是环的入口,等价于142. 环形链表 II 问题,使用快慢指针解决。

    • 判断有环?
      快指针每次走两步,慢指针每次走一步,能相遇就有环。

    • 入环点在哪?
      找到相遇位置后,固定 fast 指针,slow 指针从头结点开始,两个人一步一步走,相遇点即入环点。(可以证明)

    class Solution {
        public int findDuplicate(int[] nums) {
            int n=nums.length;
            int slow=0,fast=0;
            //slow走一步,fast走两步
            do{
                slow=nums[slow];
                fast=nums[nums[fast]];
            }while(slow!=fast);
            //找入环点
            slow=0;
            while(slow!=fast){
                slow=nums[slow];
                fast=nums[fast];
            }
            return slow;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    时间复杂度: O ( n ) O(n) O(n)

    空间复杂度: O ( 1 ) O(1) O(1)

  • 相关阅读:
    查看MySQL的初始密码
    【树】在二叉树中增加一行 层序遍历
    【C语言从0到1之指针】(详解,赶紧收藏期末考试备用)
    金仓数据库KingbaseES客户端编程接口指南-ado.net(8. 事务)
    java代理Proxy以及实际PRC场景中的使用
    arm64架构 统信UOS搭建PXE无盘启动Linux系统(麒麟桌面为例)
    【最详细】最新最全Redis面试大全(70道)
    Kafka由浅入深(6) Sender线程执行源码解析
    在windows和macos安装multipass
    W5300-TOE Arduino 网络服务器
  • 原文地址:https://blog.csdn.net/qq_43417265/article/details/126901654