这里主要是记录一些我做这个题遇到的问题及解决办法
1.问题描述
1.1 思路分析:
首先想到是要用二分法,所以做这个题要了解一下二分法的原理及代码实现。对于这个题而言,二分法最后结束的条件最好是left==right
,这样利于后面的判断因此while循环的条件应当是while(left<right)
,循环结束后有两类,一种是找到了目标值也就是返回下标mid,另外一种就是没有找到,但是目标值的下标一定跟left有关(eft==right)
,因为我们循环结束的条件是while(left<right)
,因此对于left对应的值是否等于目标值我们没有判断,所以left对应的值有三种可能,也就是nums[left]==target,nums[left]>target,nums[left]<target
而前两种情况可以归为一类,例如:1,3,5,6;
- target=1时,循环结束时left=0,那么对nums[left]==target,因此返回下标left即可。
- target=0时,循环结束时left=0,那么对nums[left]>target,因此返回下标left即可。想一下为什么返回值不是
left-1
。题目要求是如果不存在就要返回按顺序插入的下标,存在就返回对应下标。而且数组就像前面有一堵墙,排队只能往后排或者插队,插队所有人后延一位,你不能把墙推倒把,所以target<nums[left],有一个比nums[left]还小的目标值,那么left这个位置上及后面的值都要依次后延一位,而left位置被小的值替代。 - target=2时,循环结束时left=1,那么对nums[left]>target,因此返回下标left+1即可,因为经知道了
nums[left]<target,所以目标值一定是排在left+1位,不能替代原来的位置
对于一个旋转数组,取中间,一定可以分为一段是有序的另外一段是可能无序的(这一段不是重点),有序的不是在左边就是在右边,我们只用分析目标值在不在这段有序的数组中,如果不在则再次对另外一段的进行取中间的,再次分为有序和无序,再次判断,直至达到要求:
1.2 整体流程图
2.程序代码及注释:
代码效率中等,还有改进空间
int searchInsert(int* nums, int numsSize, int target) {
int left, right, mid;
left = 0;
right = numsSize - 1;
while (left < right) {
mid = (left + right) / 2;
if (nums[mid] == target) {
goto A;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
A:
if (nums[mid] == target) {
return mid;
} else if (nums[left] >= target) {
return left;
} else {
return left + 1;
}
}