mirror of
https://github.com/ShusenTang/LeetCode.git
synced 2024-09-02 14:20:01 +00:00
add solution2&3
This commit is contained in:
parent
bfd9ffd11c
commit
11ab2ab48d
@ -4,7 +4,7 @@
|
|||||||
给定一个长度为n+1的数组,里面所有的元素都位于[1, n],所以很明显有重复元素,题目假设只有一个重复数字(但可以重复多次),求这个重复数字。要求空间复杂度为常数
|
给定一个长度为n+1的数组,里面所有的元素都位于[1, n],所以很明显有重复元素,题目假设只有一个重复数字(但可以重复多次),求这个重复数字。要求空间复杂度为常数
|
||||||
且时间复杂度小于O(n^2)。
|
且时间复杂度小于O(n^2)。
|
||||||
|
|
||||||
## 思路一
|
## 思路一、位操作
|
||||||
|
|
||||||
由于要求常数空间复杂度,所以就不能用hash什么的;然后要求时间复杂度小于O(n^2),暴力计数也不行。既然直接计数不行,那么我们可以考虑位操作:
|
由于要求常数空间复杂度,所以就不能用hash什么的;然后要求时间复杂度小于O(n^2),暴力计数也不行。既然直接计数不行,那么我们可以考虑位操作:
|
||||||
计算32位中每一位当中1出现的次数。具体来讲,对于第i位(0 <= i <= 31),我们用count1代表整个nums数组中所有元素第i位是1的个数,
|
计算32位中每一位当中1出现的次数。具体来讲,对于第i位(0 <= i <= 31),我们用count1代表整个nums数组中所有元素第i位是1的个数,
|
||||||
@ -12,6 +12,29 @@
|
|||||||
|
|
||||||
时间复杂度为O(n)
|
时间复杂度为O(n)
|
||||||
|
|
||||||
|
## 思路二、二分法
|
||||||
|
题目说的时间复杂度要小于O(n^2),那么我们可以想到比这个复杂度小一个量级的常见复杂度O(nlogn),由此可想到二分法。
|
||||||
|
由于重复值肯定是在[1, n]之间,所以我们可以首先得到这个范围的中点mid,然后遍历整个数组,统计所有小于等于mid的数的个数count:
|
||||||
|
* 如果`count <= mid`,则说明重复值一定是大于mid(可以自己举例子理解),应进入右半部分继续二分;
|
||||||
|
* 否则,重复值不大于mid。
|
||||||
|
|
||||||
|
此时时间复杂度就是O(nlogn)
|
||||||
|
|
||||||
|
## 思路三
|
||||||
|
此题还有一个十分巧妙的方法[可参考[此处](https://leetcode.com/problems/find-the-duplicate-number/discuss/72846/My-easy-understood-solution-with-O(n)-time-and-O(1)-space-without-modifying-the-array.-With-clear-explanation.)]。此时要把nums数组看成一个链表:`nums[i] = j`表示链表中结点i的next结点为j,例如数组
|
||||||
|
```
|
||||||
|
index : 0 1 2 3 4
|
||||||
|
nums[i]: 3 1 3 4 2
|
||||||
|
```
|
||||||
|
表示的链表为
|
||||||
|
```
|
||||||
|
0 -> 3 -> 4 -> 2
|
||||||
|
^ |
|
||||||
|
|_________|
|
||||||
|
```
|
||||||
|
可以看到这个链表是有环的,为什么有环呢,就是因为数组nums中存在重复元素3。仔细分析我们可以发现,链表中环的开始结点即为重复元素,
|
||||||
|
即题目转变为求一个带环链表中环的开始结点,这其实就是[142. Linked List Cycle II](https://leetcode.com/problems/linked-list-cycle-ii/),可参见这题我的[题解](https://github.com/ShusenTang/LeetCode/blob/master/solutions/142.%20Linked%20List%20Cycle%20II.md),这里直接给出代码。
|
||||||
|
|
||||||
# C++
|
# C++
|
||||||
## 思路一
|
## 思路一
|
||||||
``` C++
|
``` C++
|
||||||
@ -33,3 +56,49 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 思路二
|
||||||
|
``` C++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int findDuplicate(vector<int>& nums) {
|
||||||
|
int n = nums.size() - 1;
|
||||||
|
|
||||||
|
int low = 1, high = n;
|
||||||
|
while(low < high){
|
||||||
|
int mid = low + (high - low) / 2;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for(auto &num: nums)
|
||||||
|
if(num <= mid) count++;
|
||||||
|
|
||||||
|
if(count <= mid) low = mid + 1;
|
||||||
|
else high = mid;
|
||||||
|
}
|
||||||
|
return low;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 思路三
|
||||||
|
``` C++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int findDuplicate(vector<int>& nums) {
|
||||||
|
int slow = 0, fast = 0;
|
||||||
|
while(true){
|
||||||
|
slow = nums[slow];
|
||||||
|
fast = nums[nums[fast]];
|
||||||
|
if(slow == fast) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int p = 0;
|
||||||
|
while(true){
|
||||||
|
if(p == slow) break;
|
||||||
|
slow = nums[slow];
|
||||||
|
p = nums[p];
|
||||||
|
}
|
||||||
|
return slow;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user