二分法的基本模板

二分查找

参考连接
一, 最基础的模板

给一个有序无重复的数组,给定一个target,数组中是否存在,若存在,返回对应的下标,若不存在,返回-1

int search(vector<int> &nums, int target){
    int left = 0;
	int right = nums.size()-1;
    while(left<= right){
        int mid = left + (right - left)/2;
        if(target>nums[mid]){
            left = mid+1;
        }else if(target<nums[mid]){
            right = mid-1;
        }else if(target == nums[mid]){
            return mid;
        } 
    }
    return -1;
}

二、如果数组的元素存在重复的情况,使用二分法,找到左侧第一个元素

的位置,并返回位置,否者返回-1

int search(vector<int> &nums, int target){
    int left = 0,right = nums.size()-1;
    while(left <= right){
		int mid  = left + (right - left)/2;
        if(target >nums[mid]){
            left = mid+1;
        }else if(target<nums[mid]){
            right = mid -1; 
        }else if(target == nums[mid]){
            right = mid;
        }
        
    }
    return nums[left] == target?left:-1;
}
/*
 * @Author: FeiPF2020 wpfn218925@163.com
 * @Date: 2022-07-15 23:40:04
 * @LastEditors: FeiPF2020 wpfn218925@163.com
 * @LastEditTime: 2022-07-16 00:37:48
 * @FilePath: \cpp_code\CPPinterver\chpter1\erfen.cpp
 * @Description: 经典的二分模板
 */
#include<iostream>
#include<vector>
using namespace std;
//最基础的二分法
int search(vector<int> &nums, int target){
    int left = 0;
	int right = nums.size()-1;
    while(left<= right){
        int mid = left + (right - left)/2;
        if(target>nums[mid]){
            left = mid+1;
        }else if(target<nums[mid]){
            right = mid-1;
        }else if(target == nums[mid]){
            return mid;
        } 
    }
    return -1;
}
// 有序数组,最左边
int left_search(vector<int> &nums, int target){
    int left = 0,right = nums.size()-1;
    while(left < right){
		int mid  = left + (right - left)/2;
        if(target >nums[mid]){
            left = mid+1;
        }else {
            right = mid;
        }
        
    }
    return nums[left] == target?left:-1;
}

//有序数组最右边
int right_search(vector<int> &nums, int target){
    int left = 0,right = nums.size()-1;
    while(left < right){
		int mid  = left + (right - left)/2+1;
        if(target<nums[mid]){
            right = mid -1; 
        }else {
            left = mid;
        }
        
    }
    return nums[right] == target?right:-1;
}

//有序数组,返回左右
vector<int>  lr_search(vector<int> &nums, int target){
    if(!nums.size() ) return vector<int>{-1,-1};
    vector<int> result;
    //先查找左边,
    int left = 0,right = nums.size()-1;
     while(left < right){
		int mid  = left + (right - left)/2;
        if(target >nums[mid]){
            left = mid+1;
        }else {
            right = mid;
        }
        
    }
    int res =  nums[right] == target?right:-1;
    result.push_back(res);

    if(res != -1){
        int left = res,right = nums.size()-1;
    while(left < right){
		int mid  = left + (right - left)/2+1;
        if(target<nums[mid]){
            right = mid -1; 
        }else {
            left = mid;
        }
    }
    int res1 = nums[right] == target?right:-1;
    result.push_back(res1);
    }else{
        result.push_back(-1);
    }
    return result;
   
}

int main(){
    vector<int> nums = {1,3,4,6,6,6,54,76,92},res_;
    res_ = lr_search(nums,9);
    
    for(auto &x :res_){
        cout<<x<<" ";
    }
    system("pause");
    return 0;
}

可以解决的问题有
69,374
等等

滑动窗口模板

寻找最长

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int left = 0,right = 0;
        int maxlenth = 0;
        unordered_set<char> str;
        while(right<s.size()){
            while(str.find(s[right]) != str.end()){
                str.erase(s[left]);
                left++;
            }
            str.insert(s[right]); 
            maxlenth = max(maxlenth,right-left+1);
            right++;
        }
        return maxlenth;

    }
};

寻找最短

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int left= 0,right = 0;
        int curSum= 0;
        int minLenth = 0;
        while(right<nums.size()){
            curSum  += nums[right];
            while(curSum>= target){
                if(right-left+1<minLenth||minLenth==0){
                    minLenth = right-left+1;
                }
                curSum = curSum-nums[left];
                left++;
            }
            right++;
        }
        return minLenth;
    }
};

滑动窗口算法的思路是这样:

1、我们在字符串 S 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为一个「窗口」。

2、我们先不断地增加 right 指针扩大窗口 [left, right],直到窗口中的字符串符合要求(包含了 T 中的所有字符)。

3、此时,我们停止增加 right,转而不断增加 left 指针缩小窗口 [left, right],直到窗口中的字符串不再符合要求(不包含 T 中的所有字符了)。同时,每次增加 left,我们都要更新一轮结果。

4、重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头。

第 2 步相当于在寻找一个「可行解」,然后第 3 步在优化这个「可行解」,最终找到最优解。左右指针轮流前进,窗口大小增增减减,窗口不断向右滑动。

寻找最长

int left = 0,right =0,length = 所给字符.size();
int result= 0,bestResult;
while(right<n){
    扩大窗口,加入nums[right],并更新result
        while(result不满足要求){
            窗口缩小,left++;
        }
    更新最优的结果,right++;
}
return bestresult;

//int _sum =INT_MAX;

int_min = INT_MIN

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值