【LeetCode-算法入门】D1-二分查找

本文详细介绍了二分查找算法,包括其在不同问题(如寻找目标值、第一个错误的版本、搜索插入位置)中的应用。通过示例代码展示了如何实现二分查找,并分析了时间复杂度和空间复杂度。同时,文章强调了二分查找的边界条件处理以及不同场景下区间定义的重要性。
摘要由CSDN通过智能技术生成

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 targetarray​ ,返回index
    • 如果 t a r g e t target target 不在数组中,返回-1
  • 题目假设

    • 假设数组 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 1n2311

  • 二分

    // 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} 1length104
    • − 1 0 4 ≤ n u m s [ i ] ≤ 1 0 4 -10^4\le nums[i]\le 10^{4} 104nums[i]104
    • 数组无重复
    • − 1 0 4 ≤ t a r g e t ≤ 1 0 4 -10^4\le target\le 10^{4} 104target104
  • 二分

    • 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的…我觉得原因可能是我只知道是二分查找,但是并没有对边界条件/区间条件很清晰…


二分查找总结:

二分查找的前提 :有序且无重复元素的数组

  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 − 1 right=mid-1 right=mid1,因为此时 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 mid1
  2. 左闭右开: [ 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:
  1. https://blog.csdn.net/Laoynice/article/details/79196993
  2. https://blog.csdn.net/AI_LX/article/details/89053892
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值