题目:
思路:
- 利用剑指offer第11题的代码(稍作修改),找到数组旋转之前的起始元素。
- 通过步骤1,我们就可以将旋转数组分成两个升序序列。通过将target与旋转数组第一个元素比较,判断target是在哪一部分,然后用二分法查找即可。Runtime 4ms,还是比较快的。
另一思路:找到旋转的那个位置,然后错位进行二分查找。
代码实现:
class Solution {
public:
int MinInOrder(const vector<int>& numbers, int index1, int index2) {
for (int i = 1; i < numbers.size(); i++) {
if (numbers[i - 1] > numbers[i]) {
return i;
}
}
return 0;
}
int IndOfMin(const vector<int> &numbers, int length) {
if (length <= 0) {
assert(0);
}
int index1 = 0;
int index2 = length - 1;
int indexMid = index1;
while (numbers[index1] >= numbers[index2]) {
if (index2 - index1 == 1) {
indexMid = index2;
break;
}
indexMid = (index1 + index2) / 2;
if (numbers[index1] == numbers[index2] && numbers[index2] == numbers[indexMid]) { //我的分析:只要第一次三者不全相等,则就没问题
return MinInOrder(numbers, index1, index2);
}
if (numbers[indexMid] >= numbers[index1]) { //等号是必须的,否则可能会不进行任何更新,陷入死循环。
index1 = indexMid; //因为这个if在前,所以在index1,index2,indexMid的元素值相等时,搜寻空间倾向于右面,所以可能出错。
}
else if (numbers[indexMid] <= numbers[index2]) {
index2 = indexMid;
}
}
return indexMid;
}
bool binaryFind(vector<int>& nums, int begin, int end, int target){
int mid;
while (begin <= end){
mid = begin + (end - begin) / 2;
if (nums[mid] == target){
return true;
}else if (nums[mid] > target){
end = mid - 1;
}else{
begin = mid + 1;
}
}
return false;
}
bool search(vector<int>& nums, int target) {
if (nums.size() <= 0){
return false;
}
int ind = IndOfMin(nums, nums.size());
bool ans;
if (target == nums[0]){
return true;
}else if (target > nums[0]){
if (ind - 1 >= 0){
ans = binaryFind(nums, 0, ind-1, target);
}else{
ans = binaryFind(nums, 0, nums.size()-1, target);
}
}else{
ans = binaryFind(nums, ind, nums.size()-1, target);
}
return ans;
}
};
discuss:
class Solution {
public:
bool search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int mid;
while (left <= right){
mid = (left + right) >> 1;
if (nums[mid] == target) return true;
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;
}
};
错位进行二分查找:
class Solution {
public:
bool search(vector<int>& nums, int target) {
if (nums.size() == 0) return false;
int r_len = 0;
for (int i = 1; i < nums.size(); ++i){
if (nums[i-1] > nums[i]){
r_len = i;
break;
}
}
int left = 0;
int right = nums.size()-1;
while (left <= right){
int mid = (left + right) / 2;
if (nums[(mid+r_len)%nums.size()] == target){
return true;
}else if (nums[(mid+r_len)%nums.size()] > target){
right = mid - 1;
}else{
left = mid + 1;
}
}
return false;
}
};