442. Find All Duplicates in an Array 题解

时间:2022-04-08 04:40:57

题意:给定一组整数,共n个,这组数字的值均不超过n。在这组数字中,有些数字出现了两次而其他数字只出现了一次,要求找出该组数字中所有出现两次的数。并且不能开辟额外的空间,且时间复杂度应为O(n)。

思路:题目不允许开辟额外空间,第一反应是能不能使用位运算/异或来解决该问题,仔细思考后发现似乎行不通。实际上该题目使用的是“借助数组下标记录一些信息”的思想,题目中“这组数字的值均不超过n”也印证了该想法。总之,该题目的解法是“对于数字n+1,使用下标n处数值的正负进行标记。即使用下标n处数字的正负,来标识数字n+1是否出现过”。

举例来说,可以使用数组下标2 处所保存的数值正负来标识数字3是否已经出现过。当数字3第一次出现时,将下标2处所保存的数值设置为负。这样在后续过程中,若数字下标2处的数字为正数,表示3这个数字尚未出现过;若数字下标2处的数字为负数,表示3这个数字已经出现过一次。

本题java代码如下:

class Solution {
	public List<Integer> findDuplicates(int[] nums) {
		List<Integer> result = new ArrayList<Integer>();
		for (int i = 0; i < nums.length; i++) {
			int currentNum = Math.abs(nums[i]);
			// 在当前数字对应的下标(当前数字-1)处,使用正负进行标记
			// 例如,使用数组下标2 处所保存的数值正负来标识数字3是否已经出现过;
			// 若数字下标2处的数字为正数,表示3这个数字尚未出现过;
			// 若数字下标2处的数字为负数,表示3这个数字已经出现过一次。
			int targetNum = nums[currentNum - 1];
			if (targetNum < 0) {
				result.add(currentNum);
			} else {
				nums[currentNum - 1] = -targetNum;
			}
		}
		return result;
	}
}