704. 二分查找
-
题目概括:将一个 升序 的 整型数组 n u m s nums nums 和一个 目标值 t a r g e t target target 进行匹配:
- 如果
t
a
r
g
e
t
∈
a
r
r
a
y
target\in array
target∈array ,返回
index
; - 如果
t
a
r
g
e
t
target
target 不在数组中,返回
-1
。
- 如果
t
a
r
g
e
t
∈
a
r
r
a
y
target\in array
target∈array ,返回
-
题目假设:
- 假设数组 n u m s nums nums 中的所有元素不重复;
- 数组
n
u
m
s
nums
nums 的长度为
[1,10000]
之间; - 数组
n
u
m
s
nums
nums 的每个元素都将在
[-9999,9999]
之间。
-
暴力:其实就是不用二分法,遍历整个数组,看数组内有没有目标值
int search(int* nums, int numsSize, int target){ for(int i=0;i<numsSize;i++){ if(nums[i]==target) return i; } return -1; }
-
我其实觉得这个应该不算对,因为没用二分法。。
-
时间复杂度: O ( n ) O(n) O(n)
-
-
二分:二分法就不在这里赘述了,总之可以加快运行速度(数量大的时候肯定整体优于遍历)
-
int search(int* nums, int numsSize, int target){ int left=0,right=numsSize-1,mid; while(left<=right){ mid=(left+right)/2; //better:mid = right + (right - left)/2 if(nums[mid]==target) return mid; else if(nums[mid]>target) right=mid-1; else left=mid+1; } return -1; }
-
时间复杂度 : O ( l o g n ) O(logn) O(logn)
-
空间复杂度 : O ( 1 ) O(1) O(1)
- 注意数组溢出问题:数组中的 i n d e x index index 不要随便加或减,如果是首位/末位就会造成溢出。
-
-
C language review:
-
求数组长度:
- #include<string.h> → \to → strlen(数组)
- sizeof(数组名) / sizeof(数组名[0]) 【数组名不能是形参,因为此时不指数组而是数组第一个元素的地址】
-
数组的传递(晚秋单全忘了):
-
#include <stdio.h> int test2(int a[]){ for(int i=0;i<5;i++){ printf("%d",a[i]); } } int main(){ int a[5] = {1,2,3,4,5},*p; p = a; test2(a); }
-
int test1(int *p){ for(int i=0;i<5;i++){ printf("%d",p[i]);//我们在这里还可以用)*(p+i)来输出数组中的值 } } int main(){ int a[5] = {1,2,3,4,5},*p; p = a; test1(p); }
-
#include <stdio.h> #include<stdio.h> void fun(int *array){ int sum=0; for(int i=0;i<5;i++){ printf("%d\n",array[i]); sum=sum+array[i]; } printf("%d",sum); } int main(){ int *buffer=(int*)malloc(sizeof(int)*5); if(buffer==NULL) exit(1); int array[5]={2,4,5,5,3}; memcpy(buffer,array,sizeof(int)*5); fun(buffer); }
-
-
278. 第一个错误的版本
-
题目概括:将+++++++#########分开,找到第一个#
-
题目假设: 1 ≤ n ≤ 2 31 − 1 1\le n\le 2^{31}-1 1≤n≤231−1
-
二分:
// The API isBadVersion is defined for you. // bool isBadVersion(int version); int firstBadVersion(int n) { int left = 1, right = n, mid; if(isBadVersion(left)) return left; //可以不用 if(isBadVersion(right) && !isBadVersion(right-1)) return right; //可以不用 while(left != right){ mid = left + (right - left)/2; if(!isBadVersion(mid)) left = mid + 1; //range [mid+1,right] else if(isBadVersion(mid)) right = mid; //range[left,mid] } return right; }
- 时间复杂度 : O ( l o g n ) O(logn) O(logn)
- 空间复杂度 : O ( 1 ) O(1) O(1)
- 找到分界线的条件是:left=right
- 因为条件,这个题 可以加 但 不可以减(必有#但是可以没有+)
35. 搜索插入位置
-
题目概括:将一个升序整型数组与目标值进行匹配,返回插入索引值,要求 O ( l o g n ) O(logn) O(logn)
-
题目假设:
- 1 ≤ 数 组 l e n g t h ≤ 1 0 4 1\le 数组length\le 10^{4} 1≤数组length≤104
- − 1 0 4 ≤ n u m s [ i ] ≤ 1 0 4 -10^4\le nums[i]\le 10^{4} −104≤nums[i]≤104
- 数组无重复
- − 1 0 4 ≤ t a r g e t ≤ 1 0 4 -10^4\le target\le 10^{4} −104≤target≤104
-
二分:
-
int searchInsert(int* nums, int numsSize, int target){ int left=0, right=numsSize-1,mid; while(left<=right){ mid = left + (right - left)/2; if(nums[mid]==target) return mid; else if(nums[mid]<target) left = mid+1; else if (nums[mid]>target) right = mid-1; } return left; }
-
int searchInsert(int* nums, int numsSize, int target){ int left=0, right=numsSize-1,mid; while(left<right){ mid = left + (right - left)/2; if(nums[mid]==target) return mid; else if(nums[mid]<target) left = mid+1; else if (nums[mid]>target) right = mid; } if(nums[left]<target) return left+1; return left; }
-
时间复杂度 : O ( l o g n ) O(logn) O(logn)
-
空间复杂度 : O ( 1 ) O(1) O(1)
-
区别就是对 l e f t = r i g h t left = right left=right 的处理。。我感觉我的想法一直被前面的题影响。。
-
以上为自己第一次写的code,基本都得调试,好像没有一次就AC的…我觉得原因可能是我只知道是二分查找,但是并没有对边界条件/区间条件很清晰…
二分查找总结:
二分查找的前提 :有序且无重复元素的数组
- 左闭右闭:
[
l
e
f
t
,
r
i
g
h
t
]
[left,\,\,right]
[left,right]
- 定义的目标 t a r g e t target target 在一个左闭右闭的区间内。
- l e f t = = r i g h t left == right left==right 是有意义的 $\to $ w h i l e ( l e f t < = r i g h t ) while(left<=right) while(left<=right)
- i f ( n u m s [ m i d ] > t a r g e t ) if(nums[mid]>target) if(nums[mid]>target) 时,要让 r i g h t = m i d − 1 right=mid-1 right=mid−1,因为此时 n u m s [ m i d ] nums[mid] nums[mid] 一定不是 t a r g e t target target,所以接下来右区间的结束下标位置就是 m i d − 1 mid-1 mid−1。
- 左闭右开:
[
l
e
f
t
,
r
i
g
h
t
)
[left,\,\, right)
[left,right)
- 定义的目标 t a r g e t target target 在一个左闭右开的区间内。
- l e f t = = r i g h t left == right left==right 是没有意义的 $\to $ w h i l e ( l e f t < r i g h t ) while(left<right) while(left<right)
- i f ( n u m s [ m i d ] > t a r g e t ) if(nums[mid]>target) if(nums[mid]>target) 时,要让 r i g h t = m i d right=mid right=mid,因为此时 n u m s [ m i d ] nums[mid] nums[mid] 一定不是 t a r g e t target target,而由于右区间为开区间。所以接下来右区间的结束下标位置就是 m i d mid mid,此时也不含 m i d mid mid。
Reference:
- https://blog.csdn.net/Laoynice/article/details/79196993
- https://blog.csdn.net/AI_LX/article/details/89053892