我们让最终的nums序列其索引号与数值相等,即0号索引位置上的数值是0,1号索引位置上的数值是1,......,当前nums[i]没有放到正确的坑上,并且那个正确的坑上的数与那个坑是不匹配的,那么就要不停地交换,交换到不能交换的时候,就要判断一下,是不是遇到重复的了,如果nums[i]没有放到正确的位置上,并且它要放的那个位置已经有一个数在那待着了,说明nums[i]这个数至少出现了两次了,此时,我们就可以直接返回nums[i],否则最后返回-1。
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n; ++ i)
if (nums[i] < 0 || nums[i] > n - 1) return -1;
for (int i = 0; i < n; ++ i) {
while (nums[i] != i && nums[i] != nums[nums[i]]) swap(nums[i], nums[nums[i]]);
if (nums[i] != i && nums[i] == nums[nums[i]]) return nums[i];
}
return -1;
}
};
我们要注意一点,判断nums[i]是否在0~n - 1之间不要放在循环内部,原因如下:
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n; ++ i) {
if (nums[i] < 0 || nums[i] > n - 1) return -1;
while (nums[i] != i && nums[i] != nums[nums[i]]) swap(nums[i], nums[nums[i]]);
if (nums[i] != i && nums[i] == nums[nums[i]]) return nums[i];
}
return -1;
}
};
nums[0] = 3,它应该放在3号索引位置,此时,nums[3] != 3,nums[3]与nums[0]进行交换,nums[0] = 1,然后继续向后执行,发现判断条件nums[0] != 0, nums[1] = 1,此时程序return 1。
由此看出,在遍历到-10之前,就发现了重复元素,并返回结果结束程序,所以,我们应提前遍历一遍,发现其中有不合法的数,直接return -1。
本题也可以用unordered_map
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
unordered_map<int, bool> res;
int n = nums.size();
for (int i = 0; i < n; ++ i)
if (nums[i] < 0 || nums[i] > n - 1) return -1;
for (int i = 0; i < n; ++ i) {
if (res[nums[i]]) return nums[i];
res[nums[i]] = true;
}
return -1;
}
};