Leetcode 424 数组中重复的数据

一、问题描述

  给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
  你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。

二、示例及约束

示例 1:
输入: nums = [4,3,2,7,8,2,3,1]
输出: [2,3]

示例 2:
输入: nums = [1,1,2]
输出: [1]

示例 3:
输入: nums = [1]
输出: [ ]

提示:
● n == nums.length
● 1 <= n <= 1 0 5 10^5 105
● 1 <= nums[i] <= n
● nums 中的每个元素出现 一次两次

三、代码

方法一:交换元素到对应位置

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        int n = nums.size();
        /*由于有数字出现了2次,则表示有数字没有出现过,因此可以将每个数放在对应的位置,
        其余的数即为题设所需,数组下标范围是[0,n-1],因此数i要放到i-1的位置上
        */
        for (int i = 0; i < n; ++i) {
        //判断该数是否已经放置到正确的位置,如果没有的话,将其放置到nums[i]-1的位置上
            while (nums[i] != nums[nums[i] - 1]) {
                swap(nums[i], nums[nums[i] - 1]);
            }
        }
        vector<int> ans;
        //下标不一致的数会在连续的位置上,依次进行输出即可
        for (int i = 0; i < n; ++i) {
            if (nums[i] - 1 != i) {
                ans.push_back(nums[i]);
            }
        }
        return ans;
    }
};

方法二:使用正负号作为标记

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        int n = nums.size();
        vector<int> ans;
        /*由于次数只有1次和2次,可以用负号表示出现了1次,正号表示出现了2次,
        在遍历过程中,若遍历到数nums[i]时,将i对应的下标nums[x-1]其变为负,表示遍历过1次,若再次遍历到nums[i]时,则此时的nums[x-1]已经是负数,此时将其绝对值x输出,即可满足题设需求
        */
        for (int i = 0; i < n; ++i) {
            int x = abs(nums[i]);//由于数组下标和输出结果为正,加绝对值
            //如果值为正,说明第一次遍历到这个数,取负
            if (nums[x - 1] > 0) {
                nums[x - 1] = -nums[x - 1];
            }
            //如果值为负,说明第二次遍历到这个数,输出绝对值x
            else {
                ans.push_back(x);
            }
        }
        return ans;
    }
};

四、总结

由于题设要求O(1)的空间复杂度,所以两种方法都是对原数组进行修改。
时间复杂度:
方法一:O(n),每一次交换操作会使得至少一个元素被交换到对应的正确位置,因此交换的次数为 O(n),总时间复杂度为 O(n)。
方法二:O(n),只需要对数组 nums 进行一次遍历。
空间复杂度:
均为O(1)

方法时间复杂度空间复杂度
方法一O( n n n)O(1)
方法二O( n n n)O(1)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值