leetcode刷题(第一周)笔记--二分专题

leetcode --二分专题

一.思路

在这里插入图片描述
常见的二分一般是数组满足按序排列,其实广义来看,只需要满足左边符合性质1,右边满足性质2即可,分界点跟随其中的某一段性质,然后根据中点不断二分,最后当l=r时,就找完了整个数组,若这个时候找到的值等于target,则寻找完毕,输出即可!

二.两套模板

简易速记:更新L和R时,两个模板中一个时R=M,一个是L=M,模板中对M的更新可以概括为左加右不加,左加等价于(m=(l+r+1)/2),多加一个1,右不加等价于(m=(l+r)/2)

写代码时候,我习惯将含边界点(一般来说判断条件有等于号的)写在if里

上图的模板1:右不加情况:要把R更新为M

//找的点是性质2的分界点(即满足性质2)
int l,r;
while(l<r){
    int m=(l+r)/2;
    if(m满足性质2,可知分界点在m的左边或就是m,所以将区间更新为(l,m)) r=m;
    else  l=m+1;
}
return l or r;

上图的模板1:左加的情况:要把L更新为M

//找的点是性质1的分界点(即满足性质1)
int l,r;
while(l<r){
    int m=(l+r+1)/2;   //多加一个1
    if(m满足性质1,可知分界点在m的右边或就是m,所以将区间更新为(m,r)) l=m;
    else  r=m-1;
}
return l or r;

三.具体的题目(leetcode)

整理了10道题目 题号如下:
1.69-------2.35-------3.34-------4.74-------5.153
6.33-------7.278-----8.162------9.287----10.275
具体题目就不放了,题目可以去官网找:https://leetcode.com/problemset/all/

//二分-1:leetcode 69
class Solution {
public:
    int mySqrt(int x) {
    	int l=0,r=x;

    	while(l<r){
    		int mid = l+(long long )r+1 >>1;
    		if(mid<=x/mid) l=mid;
    		else r=mid-1;
    	}
    	return r;
        
    }
};

//二分-2:leetcode 35
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
    	//特判一下
    	int n=nums.size();
    	if (n==0 || nums[n-1]<target) return n;
    	int l=0,r=n-1;
    	while(l<r){
    		int mid=l+r>>1;
    		if(target<=nums[mid]) r=mid;
    		else l=mid+1;
    	}
    	return r;
    }
};

//二分-3:leetcode 34
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
    	//左边和右边就都需要判定
        //先找出左边的数字
        int start,end;
        int n=nums.size();
        if(n==0) return vector<int> ({-1,-1})
        int l=0,r=n-1;
        while(l<r){
        	int mid=l+r>>1;
        	if(nums[mid]>=target) r=mid;
        	else l=mid+1; 
        }
        if(nums[r]!=target) return vector<int> ({-1,-1});
        else 
        	start=r;    //将小的找了出来
       	r=n-1

        while(l<r){
        	int mid=l+r+1>>1;
        	if(nums[mid]<=target) l=mid;
        	else r=mid-1; 
        }
        if(nums[r]!=target) return vector<int> ({-1,-1});
        else
        	end=r;

        return vector<int> ({start,end});

    }
};

//二分-4:leetcode 74
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.empty() || matrix[0].empty()) return false;
        int n=matrix.size(),m=matrix[0].size();
      int l=0,r=n*m-1;
      while(l<r){
        int mid=l+r+1>>1;
        if(matrix[mid/m][mid%m]<=target) l=mid;
        else r=mid-1;
      }
        return matrix[r/m][r%m] == target;
    }
};

//二分-5:leetcode 153
//[4,5,6,7,1,2,3]  旋转后的表,需要找到二分的点,因为旋转的是单调数组,
//所以在例子中的1右边的数都小于4,左边都大于4,
class Solution {
public:
    int findMin(vector<int>& nums) {
    	int n=nums.size();
    	int l=0,r=n-1;
    	while(l<r){
    		int mid=l+r>>1;
    		if(nums[mid]<=nums[n-1]) r=mid;
    		else l=mid+1;
    	}
    	return nums[r];
    }
};

//二分-6 :leetcode 33
class Solution {
public:
    int search(vector<int>& nums, int target) {
        if(nums.empty()) return -1;
        int n=nums.size();
    	int l=0,r=n-1;
    	while(l<r){
    		int mid=l+r>>1;
    		if(nums[mid]<=nums[n-1]) r=mid;
    		else l=mid+1;
    	}
    	int min_index=r;   //这个时候报错 debug
    	//Last executed input 只有一个数的时候
    	if(nums[n-1]>=target) 
            l=min_index,r=n-1;
    	else
    		l=0,r=max(0,min_index-1); //如果r=min_index-1的话,就会溢出报错,所以特判一下,=-1,max将其设为0
    	while(l<r){
    		int mid1 = l+r+1>>1;
    		if(nums[mid1]<=target) l=mid1;
    		else r=mid1-1;
    	}
    	if(nums[r]==target) return r;
    	else return -1;
    }
};


//二分-7 :leetcode 278
// Forward declaration of isBadVersion API.
//[1,2,3,4,5,4,3,2,1] 拆分性质 第一个属于[1,2,3,4] 好产品  第二个属于[5,4,3,2,1]坏产品
bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
    	int l=1,r=n;
    	while(l<r){
    		int mid=(long long)l+(long long)r>>1;   //大的值溢出,所以将l和r的类型转换成long long
    		//或者直接在开头定义为 long long l=1,r=n;
    		if(isBadVersion(mid)) r=mid;
    		else l=mid+1;
    	}
    	return r;
    }
};

//二分-8 :leetcode 162
//[1,2,3,2]滑动窗口为3,扫一遍,o(n)肯定可以将所有的峰值点找出来,但在这个题中,只需要返回一个峰值即可,
//所以将时间复杂度降低的方法,考虑二分,拆分性质,左边右边。
//[1,2,1,3,5,6,4]  
class Solution {
public:
    int findPeakElement(vector<int>& nums) {
    	int n=nums.size();
    	if(n==1 || nums[0]>nums[1]) return 0;
    	int l=1,r=n-1;
    	while(l<r){
    		int mid=l+r+1>>1;
    		if(nums[mid]>nums[mid-1]) l=mid;
    		else r=mid-1;
    	}
    	return r;
    }
};

//二分-9 :leetcode 287
//不能使用额外空间,原本可以用线性扫描+hash表来处理,但是不可以使用额外空间,暴力做法两重循环,复杂度o(n2)
//优化在于是否考虑可以将o(n2)降成o(nlogn),这里改变一下思路,不二分索引,而是二分n的大小,n+1个数,每个数从
//1到n,要重复的话,这个词就只能出现1次,所以在1-n这个角度上进行二分,每次比较的是小于等于mid的数的数量是否
//等于mid,还是大于mid,第一层二分循环上时间复杂度为o(logn),循环里面统计个数扫描时间复杂度为o(n),总共的时间
//复杂度为o(nlogn),优化了o(n)
class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int n=nums.size();
        int l=1,r=n;
        while(l<r){
            int mid=l+r>>1;//用mid将其分为两部分,
            int count=0;
            for (int i=0;i<n;i++){
                if(nums[i]<=mid) count++;
            }
            if(count>mid) r=mid;
            else l=mid+1;   //其实else就是count=mid,
        }
    }
};

//二分-10 :leetcode 275
//由于数组是从小到大排好序的,所以我们的任务是:在数组中找一个最大的 hh,使得后 hh 个数大于等于 hh。
//我们发现:如果 hh 满足,则小于 hh 的数都满足;如果 hh 不满足,则大于 hh 的数都不满足。所以具有二分性质。
//直接二分即可。时间复杂度分析:二分检索,只遍历 lognlogn 个元素,所以时间复杂度是 O(logn)O(logn)。
class Solution {
public:
    int hIndex(vector<int>& citations) {
        if (citations.empty()) return 0;
        int l = 0, r = citations.size() - 1;
        while (l < r)
        {
            int mid = (l + r) / 2;
            if (citations.size() - mid <= citations[mid]) r = mid;
            else l = mid + 1;
        }
        if (citations.size() - l <= citations[l]) return citations.size() - l;
        return 0;
    }
};

虽说算法靠理解,但是应对笔试面试,还是需要背一定的模板!记得面字节跳动01背包,快速和归并排序都是原题,背模板就可以,很重要重要!

感谢acwing的闫学灿大佬:https://www.acwing.com/,推荐给刷题的小伙伴们~
秋招加油~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值