Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).You are given a target value to search. If found in the array return its index, otherwise return -1.You may assume no duplicate exists in the array.Your algorithm's runtime complexity must be in the order of O(log n).Example 1:Input: nums = [4,5,6,7,0,1,2], target = 0Output: 4Example 2:Input: nums = [4,5,6,7,0,1,2], target = 3Output: -1
断点函数单调性,无非单增,或者只有两段,且各自区间范围内单增
C
4 ms
int search(int* nums, int numsSize, int target) { if(numsSize == 0) return -1; int left = 0, right = numsSize -1; int pivot = 0; // turning point int mid = 0; // search for turning point. while (left < right) { mid = left + (right - left) / 2; if(nums[mid] > nums[right]) { left = mid + 1; }else{ right = mid; } } pivot = left; // search for target. left = 0, right = numsSize-1; while (left <= right) { //printf("mid:%d, left:%d, right:%d\n", mid, left, right); mid = left + (right - left) / 2; int realmid = (mid + pivot)%numsSize; if(nums[realmid] == target) { return realmid; }else if (nums[realmid] < target) { left = mid + 1; }else { right = mid - 1; } } return -1;}
C++ 0ms
static int x=[](){ // toggle off cout & cin, instead, use printf & scanf std::ios::sync_with_stdio(false); // untie cin & cout cin.tie(NULL); return 0;}();class Solution {public: int search(vector & nums, int target) { if(nums.empty()) return -1; function_find = [&nums]() -> int { if(nums.empty()) return 0; int low = 0, high = nums.size() -1; while(low <= high) { int mid = (high-low)/2 + low; if(nums[mid] > nums[high]) low = mid+1; else if(nums[mid] < nums[high]) high = mid; else return mid; }// return low; }; function binary_search = [&nums](int target, int index) -> int { if(nums.empty()) return -1; int low =index, high = nums.size() -1 + index; while (low <= high) { int mid = (high-low)/2 + low; int value = nums[mid%nums.size()]; if(target < value) high = mid -1; else if(target > value) low = mid + 1; else return mid%nums.size(); } return -1; }; int mid = _find(); return binary_search(target, mid); }};
c++ 4ms
/*ExplanationLet's say nums looks like this: [12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]Because it's not fully sorted, we can't do normal binary search. But here comes the trick:If target is let's say 14, then we adjust nums to this, where "inf" means infinity:[12, 13, 14, 15, 16, 17, 18, 19, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf]If target is let's say 7, then we adjust nums to this:[-inf, -inf, -inf, -inf, -inf, -inf, -inf, -inf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]And then we can simply do ordinary binary search.Of course we don't actually adjust the whole array but instead adjust only on the fly only the elements we look at. And the adjustment is done by comparing both the target and the actual element against nums[0]. by StefanPochmannhttps://leetcode.com/problems/search-in-rotated-sorted-array/discuss/14443/C++-4-lines-4ms by rantos22*/class Solution {public:int search(vector &nums, int target) { auto skip_left = [&]( int x) { return x >= nums[0] ? numeric_limits ::min() : x; }; auto skip_right = [&] (int x) { return x < nums[0] ? numeric_limits ::max() : x; }; auto adjust = [&] (int x) { return target < nums[0] ? skip_left(x) : skip_right(x); }; auto it = lower_bound( nums.begin(), nums.end(), target, [&] (int x, int y) { return adjust(x) < adjust(y); } ); return it != nums.end() && *it == target ? it-nums.begin() : -1;}};
c 4ms
/*The idea is that when rotating the array, there must be one half of the array that is still in sorted order.For example, 6 7 1 2 3 4 5, the order is disrupted from the point between 7 and 1. So when doing binary search, we can make a judgement that which part is ordered and whether the target is in that range, if yes, continue the search in that half, if not continue in the other half. -- by flyinghx61https://leetcode.com/problems/search-in-rotated-sorted-array/discuss/14472/Java-AC-Solution-using-once-binary-search */int search(int* nums, int numsSize, int target) { int start = 0; int end = numsSize - 1; while (start <= end){ int mid = (start + end) / 2; if (nums[mid] == target) return mid; if (nums[start] <= nums[mid]){ if (target < nums[mid] && target >= nums[start]) end = mid - 1; else start = mid + 1; } if (nums[mid] <= nums[end]){ if (target > nums[mid] && target <= nums[end]) start = mid + 1; else end = mid - 1; } } return -1;}
c 4ms 下面的程序只是结果满足测试用例,实际情况凑巧而已。
/*The idea is that when rotating the array, there must be one half of the array that is still in sorted order.For example, 6 7 1 2 3 4 5, the order is disrupted from the point between 7 and 1. So when doing binary search, we can make a judgement that which part is ordered and whether the target is in that range, if yes, continue the search in that half, if not continue in the other half. -- by flyinghx61https://leetcode.com/problems/search-in-rotated-sorted-array/discuss/14472/Java-AC-Solution-using-once-binary-search */int search(int* nums, int numsSize, int target) { int lo = 0, hi = numsSize - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; if (target == nums[mid]) return mid; if (nums[mid] < nums[lo]) { // 6,7,0,1,2,3,4,5 if (target < nums[mid] || target >= nums[lo]) hi = mid - 1; else lo = mid + 1; } else { // 2,3,4,5,6,7,0,1 if (target > nums[mid] || target < nums[lo]) lo = mid + 1; else hi = mid - 1; } } return -1;}
81. Search in Rotated Sorted Array IISuppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]).You are given a target value to search. If found in the array return true, otherwise return false.Example 1:Input: nums = [2,5,6,0,0,1,2], target = 0Output: trueExample 2:Input: nums = [2,5,6,0,0,1,2], target = 3Output: falseFollow up:This is a follow up problem to Search in Rotated Sorted Array, where nums may contain duplicates.Would this affect the run-time complexity? How and why?
bool search(int* nums, int numsSize, int target) { int l = 0, r = numsSize - 1; while (l <= r) { int m = l + (r - l)/2; if (nums[m] == target) return true; //return m in Senumsrch in Rotnumsted numsrrnumsy I if (nums[l] < nums[m]) { //left hnumslf is sorted if (nums[l] <= target && target < nums[m]) r = m - 1; else l = m + 1; } else if (nums[l] > nums[m]) { //right hnumslf is sorted if (nums[m] < target && target <= nums[r]) l = m + 1; else r = m - 1; } else l++; } return false;}
/* 1) everytime check if targe == nums[mid], if so, we find it.2) otherwise, we check if the first half is in order (i.e. nums[left]<=nums[mid]) and if so, go to step 3), otherwise, the second half is in order, go to step 4)3) check if target in the range of [left, mid-1] (i.e. nums[left]<=target < nums[mid]), if so, do search in the first half, i.e. right = mid-1; otherwise, search in the second half left = mid+1;4) check if target in the range of [mid+1, right] (i.e. nums[mid]<= nums[right]), if so, do search in the second half, i.e. left = mid+1; otherwise search in the first half right = mid-1;The only difference is that due to the existence of duplicates, we can have nums[left] == nums[mid] and in that case, the first half could be out of order (i.e. NOT in the ascending order, e.g. [3 1 2 3 3 3 3]) and we have to deal this case separately. In that case, it is guaranteed that nums[right] also equals to nums[mid], so what we can do is to check if nums[mid]== nums[left] == nums[right] before the original logic, and if so, we can move left and right both towards the middle by 1. and repeat.dong.wang.1694*/class Solution {public: bool search(vector & nums, int target) { int left = 0, right = nums.size()-1, mid; while(left<=right) { mid = (left + right) >> 1; if(nums[mid] == target) return true; // the only difference from the first one, trickly case, just updat left and right if( (nums[left] == nums[mid]) && (nums[right] == nums[mid]) ) {++left; --right;} else if(nums[left] <= nums[mid]) { if( (nums[left]<=target) && (nums[mid] > target) ) right = mid-1; else left = mid + 1; } else { if((nums[mid] < target) && (nums[right] >= target) ) left = mid+1; else right = mid-1; } } return false; }};
81. Search in Rotated Sorted Array IISuppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]).You are given a target value to search. If found in the array return true, otherwise return false.Example 1:Input: nums = [2,5,6,0,0,1,2], target = 0Output: trueExample 2:Input: nums = [2,5,6,0,0,1,2], target = 3Output: falseFollow up:This is a follow up problem to Search in Rotated Sorted Array, where nums may contain duplicates.Would this affect the run-time complexity? How and why?
6ms
bool search(int* nums, int numsSize, int target) { int l = 0, r = numsSize - 1; while (l <= r) { int m = l + (r - l)/2; if (nums[m] == target) return true; //return m in Senumsrch in Rotnumsted numsrrnumsy I if (nums[l] < nums[m]) { //left hnumslf is sorted if (nums[l] <= target && target < nums[m]) r = m - 1; else l = m + 1; } else if (nums[l] > nums[m]) { //right hnumslf is sorted if (nums[m] < target && target <= nums[r]) l = m + 1; else r = m - 1; } else l++; } return false;}
4ms
/* 1) everytime check if targe == nums[mid], if so, we find it.2) otherwise, we check if the first half is in order (i.e. nums[left]<=nums[mid]) and if so, go to step 3), otherwise, the second half is in order, go to step 4)3) check if target in the range of [left, mid-1] (i.e. nums[left]<=target < nums[mid]), if so, do search in the first half, i.e. right = mid-1; otherwise, search in the second half left = mid+1;4) check if target in the range of [mid+1, right] (i.e. nums[mid]<= nums[right]), if so, do search in the second half, i.e. left = mid+1; otherwise search in the first half right = mid-1;The only difference is that due to the existence of duplicates, we can have nums[left] == nums[mid] and in that case, the first half could be out of order (i.e. NOT in the ascending order, e.g. [3 1 2 3 3 3 3]) and we have to deal this case separately. In that case, it is guaranteed that nums[right] also equals to nums[mid], so what we can do is to check if nums[mid]== nums[left] == nums[right] before the original logic, and if so, we can move left and right both towards the middle by 1. and repeat.dong.wang.1694*/class Solution {public: bool search(vector & nums, int target) { int left = 0, right = nums.size()-1, mid; while(left<=right) { mid = (left + right) >> 1; if(nums[mid] == target) return true; // the only difference from the first one, trickly case, just updat left and right if( (nums[left] == nums[mid]) && (nums[right] == nums[mid]) ) {++left; --right;} else if(nums[left] <= nums[mid]) { if( (nums[left]<=target) && (nums[mid] > target) ) right = mid-1; else left = mid + 1; } else { if((nums[mid] < target) && (nums[right] >= target) ) left = mid+1; else right = mid-1; } } return false; }};