leetcode442.数组中重复的数据

题目大意

给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次。

找到所有出现两次的元素。

你可以不用到任何额外空间并在O(n)时间复杂度内解决这个问题吗?

示例

输入:
[4,3,2,7,8,2,3,1]

输出:
[2,3]

解题思路

方法一:

遍历到位置i时,将位置i的元素nums[i]和位置nums[i]-1的元素进行交换,这样就能使得nums[i]的元素处于正确的位置。但是交换过来的元素不一定在正确位置,因此继续交换,直到nums[i]=i+1或者不符合条件。

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
    	if (nums.size() < 2)
    		return {};

    	vector<int> res;

    	for (int i = 0; i < nums.size(); ++i){
    		//如果该位置正确放置,则遍历下一个元素
    		if (nums[i] == i + 1)
    			continue;
			
			// 如果该位置元素不是0,且后面的条件不满足
			// 第二个条件是:当前元素nums[i]=4,应该被放到位置3,但是位置3上已经有个一个4,所以表示4重复了,可以退出while循环了
			// 那么就可以把当前的nums[i]放到正确位置上
    		while (nums[i] != 0 && nums[nums[i] - 1] != nums[i]){
    			int tmp = nums[i];
    			nums[i] = nums[tmp - 1];
    			nums[tmp - 1] = tmp;
    		}
			// 上述交换完成后,如果当前元素不是0,且没有正确放置,且应该正确放置的位置上已经有了一个相同的元素了,表示该元素是重复元素
    		if (nums[i] != 0 && nums[i] != i + 1 && nums[i] == nums[nums[i] - 1]){
    			res.push_back(nums[i]);
    			// 置为0.表示这个元素出现过一次了,后续不需要再进行判断
    			nums[i] = 0;
    		}
    	}
    	return res;
    }
};
方法二:

遍历每一个元素,对于位置i的nums[i],按理说nums[i]这个元素应该放置在nums[nums[i]-1]这个位置,那么我们就将这个位置的元素变成负数,表示这个位置上的正确元素出现过一次了。
如果位置j的元素nums[j]的正确位置nums[nums[j]-1]已经是负数了,表示nums[j]这个元素出现过一次。

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
    	if (nums.size() < 2)
    		return {};

    	vector<int> res;
    	int index = 0;

    	for (int i = 0; i < nums.size(); ++i){
    		// 表示nums[i]应该被正确放置的位置是index
    		index = abs(nums[i]) - 1;
    		// 如果index位置的元素小于0,表示nums[i]已经出现过一次了
    		if (nums[index] < 0)
    			res.push_back(index);
    		else
    			// 反之表示nums[i]没出现过,因此记录一下
    			nums[index] = -nums[index];
    	}

    	return res;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_41092190/article/details/106519648