题意:给定一组整数,共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; } }