LeetCode 287. 寻找重复数
//二分法查找 class Solution { public int findDuplicate(int[] nums) { //定义数组左边界的指针 left,右边界指针 right int left = 1; int right = nums.length - 1; while(left < right){ //确定mid, 这里的写法参考了题解中liweiwei1419的写法,我这菜鸡一般都写 mid = left + (right - left) / 2; int mid = (left + right) >>> 1; //定义一个计数器 count,统计数组中的元素小于等于 中间元素mid的数量 int count = 0; for(int num : nums){ if(num <= mid){ count++; } } //遍历完一次 判断下一次遍历的区间 //liweiwei1419大神讲解了抽题原理,讲 若mid = 4, 小于等于4的元素如果严格大于4个,此时重复元素一定在【1,4】区间里 if(count > mid){ //更改 right边界 [left,mid] right = mid; }else{ //更改 left 边界 [mid+1,right] left = mid + 1; } } return left; } }
这道题(据说)花费了计算机科学界的传奇人物Don Knuth
24小时才解出来。并且我只见过一个人(注:Keith Amling
)用更短时间解出此题。作为普通人的我们在刷题的道路上不要气馁,努力前行,相信努力和汗水不会白费。
双指针解法(官方题解),推荐官方题解的动画演示,双指针法有其数学道理,有能力的同学请自行深研。
详细讲解请移步官方题解,谢谢。
//快慢指针法 class Solution { public int findDuplicate(int[] nums) { //定义快慢指针 slow ,fast int slow = nums[0]; int fast = nums[nums[0]]; while(slow != fast){ slow = nums[slow]; fast = nums[nums[fast]]; } //这里置 fast 或者 slow 都可以 slow = 0; while(slow != fast){ slow = nums[slow]; fast = nums[fast]; } return slow; } }