Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Note:
O(n2)
.
我的AC【弄个新数组,排序后比较相邻两值(错错错=。= 因为还是相当于modify the array了。我就说嘛,hard难度的题不可能这样就搞定..)】:
<span style="font-size:14px;">int comp(const int *a, const int *b){ if (*a >= *b) return 1; else return -1; } int findDuplicate(int* nums, int numsSize) { int* c = nums; qsort(c, numsSize, sizeof(int), comp); for(int i = 0; i < numsSize ; i++){ if (c[i] == c[i + 1]) return c[i]; } }</span>
1.二分查找 binary search
思路:
设 low为左值, high为右值, mid 为两者的中间值。这里的 low, high, mid 均是指元素的值,不是指下标,之所以可以这么做,是因为题目的条件“ n+1 长的数组里面只有 1...n 的数值”。
1>.将数组扫一遍,得到大于等于 low 且 小于等于 mid 的元素个数,即为 count。
2>.当 count 大于 本应该有的个数,,说明重复值在[low,mid]之间,缩小范围。
3>.当 count 小于等于 本应该有的个数,说明重复值在 [mid, high] 之间,缩小范围。
4>.重复前面步骤,直到找到重复值。
int findDuplicate(int* nums, int numsSize) { int low = 1, high = numsSize - 1, mid; while (low <= high) { mid = low + (high - low) / 2; int count = 0; for (int i = 0; i < numsSize; i++) { if (nums[i] <= mid) count++; } if (count <= mid) low = mid + 1; else high = mid - 1; /* if(count > mid) high = mid; else low = mid + 1; */ } return low; }
2.快慢指针 two pointer
思路:因为有数字可能出现多次,会有 i != j, nums[i] == nums[j]。
This algorithm also called Floyd's cycele detection algorithm。
<span style="font-size:14px;">int findDuplicate(int* nums, int numsSize) {</span>
<span style="font-size:14px;"> int slow = 0; int fast = 0; int finder = 0; while (1) { slow = nums[slow]; fast = nums[nums[fast]]; if (slow == fast) break; } while (1) { slow = nums[slow]; finder = nums[finder]; if (slow == finder) return slow; } } /* 最后一段while也可写成: fast = 0; while(1) { slow=nums[slow]; fast=nums[fast]; if(slow==fast)return slow; }</span> */
此题的快慢指针+详细解释
https://leetcode.com/discuss/61514/understood-solution-space-without-modifying-explanation
https://leetcode.com/discuss/61086/java-time-and-space-solution-similar-find-loop-in-linkedlist(有图+例子)