数组中重复的数字(五十)
题目描述:
在一个长度为 n
的数组里的所有数字都在 0
到 n - 1
的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为 7
的数组{2,3,1,0,2,5,3}
,那么对应的输出是第一个重复的数字 2
。
代码(已在牛客上 AC)
使用排序或者哈希表的思路就不多谈了, 这里参考 http://cuijiahua.com/blog/2018/01/basis_50.html 了解到第三种思路. 一般像数组中元素值的大小在 0 ~ n - 1
之间(或者 1 ~ n
之间) 啥的, 都可以考虑将元素值作为索引…
这道题是基于这样的考虑: 如果数组中没有重复元素, 那么在排序的情况下, i
与 A[i]
是要一一对应的, 比如:
A[i] : 0 3 2 1
i : 0 1 2 3
从 i
的角度来看, 由于 A[1] != 1
却等于 3
, 而从 A[i]
的角度看, 有 A[A[1]] = A[3] == 1
却不等于 3
, 因此, 只要 i
的位置上的数据 A[i]
与数值 i
不相等, 那么相应的有 A[i]
位置上的数据 A[A[i]]
不等于 A[i]
(为了不烧脑, 绕口, 这句话可以从 A[i]
的角度看, 即把上面的 A[i]
那一行当索引, i
那一行当数组中的数值). 这种情况下, 可以考虑将位于索引 i
上的元素 A[i]
与 A[A[i]]
交换, 看看交换后索引和值是否匹配, 如果仍然不相等, 那么继续交换这个过程.
上面的思想反映到下面的代码, 主要是:
while (i != numbers[i]) {
if (numbers[i] == numbers[numbers[i]]) {
*duplication = numbers[i];
return true;
}
swap(numbers[i], numbers[numbers[i]]);
}
即对于当前的索引 i
, 判断 i
与其上的值 numbers[i]
是否相等, 如果不相等, 就不断将 numbers[i]
和 numbers[numbers[i]]
中的数据交换. 但由于数组中存在重复值, 所以交换过程中, 如果遇到 numbers[i]
与 numbers[numbers[i]]
相等, 那么直接返回 true
.
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
// 这道题还是有难度的, 不在于编码, 而在于思路, 详情参考:
// http://cuijiahua.com/blog/2018/01/basis_50.html
// 下面的方式是 O(N) 的, 假设数组中没有元素是重复的, 那么就希望索引和对应的元素相等,
// 即 i == A[i]. 基于这一考虑, 遍历数组 A, 如果存在 i != A[i], 那么就判断 A[A[i]]
// 与 A[i] 的关系, 如果仍然不相等, 那么就交换 A[A[i]] 与 A[i] 这个过程要持续下去,
// 直到 i == A[i]. 如果在交换过程中发现某次 A[i] 与 A[A[i]] 相等了, 说明就找到了重复的
// 元素, 返回 duplication 即可.
bool duplicate(int numbers[], int length, int* duplication) {
// 防止非法输入
if (numbers == NULL || length <= 0) return false;
for (int i = 0; i < length; ++i)
if (numbers[i] < 0 || numbers[i] > length - 1) return false;
for (int i = 0; i < length; ++i) {
while (i != numbers[i]) {
if (numbers[i] == numbers[numbers[i]]) {
*duplication = numbers[i];
return true;
}
swap(numbers[i], numbers[numbers[i]]);
}
}
return false;
}
};