mirror of
https://github.com/ShusenTang/LeetCode.git
synced 2024-09-02 14:20:01 +00:00
33. Search in Rotated Sorted Array
This commit is contained in:
parent
31fde1b35a
commit
f762848060
@ -29,6 +29,7 @@ LeetCode solutions with Chinese explanation. LeetCode中文题解。
|
||||
| 27 |[Remove Element](https://leetcode.com/problems/remove-element)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/27.%20Remove%20Element.md)|Easy| |
|
||||
| 29 |[Divide Two Integers](https://leetcode.com/problems/divide-two-integers)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/29.%20Divide%20Two%20Integers.md)|Medium| |
|
||||
| 31 |[Next Permutation](https://leetcode.com/problems/next-permutation)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/31.%20Next%20Permutation.md)|Medium| |
|
||||
| 33 |[Search in Rotated Sorted Array](https://leetcode.com/problems/search-in-rotated-sorted-array/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/33.%20Search%20in%20Rotated%20Sorted%20Array.md)|Medium| |
|
||||
| 35 |[Search Insert Position](https://leetcode.com/problems/search-insert-position)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/35.%20Search%20Insert%20Position.md)|Easy| |
|
||||
| 38 |[Count and Say](https://leetcode.com/problems/count-and-say)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/38.%20Count%20and%20Say.md)|Easy| |
|
||||
| 53 |[Maximum Subarray](https://leetcode.com/problems/maximum-subarray)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/53.%20Maximum%20Subarray.md)|Easy| |
|
||||
|
101
solutions/33. Search in Rotated Sorted Array.md
Normal file
101
solutions/33. Search in Rotated Sorted Array.md
Normal file
@ -0,0 +1,101 @@
|
||||
# [33. Search in Rotated Sorted Array](https://leetcode.com/problems/search-in-rotated-sorted-array/)
|
||||
|
||||
# 思路
|
||||
题意就是在一个经过了循环移位的有序数组(无重复元素)里进行查找,要求时间复杂度O(logn)。
|
||||
由于要求的时间复杂度为O(logn),所以肯定是考虑二分查找的。假如这个数组没有进行循环移位,即就是一个有序的,那对其进行查找就是一个简单的二分查找,so easy,时间复杂度O(logn)。怎样把二分查找运用在本题呢?(本文默认你掌握了二分查找,否则建议先去看看二分查找)
|
||||
|
||||
## 思路一
|
||||
前面也说了,本题的数组就是一个有序数组再经过了循环移位,如下例就是向右循环移位了4步(或者左循环移位了3步):
|
||||
```
|
||||
下标:0 1 2 3 4 5 6
|
||||
移位前元素:0 1 2 4 5 6 7
|
||||
移位后元素:4 5 6 7 0 1 2
|
||||
```
|
||||
可以看到移位后的元素的下标相当于是移位前的下标加4(然后对7取模),既然这样,那我们在二分查找判断target和nums[mid]大小之前也对mid加4(然后对7取模)不就行了。(具体实现可参考代码)
|
||||
|
||||
现在问题来了,怎样计算这个偏移量4?我们只需要知道一个元素在循环移位前和循环移位后的下标就行了,为了简单不妨去找最小的那个元素,这样其对应的移位后的下标就是偏移量。
|
||||
|
||||
由于要求时间复杂度O(logn),所以应该用二分查找这个最小值。二分查找的时候我们会知道nums[low]、nums[mid]、nums[high],怎样通过这三个数的大小关系确定最小值在[low, mid]或者[mid, high]哪一个区间呢?
|
||||
|
||||
先看来看看nums[low]和nums[mid]比较:
|
||||
> 假设`nums[low] < nums[mid]`,此时最小值可能就是nums[low]比如012或者在[mid, high]区间比如120。
|
||||
|
||||
所以拿nums[low]和nums[mid]比较不是一个好选择。再来看看nums[mid]和nums[high]比较:
|
||||
> * 若`nums[mid] < nums[high]`,此时最小值只能是位于[low, mid]。
|
||||
> * 否则若`nums[mid] > nums[high]`,此时最小值只能是位于[mid+1, low]。
|
||||
> * 假设`nums[mid] == nums[high]`,此时`low = mid = high`,最小值就是nums[mid]。
|
||||
|
||||
可见用nums[mid]和nums[high]的大小关系可以确定最小值位于哪一个区间。
|
||||
知道了最小值,那也就知道了偏移量,再用二分法,问题迎刃而解。
|
||||
|
||||
时间复杂度O(logn),空间复杂度O(1)
|
||||
|
||||
## 思路二
|
||||
思路一虽然时间复杂度为O(logn),但是却进行了两次查找,一点都不elegant,能不能直接一步到位呢?肯定还是二分法,那么我们应该如何判断target是在左半部分[low, mid)还是右半部分(mid, high]呢?
|
||||
|
||||
我们知道,判断一个数是否在一个有序数组数组是很方便的(只需要判断端点和这个数的大小关系),幸运的是,仔细分析此题的数组可知,左右两半至少有一半是有序的。所以我们可以判断target是否在这有序的一半,若在则丢弃掉另一半进入下一次循环,若不在则丢弃掉有序的这一半进入下一次循环。那么如何判断哪一半是有序的呢?也很简单,只需要判断左右端点即可,以左半部分为例:
|
||||
* 若`nums[low] <= nums[mid]`,则左半部分一定是有序的(想想为什么);
|
||||
* 否则左半部分是无序的,则右半部分一定是有序的。
|
||||
|
||||
时间复杂度O(logn), 空间复杂度O(1)
|
||||
|
||||
|
||||
# C++
|
||||
## 思路一
|
||||
``` C++
|
||||
class Solution {
|
||||
public:
|
||||
int search(vector<int>& nums, int target) {
|
||||
if(nums.empty()) return -1;
|
||||
int len = nums.size();
|
||||
int delta, mid, low = 0, high = len - 1; // delta偏移量
|
||||
|
||||
// 计算偏移量
|
||||
while(low != high){
|
||||
mid = low + (high - low) / 2; // 不写成 (low + high) / 2 是为了避免溢出的风险
|
||||
if(nums[mid] < nums[high]) high = mid;
|
||||
else low = mid + 1; // 注意这里是 mid+1 !!!
|
||||
} // low == high == mid == 偏移量
|
||||
delta = low;
|
||||
|
||||
// 考虑偏移的二分查找
|
||||
low = 0;
|
||||
high = len - 1;
|
||||
int real_mid; // 算上偏移的mid
|
||||
while(low <= high){
|
||||
mid = low + (high - low) / 2;
|
||||
real_mid = (mid + delta) % len;
|
||||
if(nums[real_mid] == target) return real_mid;
|
||||
else if(nums[real_mid] < target) low = mid + 1;
|
||||
else high = mid - 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 思路二
|
||||
``` C++
|
||||
class Solution {
|
||||
public:
|
||||
int search(vector<int>& nums, int target) {
|
||||
if(nums.empty()) return -1;
|
||||
int len = nums.size();
|
||||
int mid, low = 0, high = len - 1;
|
||||
while(low <= high){
|
||||
mid = low + (high - low) / 2;
|
||||
if(nums[mid] == target) return mid;
|
||||
if(nums[low] <= nums[mid]){ // 左半边有序
|
||||
if(nums[low] <= target && target < nums[mid]) high = mid - 1; // target在左半边
|
||||
else low = mid + 1;
|
||||
}
|
||||
else{ // 右半边有序
|
||||
if(nums[mid] < target && target <= nums[high]) low = mid + 1; // target在右半边
|
||||
else high = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
```
|
Loading…
Reference in New Issue
Block a user