题目
解题
解题一:二分搜索
转换成寻找满足 cnt > num 的最小 num 值,num 的取值范围是 [1, n],所以初始化时 left = 1, right = n - 1
。
// javascript
var findDuplicate = function(nums) {
const n = nums.length;
let left = 1, right = n - 1;
while (left <= right) {
const mid = left + ((right - left) >> 1);
let cnt = 0;
for (let i = 0; i < n; i++) {
cnt += nums[i] <= mid; // if (nums[i] <= mid) cnt++;
}
if (cnt <= mid) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
};
解题二:快慢指针
存在环的原因参考:287.寻找重复数
用快慢指针找出环入口的推导参考:LeetCode142 环形链表 II &《程序员面试金典》面试题 02.08. 环路检测
142 题是先判断有没有环路,再去找环路的入口。而这道题我们通过分析得出一定有环的结论,所以只需要去找环入口。
// javascript
var findDuplicate = function(nums) {
let slow = 0, fast = 0;
// 因为 slow 和 fast 初始值一样是 0,所以用 do while
// 用 while 的话直接一步没走原地结束
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow !== fast);
slow = 0;
while (slow !== fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
};
解题三:二进制
官方还介绍了二进制的方法:方法二:二进制
// javascript
var findDuplicate = function(nums) {
const n = nums.length;
let ans = 0;
// 确定二进制下最高位是多少
let bit_max = 31;
while (!((n - 1) >> bit_max)) {
let m = ((n - 1) >> bit_max);
bit_max -= 1;
}
for (let bit = 0; bit <= bit_max; ++bit) {
let x = 0, y = 0;
for (let i = 0; i < n; ++i) {
if (nums[i] & (1 << bit)) {
x += 1;
}
if (i >= 1 && (i & (1 << bit))) {
y += 1;
}
}
if (x > y) {
ans |= 1 << bit;
}
}
return ans;
};