Const
将n+1个整数,一一对应[1,n]的抽屉里,那么至少有一个抽屉里放了两个数。对抽屉编号进行二分,每次二分猜编号m。 那么如果n+1个数中,每个<=m的数一一对应到[1,m]的抽屉里,没有重复放,那么抽屉的数量应该是m。 比如[1,2,3,4,5]个抽屉,有6个数,如果是[1,2,3,4,5,5],那么m取3的时候,抽屉的编号是3,表明前三个抽屉它可以放1,2,3这三个数。此时我们开始从[1,2,3,4,5,5]中逐个看,哪些数能往里头放。 第一个数是1,可以放,第二个数是2,可以放,第三个数是3,可以放。第四个数是4放不进去,第五个数是5,放不进去。第六个数是5,放不进去。刚好放进去的数的个数跟抽屉编号代表的前三个数相等,并没有多放。 假设此时m=5,抽屉的编号是5,表明前五个抽屉它可以放1,2,3,4,5这五个数。此时我们开始从[1,2,3,4,5,5]中逐个看,哪些数能往里头放。 第一个数是1,可以放,第二个数是2,可以放,第三个数是3,可以放。第四个数是4,可以放,第五个数是5,可以放。第六个数是5,可以放。照正常来说,每个抽屉只放1个的话,<=5的数就是5,但是此时<=5的数有6个,说明在m=5的时候前5个数放了6个,有一个抽屉重复放了。 那么重复数一定在[1,5]之间。我们缩小范围,只需要在抽屉[1,5]中找重复数就好了。即此时的[1,n]缩小成了[1,5]。 然后我们继续看,如果m=3,抽屉的编号是3,表明前三个抽屉它可以放1,2,3这三个数。此时我们开始从[1,2,3,4,5,5]中逐个看,哪些数能往里头放。 第一个数是1,可以放,第二个数是2,可以放,第三个数是3,可以放。第四个数是4放不进去,第五个数是5,放不进去。第六个数是5,放不进去。刚好放进去的数的个数跟抽屉编号代表的前三个数相等,并没有多放。 说明编号为3终止的前三个抽屉一定没多放,此时我们缩小查看抽屉的范围,缩小到[4,5]。 我们继续二分,如果m=4,抽屉的编号是4,表明前四个抽屉它可以放1,2,3,4这四个数。此时我们开始从[1,2,3,4,5,5]中逐个看,哪些数能往里头放。 第一个数是1,可以放,第二个数是2,可以放,第三个数是3,可以放。第四个数是4,可以放。第五个数是5,放不进去。第六个数是5,放不进去。刚好放进去的数的个数跟抽屉编号代表的前四个数相等,并没有多放。 说明编号为4终止的前四个抽屉一定没多放,此时我们缩小查看抽屉的范围,缩小到[5]。 我们继续二分,如果m=5,抽屉的编号是5,表明前五个抽屉它可以放1,2,3,4,5这五个数。此时我们开始从[1,2,3,4,5,5]中逐个看,哪些数能往里头放。 第一个数是1,可以放,第二个数是2,可以放,第三个数是3,可以放。第四个数是4,可以放,第五个数是5,可以放。第六个数是5,可以放。此时我们发现5个抽屉放了6个数。 说明5就是我们要找的那个放了重复数的抽屉。
function findDuplicate(nums: number[]): number {
// 抽屉原理:n个抽屉,n+1个物品,至少有一个抽屉放了2个物品
// 在这个问题中:
// - 抽屉:1到n的每个数字
// - 物品:数组中的n+1个数字
const n = nums.length - 1;
let l = 1;
let r = n;
while (l < r) {
// 有1-n个抽屉,m代表前m个抽屉。
const m = l + Math.floor((r - l) / 2);
let cnt = 0;
// 我们尝试看下,前m个抽屉里,要放对应编号的数,能放多少个。正常来说一一对应,那么应该放m个数。cnt === m
// 如果cnt > m,说明重复的数在[1,m]抽屉里
for (const x of nums) {
// 统计nums中小于等于m的数字的个数
// 如果没重复,最终cnt应该等于m
// 否则就是cnt > m,说明重复的数在[1,m]之间
if (x <= m) {
cnt++;
}
}
if (cnt > m) {
// 说明重复的数在[1,m]之间
r = m;
}
else {
// 说明重复的数在[m+1,n]之间
l = m + 1;
}
}
return r;
}
287.寻找重复数
给定一个包含 n + 1 个整数的数组
nums
,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
示例 1:
输入:
nums = [1,3,4,2,2]
输出:
2
示例 2:
输入:
nums = [3,1,3,4,2]
输出:
3
示例 3:
输入:
nums = [1,1]
输出:
1
示例 4:
输入:
nums = [1,1,2]
输出:
1
提示:
1 <= n <= 10^5
nums.length == n + 1
1 <= nums[i] <= n
nums
中 只有一个整数 出现两次或多次,其余整数均只出现 一次