图床:blogimg/刷题记录/Q/
刷题代码汇总:https://www.cnblogs.com/geaming/p/16428234.html
存在一个序列1、2、……、n-1、n、n、n+1、……
在这个序列中,只有一个数字有重复,找出重复的数字n
n
n
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
value | 1 | 2 | 3 | 3 | 4 | 5 |
可以看到如果序列是有序的,重复出现的数字为3
,如果未出现重复数字则value=pos+1
但在出现重复数字之后的序列中value=pos
故可以采用二分法进行查找。先判断arr[mid]==arr[mid+]
,如果相等则返回arr[mid]
,若arr[mid]==mid+1
说明重复数字出现在区间[mid+1,right]
,若arr[mid]==mid
说明重复数字出现在区间[left,mid-1]
,时间复杂度为\(\mathrm{O}(\mathrm{log}n)\)
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
value | 5 | 1 | 3 | 4 | 2 | 3 |
这个题如果对于空间复杂度不做要求的话,可以直接使用哈希表进行计算,时间复杂度为\(\mathrm{O}(n)\),而如果我们要求空间复杂度为\(\mathrm{O}(1)\),则不能使用哈希表的做法。
如果将value
视为下一个节点的位置,可以把整个数据看成为一个链表,则问题转换为单链表有环问题。因为有一个value
出现两次,此时形成了环。
#include <iostream> #include <vector> using namespace std; int main() { int a; vector<int> Vec; while (cin >> a) { Vec.push_back(a); if (cin.get() == '\n') break; } //二分查找 int l = 0; int r = Vec.size() - 1; while (l <= r) { int mid = (l + r) / 2; if (Vec[mid] == Vec[mid + 1]) { cout << Vec[mid] << endl; return 0; } else if (Vec[mid] == mid) { r = mid - 1; } else { l = mid + 1; } } }
样例:
输入:1 2 2 3 4
输出:2
输入:1 2 3 3 4
输出:3
#include <iostream> #include <vector> using namespace std; int main() { int a; vector<int> Vec; while (cin >> a) { Vec.push_back(a); if (cin.get() == '\n') break; } //快慢指针 int slow = Vec[0]; int fast = Vec[Vec[0]]; while (slow != fast) { fast = Vec[Vec[fast]]; slow = Vec[slow]; } fast = 0; while (slow != fast) { fast = Vec[fast]; slow = Vec[slow]; } cout << fast << endl; //注意最后返回的是下标值而不是value值 }
单链表有环问题讲解:https://www.bilibili.com/video/BV1kL4y1K7YC