Leetcode(448)——找到所有数组中消失的数字

Leetcode(448)——找到所有数组中消失的数字

题目

在这里插入图片描述

题解

注:下面两个方法其实都是使用了同样的原理,只是交互元素到对应下标索引上的方法不一样

方法1.1:

思路

​  1. 鸽笼原理(The Pigeonhole Principle)+
​  2. 交互元素到对应下表索引上

​  由题目知,nums 且 nums 中的数字一定属于 [1, n]。所以可以在第一个 for 循环中让 nums[i] 加上特定次数的 nums.size() 。而 nums[i]nums.size() 的次数等于数组 nums 中 i+1 值的个数
​  至于为什么是加 nums.size() ,是为了后续的判断。在最后一次 for 循环遍历 nums 时,如果 nums[i] 的值大于 nums.size() ,那么它就是在 [1, n] 范围内且出现在 nums 中的数字。所以第一次 for 循环所加值必须大于或等于 nums.size()
  至于在第一次 for 循环时,在对某个值添加了 nums.size() 后,该如何知道其原值以继续执行让 nums[i] 加上特定次数的 nums.size() 。通过取余 (num - 1) % n 就可以获取其原值。因为 nums 的数字属于 [1, n]。

例子:[4,3,2,7,8,2,3,1] 在第一个 for 循环结束后是 [12,19,18,15,8,2,11,9]
nums[1] 被改变了2次得到19,即 nums 中出现了两次2,nums[2] 被改变了2次变成了18,即 nums 中出现了两次3。
代码实现
class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        int n = nums.size();	// 增值必须大于或等于 nums.size()
        for (auto& num : nums) {
            int x = (num - 1) % n;	// 获取原值
            nums[x] += n;
        }
        vector<int> ret;
        for (int i = 0; i < n; i++) {
            if (nums[i] <= n) {	// 原值一定属于 [1,nums.size()]
                ret.push_back(i + 1);
            }
        }
        return ret;
    }
};
复杂度分析

时间复杂度: O ( N ) O(N) O(N) N N N 表示数组的长度
空间复杂度: O ( 1 ) O(1) O(1)

方法1.2:

思路

​  1. 将所有正数作为数组下标,置对应数组值为负值。
​  2. 那么,仍为正数的位置即为消失的数字。

思考了一下为什么必须是 nums[abs(nums[i])-1] = -abs(nums[abs(nums[i])-1]); 因为如果直接设置成0,那后面遍历到这个位置的时候就没办法使用它的值了; 而如果直接乘以-1设置成相反数,那么后面遍历到重复元素的时候,这个负数又会变回正数,从而对结果产生影响; 因此只能等于负的绝对值,确保万无一失。

举个例子:
原始数组:[4,3,2,7,8,2,3,1]
重置后为:[-4,-3,-2,-7,8,2,-3,-1]
结论:[8,2] 分别对应的 index 为 [5,6] (消失的数字)
代码实现
class Solution {
public:
	vector<int> findDisappearedNumbers(vector<int>& nums) {
		// abs(n) 函数返回 n 的绝对值
    	for (int i = 0; i < nums.size(); ++i)
        	nums[abs(nums[i])-1] = -abs(nums[abs(nums[i])-1]);
    	vector<int> res;
    	for (int i = 0; i < nums.size(); ++i){
        	if (nums[i] > 0)
            	res.push_back(i+1);
    	}
    	return res;
    }
}
复杂度分析

时间复杂度: O ( N ) O(N) O(N) N N N 表示数组的长度
空间复杂度: O ( 1 ) O(1) O(1)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值