442. 数组中重复的数据 - 力扣(LeetCode) (leetcode-cn.com)
给你一个长度为 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 中的每个元素出现 一次 或 两次
注意关键信息,1 <= nums[i] <= n ,说明数组中的元素的最大值不超过数组长度,那么我们可以根据索引,将值放入到对应的索引位置上,使其满足 i == num[i] - 1.如果不满足,则说明这些数重复了
方法一:交换位置
/**
* 方法一:将元素交换到对应的位置
*
* @param nums
* @return
*/
public static List<Integer> findDuplicates(int[] nums) {
List<Integer> ans = new ArrayList<>();
int n = nums.length;
for (int i = 0; i < n; i++) {
// 交换
while (nums[i] != nums[nums[i] - 1]) {
int tmp = nums[nums[i] - 1];
nums[nums[i] - 1] = nums[i];
nums[i] = tmp;
}
}
for (int i = 0; i < n; i++) {
// 交换完成之后,还不等于,就是说明重复了
if (i != nums[i] - 1) {
ans.add(nums[i]);
}
}
return ans;
}
复杂度分析
- 时间复杂度:O(n)。每一次交换操作会使得至少一个元素被交换到对应的正确位置,因此交换的次数为 O(n),总时间复杂度为 O(n)。
- 空间复杂度:O(1)。返回值不计入空间复杂度。
方法二:正负号
不交换位置,我们可以将对应的数值 * -1 , 取符号,如果重复,负负得正,对应的值为正时,说明重复了
/**
* 方法二:使用正负号作为标记
*
* @param nums
* @return
*/
public static List<Integer> findDuplicates(int[] nums) {
List<Integer> ans = new ArrayList<>();
int n = nums.length;
for (int i = 0; i < n; i++) {
int num = Math.abs(nums[i]);
if (nums[num - 1] > 0) {
nums[num - 1] *= -1;
} else {
ans.add(num);
}
}
return ans;
}
复杂度分析
- 时间复杂度:O(n)。我们只需要对数组 nums 进行一次遍历。
- 空间复杂度:O(1)。返回值不计入空间复杂度。
相似题目推荐:
https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-duplicates-in-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
网友评论