题目链接:
我的答案:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int i = 0, j = nums.size() - 1;
if (nums[i] == target) return i;
if (nums[j] == target) return j;
if (nums[i] > target) {
nums.insert(nums.begin(), target);
return 0;
}
if (nums[j] < target) {
nums.insert(nums.begin() + nums.size(), target);
return nums.size() - 1;
}
int mid = (i + j) / 2;
while(mid != i) {
if (nums[mid] == target) return (i + j) / 2;
else if(nums[mid] < target) {
i = mid;
mid = (i + j) / 2;
}else {
j = mid;
mid = (i + j) / 2;
}
}
nums.insert(nums.begin() + mid + 1, target);
return mid+1;
}
};
单独考虑边界情况,执行通过,但if条件判断太多,代码不够简洁
此外,在做题的时候,说是要插入不存在的元素,但并不需要真的插入,只需要输出插入位置即可!因为题目只需要输出与答案相符。
官方答案:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) return mid;
else if(nums[mid] < target) { //[mid + 1, right]
left = mid + 1;
}else {
right = mid - 1; //[left, mid - 1]
}
}
return left;
}
};
知识点:
二分法
有序数组的查找,可考虑采用二分法
二分查找学习视频:8-1 「二分查找」的基本思想_哔哩哔哩_bilibili
相似题目:
/**
* Forward declaration of guess API.
* @param num your guess
* @return -1 if num is higher than the picked number
* 1 if num is lower than the picked number
* otherwise return 0
* int guess(int num);
*/
class Solution {
public:
int guessNumber(int n) {
if(guess(n) == 0) return n; //判断边界,最后一个数
unsigned int mid = (1 + n) / 2;
unsigned int i = 1, j = n;
while(true) {
if(guess(mid) == 0) return mid;
else if(guess(mid) == -1) { //猜的数字大了
j = mid;
mid = (i + j) / 2;
}else { //猜的数字小了
i = mid;
mid = (i + j) / 2;
}
}
}
};
注意:int最大值为2^31-1,题目中给出的n的最大值为2^31-1,但执行相加操作可能会超出最大值,发生整型溢出
解决方法:
将int 改为 unsigned int
或者
mid = i + (j - i) / 2;
知识点:
C/c++中 int、long、long long等取值范围:
unsigned int 0~4294967295
int -2147483648~2147483647
unsigned long 0~4294967295
long -2147483648~2147483647
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:18446744073709551615 //20位
class Solution {
public:
int search(vector<int>& nums, int target) {
int i = 0, j = nums.size() - 1;
if (nums[i] == target) return i;
if (nums[j] == target) return j;
int mid = (i + j) / 2;
while(mid != i) {
if (nums[mid] == target) return (i + j) / 2;
else if(nums[mid] < target) {
i = mid;
mid = (i + j) / 2;
}else {
j = mid;
mid = (i + j) / 2;
}
}
return -1;
}
};
使用left > right作为while循环终止判断的写法:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1; //初始判断区间[left, right]
while(left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) return mid;
else if(nums[mid] < target) { //缩小区间为[mid+1, right]
left = mid + 1;
}else { //缩小区间为[left, mid - 1]
right = mid -1;
}
}
return -1;
}
};
在数组中使用二分查找的前提:
① 数组具有随机访问特性
② 数组内元素有序(但不是有序的数组有时也可以使用二分查找)
35题精选回答提供的——
二分查找题解列表:
题型一:二分求下标(在数组中查找符合条件的元素的下标)
704、34、35、300、611、658、436、1237、1300、4
二分查找不一定是有序数组,如
旋转有序数组:33、81、153、154
山脉数组:852、1095
题型二:二分答案(在一个有范围的区间里搜索一个整数)
69、287、374、275、1283、1292
题型三:二分答案的升级版(每一次缩小区间的时候都需要遍历数组)
875、410、LCP 12、1011、1482、1552、209