LeetCode刷题之HOT100之找到数组中消失的数字

2024/5/24 今天早上没有下雨,太好了。下周就要搬到二楼会议室开发了,很多计划都要被打破了。事已至此,先做题吧!

在这里插入图片描述

2、逻辑分析

题目的要求是:给定一个长度为n的整数数组nums,要输出在[1,n]范围内但没有出现在nums中的数字,以数组的形式返回。想了五分钟以上,想不出来。看了官方题解也没怎么看懂,还是用哈希集合来存储,再遍历,没有出现的数就是我们要找的数。

3、代码演示

public List<Integer> findDisappearedNumbers(int[] nums) {
        List<Integer> res = new ArrayList<>();
        Set<Integer> set = new HashSet<>();
        // 遍历数组nums,将数组中的数字添加到HashSet中 
        for(int i = 0 ; i < nums.length; i++){
            set.add(nums[i]);
        }
        // 遍历从1到nums.length的数字
        for(int i = 1; i <= nums.length; i++){
            // 如果数字i不在HashSet中(即不存在于nums数组中),则它是缺失的数字
            if(!set.contains(i)){
                res.add(i);
            }
        }
        // 返回缺失的数字列表  
        return res;
    }

这里我们利用了Set集合中元素的唯一性来求解,逻辑简单,比较好想出来。时间复杂度:O(n),空间复杂度:O(n)。性能可能就没有那么好。还是来看看优化的算法:

  1. 利用数组 nums 本身作为哈希表来标记数字的出现情况。
  2. 将每个数字 num 映射到索引 (num-1) % n 处,并将对应位置的值加上 n。这样做的目的是为了标记该数字出现过。
  3. 在第二次遍历数组时,检查每个位置上的值是否小于等于 n。如果是的话,说明该位置上的数字没有出现过,将其添加到结果列表中。

下面看看代码:

public List<Integer> findDisappearedNumbers(int[] nums) {
        int n = nums.length;
        // 遍历数组 nums
        for(int num : nums){
            // 将数字 num 映射到索引范围 [0, n-1] 内
            int x = (num - 1)% n;
            // 将 nums[x] 加上 n,表示该数字出现过
            nums[x] += n; 
        }
        // 创建结果列表 ret
        List<Integer> ret = new ArrayList<Integer>();
        // 再次遍历数组 nums
        for(int i = 0; i < n ; i++){
            // 如果 nums[i] 小于等于 n,说明该位置上的数字没有出现过
            if(nums[i] <= n){
                // 将该位置 i+1 添加到结果列表中
                ret.add(i + 1);
            }
        }
        return ret;
    } 

其实仔细看看就可以理清逻辑了,下面看看它的运行过程是怎么样的:

假设我们有以下输入数组 nums = [4,3,2,7,8,2,3,1]。

首先,我们获取数组的长度 n = 8。

  1. 开始遍历数组 nums:

num = 4: x = (4-1) % 8 = 3, 将 nums[3] 加上 8, 即 nums[3] = 15。
num = 3: x = (3-1) % 8 = 2, 将 nums[2] 加上 8, 即 nums[2] = 10。
num = 2: x = (2-1) % 8 = 1, 将 nums[1] 加上 8, 即 nums[1] = 11。
num = 7: x = (7-1) % 8 = 6, 将 nums[6] 加上 8, 即 nums[6] = 11。
num = 8: x = (8-1) % 8 = 7, 将 nums[7] 加上 8, 即 nums[7] = 9。
num = 2: x = (2-1) % 8 = 1, 将 nums[1] 加上 8, 即 nums[1] = 19。
num = 3: x = (3-1) % 8 = 2, 将 nums[2] 加上 8, 即 nums[7] = 18。
num = 1: x = (1-1) % 8 = 0, 将 nums[0] 加上 8, 即 nums[0] = 12。
修改后的数组 nums = [12, 19, 18, 15, 8, 2, 11, 9]。

  1. 再次遍历数组 nums:

nums[0] = 12 > 8, 所以 1 出现了。
nums[1] = 19 > 8, 所以 2 出现了。
nums[2] = 18 > 8, 所以 3 出现了。
nums[3] = 15 > 8, 所以 4 出现了。
nums[4] = 8 <= 8, 所以 5 没有出现。
nums[5] = 2 <= 8, 所以 6 没有出现。
nums[6] = 11 > 8, 所以 7 出现了。
nums[7] = 9 > 8, 所以 8 出现了。
将没有出现的数字 5、6 添加到结果列表 ret 中,最终 ret = [5,6]。
通过这个例子,我们可以看到这个算法是如何利用数组本身作为哈希表来标记数字的出现情况,并最终找出消失的数字。整个过程非常高效,只需要遍历数组两次。

时间复杂度:O(n),空间复杂度:O(1)。

好啦,做完啦,有些许收获,休息一下,BYE!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值