首页 > 其他分享 >力扣-442. 数组中重复的数据

力扣-442. 数组中重复的数据

时间:2024-04-25 17:12:30浏览次数:20  
标签:nums int 442 位置 力扣 vector 数组 ans

1.题目介绍

题目地址(442. 数组中重复的数据 - 力扣(LeetCode))

https://leetcode.cn/problems/find-all-duplicates-in-an-array/

题目描述

给你一个长度为 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 <= 105
  • 1 <= nums[i] <= n
  • nums 中的每个元素出现 一次两次

2.题解

2.1 哈希表

思路

哈希表记录出现次数,但是这种方法是错误的,并不满足使用常量级空间存储哈希表的要求!!!

代码

  • 语言支持:C++

C++ Code:


class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        unordered_map<int, int> mp;
        int n = nums.size();
        for(int num: nums){
            if(mp.count(num)){
                mp[num]++;
            }else{
                mp.emplace(num, 1);
            }
        }

        vector<int> ans;
        for(int i = 1; i <= n; i++){
            if(mp[i] == 2){
                ans.push_back(i);
            }
        }
        return ans;
    }
};

复杂度分析

令 n 为数组长度。

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(n)\)

2.2 交换位置

思路

我们知道应该将num[i] 这个值放到对应 nums[nums[i] - 1]的位置上, 所以我们考虑遍历数组, 进行 swap(num[i], nums[nums[i] - 1]), 这样就行了吗?
不行, 换出的值位置是对了, 换进来的却是不对的, 但是我们是按照从前向后的顺序执行,换进前面的数如果不对,后面就有可能一直不对下去,导致错误
[4,3,2,7,8,2,3,1]
0 [7,3,2,4,8,2,3,1]
1 [7,2,3,4,8,2,3,1]
2 [7,2,3,4,8,2,3,1]
3 [7,2,3,4,8,2,3,1]
4 [7,2,3,4,1,2,3,8]
5 [7,2,3,4,1,2,3,8]
6 [7,2,3,4,1,2,3,8]
7 [7,2,3,4,1,2,3,8]

我们思考后, 猜想是否应该保证遍历时每次的首项正确即可? 即最后 下标 == 值 - 1 ;(i == nums[i] - 1;)
像是加上 while (i != nums[i] - 1) 可以吗? 保证位置0对应1,位置1对应2.... 错误的, 这样判断如果对应位置的数不存在,比如像如果数组中不存在3,就会不断交换导致死循环!!!!

正确思路应该是: while (nums[i] != nums[nums[i] - 1]) , 想法和上面还是一样的 下标 == 值 - 1
while循环的停止条件 1. 重复元素-两个位置[i 和 nums[i] - 1]](像是下面例子中的两个3) 2.元素处于正确位置
这样就不是保证每个位置i对应的值都正确, 而是保证数组中所有存在的数作为位置下标nums[i], 值为 nums[nums[i] - 1]
执行的顺序不是按0-n, 而是按遍历数组的元素顺序来(每次确保数组的每一个元素位置正确), 最后停止时当前位置元素必定为重复元素/位于正确位置的数组元素, 前面不可能还有没有正确排位置的数组元素, 故继续向后遍历
[4,3,2,7,8,2,3,1]
0.1 [7,3,2,4,8,2,3,1]
0.2 [3,3,2,4,8,2,7,1]
0.3 [2,3,3,4,8,2,7,1]
0.4 [3,2,3,4,8,2,7,1]
1.1 [3,2,3,4,8,2,7,1]
2.1 [3,2,3,4,8,2,7,1]
3.1 [3,2,3,4,8,2,7,1]
4.1 [3,2,3,4,1,2,7,8]
4.2 [1,2,3,4,3,2,7,8]
5.1 [1,2,3,4,3,2,7,8]
6.1 [1,2,3,4,3,2,7,8]
7.1 [1,2,3,4,3,2,7,8]
经检查[5,6]不在数组中!

代码

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        vector<int> ans; 
        int n = nums.size();
        for(int i = 0; i < n; i++){
            while(nums[i] != nums[nums[i] - 1])
                swap(nums[i], nums[nums[i] - 1]); // 这里切不可只交换一次, 我们考虑一种极端情况,如果第一个数和第i个数交换后,第一个数到达正确位置,而第i个数到达错误位置
        }

        for(int i = 0; i < n; i++){
            if(nums[i] != i + 1){
                ans.push_back(nums[i]);
            }
        }
        return ans;
    }
};

2.3 索引-值

思路

同力扣-448. 找到所有数组中消失的数字
那里是出现零次和一次的数,这里是出现一次和两次的数,原理是一样的

代码

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        vector<int> ans; 
        int n = nums.size();
        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] > 2 * n){
                ans.push_back(i + 1);
            }
        }
        return ans;
    }
};

2.3 正负号标记

思路

思路同2.2, 我们需要一个能实时还原为下标的标记,然后就可以使用该标记判断哪些元素时重复出现了
这里使用正负号, 标记的时候使其变负即可; 而还原的时候简单的使用abs即可还原!

代码

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        vector<int> ans; 
        int n = nums.size();
        for(int i = 0; i < n; i++){
            int x = abs(nums[i]) - 1;  
            if(nums[x] > 0){
                nums[x] = -nums[x];
            } else{
                ans.push_back(x + 1);
            }         
        }
        return ans;
    }
};

标签:nums,int,442,位置,力扣,vector,数组,ans
From: https://www.cnblogs.com/trmbh12/p/18158142

相关文章

  • 力扣-448. 找到所有数组中消失的数字
    1.题目题目地址(448.找到所有数组中消失的数字-力扣(LeetCode))https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array/题目描述给你一个含n个整数的数组nums,其中nums[i]在区间[1,n]内。请你找出所有在[1,n]范围内但没有出现在nums中的数字,......
  • php几个数组的奇淫巧计
    使用array_map()应用函数到数组的每个元素。$numbers=[1,2,3,4,5];$squares=array_map(function($number){return$number*$number;},$numbers);//$squares=[1,4,9,16,25]使用array_filter()过滤数组中的元素。$numbers=[1,2,3,4,5];$o......
  • C++数组的连续性
    虚拟上连续,物理上大概率连续,除非不在同一个物理页上,并且物理页不连续时数组在物理地址空间是否连续,对于用户空间的程序是不需要关心的。另外,对于一个抽象层次很高的编程语言,数组是不是一定要保证虚拟地址空间连续,感觉也是可以研究的。例如,java的数组就不连续?所以array到底是在......
  • 力扣-645. 错误的集合
    1.题目介绍题目地址(645.错误的集合-力扣(LeetCode))https://leetcode.cn/problems/set-mismatch/题目描述集合s包含从1到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合丢失了一个数字并且有一个数字重复。......
  • 力扣-697. 数组的度
    1.题目介绍题目地址(697.数组的度-力扣(LeetCode))https://leetcode.cn/problems/degree-of-an-array/题目描述给定一个非空且只包含非负数的整数数组 nums,数组的度的定义是指数组里任一元素出现频数的最大值。你的任务是在nums中找到与 nums 拥有相同大小的度的最短......
  • 第三章 字符串、向量和数组
    当用+连接string对象和字符串字面值的时候,必须确保有一个操作数是string对象。头文件包含字符处理相关函数使用范围for循环实际上是在使用迭代器循环,所以不能再循环里改变容易容量或执行让迭代器失效的操作。数组的名字在很多情况下会转换成指针,auto会推导出指针,但是decltype还......
  • 力扣-396. 旋转函数
    1.题目介绍题目地址(396.旋转函数-力扣(LeetCode))https://leetcode.cn/problems/rotate-function/题目描述给定一个长度为n的整数数组 nums 。假设 arrk 是数组 nums 顺时针旋转k个位置后的数组,我们定义 nums 的旋转函数  F 为:F(k)=0*arrk[0]+1*......
  • 力扣-189. 轮转数组
    1.题目题目地址(189.轮转数组-力扣(LeetCode))https://leetcode.cn/problems/rotate-array/题目描述给定一个整数数组nums,将数组中的元素向右轮转k 个位置,其中 k 是非负数。 示例1:输入:nums=[1,2,3,4,5,6,7],k=3输出:[5,6,7,1,2,3,4]解释:向右轮转1步......
  • 笔记/C++中的数组排序
    在C++中,std::sort函数是一个用于对容器(如数组、向量等)进行排序的通用算法。它定义在<algorithm>头文件中,并接受两个迭代器参数,分别指向要排序的范围的开始和结束位置。此外,std::sort还可以接受一个可选的比较函数或lambda表达式,用于自定义排序规则。以下是std::sort函数的基本用......
  • C 数组
    创建数组数组是一组相同类型的值,按照顺序储存在一起。数组通过变量名后加方括号表示,方括号里面是数组的成员数量。intarr[100];上面示例声明了一个数组arr,里面包含100个成员,每个成员都是int类型。注意,声明数组时,必须给出数组的大小。数组的成员从0开始编号,所以数组arr[100]......