代码随想录:二分查找和双指针

二分查找

lc704

c 复制代码
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        while(left < right){
            int mid = (left + right) >> 1;  // 可以写成mid = left + (right - left) >> 1
            if(nums[mid] >= target){
                right = mid;
            }else{
                left = mid + 1;
            }
        }
        if(nums[left] == target){
            return left;
        }
        return -1;
    }
};

lc35

  • lc35
  • 思路:手写lower_bound
  • 代码
c 复制代码
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        // 找第一个>=target的位置
        int left = 0, right = nums.size();
        while(left < right){
            int mid = (left + right) >> 1;
            if(nums[mid] >= target){
                right = mid;
            } else{
                left = mid + 1;
            }
        }
        return left;
    }
};

lc34

  • lc34
  • 和y总的二分例题一样
  • 代码
c 复制代码
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.empty()){
            return {-1, -1};
        }
        // lower_bound和upper_bound,注意二分计算时mid的溢出
        // 1. 第一个位置
        int left = 0, right = nums.size() - 1;
        while(left < right){
            int mid = left + (right - left) / 2;
            if(nums[mid] >= target){
                right = mid;
            }else{
                left = mid + 1;
            }
        }
        if(nums[left] != target){
            // 返回[-1, -1]
            return {-1, -1};
        }
        int first = left;  // 记录第一个位置
        left = 0, right = nums.size() - 1;
        // 2. 最后一个位置
        while(left < right){
            int mid = left + (right - left + 1) / 2;
            if(nums[mid] <= target){
                left = mid;
            }else{
                right = mid - 1;
            }
        }
        // 返回结果
        return {first, left};
    }
};

lc69

  • lc69
  • 回忆浮点数二分:保证一定精度内正确;但这题使用整数二分即可
  • 代码
c 复制代码
class Solution {
public:
    int mySqrt(int x) {
        int left = 0, right = 1e9;
        while(left < right){
            int mid = (right + left + 1) / 2;
            if((long long)mid * mid <= x){  // 舍去小数,所以找小于的一边
                left = mid;
            }else{
                right = mid - 1;
            }
        }
        return left;
    }
};

lc367

c 复制代码
class Solution {
public:
    bool isPerfectSquare(int num) {
        // 暴力:遍历所有int看是否平方 == num;所以使用二分简化
        int left = 1, right = 1e9;
        while(left < right){
            int mid = (left + right) >> 1;
            if((long long)mid * mid >= num){
                right = mid;
            }else{
                left = mid + 1;
            }
        }
        if((long long)left * left == num){
            return true;
        }
        return false;
    }
};

快慢指针

lc27

  • lc27
  • 暴力解:双重for,遍历到val就全部元素往前移一个位置,时间复杂度为O(n^2)
  • 优化思路:弄懂快慢指针含义即可,时间复杂度为O(n)
    • fast: 原数组位置,寻找不为val值的元素
    • slow:最终的目标数组位置
    • 变化:fast指向的不是val的元素放到slow处
  • 代码
c 复制代码
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int fast = 0, slow = 0; 
        for(; fast < nums.size(); fast++){
            if(val != nums[fast]){
                nums[slow++] = nums[fast];
            }
        }
        return slow;
    }
};

lc26

  • 题目
  • 上一题的变形,主要理解快慢指针的含义和他们之间的关系
  • 代码
c 复制代码
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.empty()){
            return 0;
        }
        // 快指针:指向原数组,找到第一个不同的元素
        // 慢指针:指向结果数组的位置
        // 如果nums[fast] != nums[fast - 1],就把这个不重复元素送到slow位置
        int slow = 1, fast = 1;
        for(; fast < nums.size(); fast++){
            if(nums[fast] != nums[fast -1]){
                nums[slow++] = nums[fast];
            }
        }
        return slow;
    }
};

lc844

  • lc844
  • 思路1:利用上面快慢指针的思想,分别得到两个最终的字符串后,再比较,时间复杂度为O(n+m);也可以用栈的思路获取最终的字符串
  • 代码:
c 复制代码
class Solution {
public:
    bool backspaceCompare(string s, string t) {
        // 1. 先去掉退格字符
        int change_s = changeString(s);
        int change_t = changeString(t);
        cout << "s = " << s << " t = " << t << endl;
        cout << change_s << ' ' << change_t << endl;
        // 2. 比较前几个字符是否相同
        if(change_s != change_t){
            return false;
        }
        for(int i = 0; i < change_s; i++){
            if(s[i] != t[i]){
                return false;
            }
        }
        return true;
    }
    int changeString(string &str){
        // 返回前几个字符是有效的
        int slow = 0, fast = 0;
        for(; fast < str.size(); fast++){
            if(str[fast] == '#'){
                if(slow != 0){  // 如果slow已经在开头,不用动
                    --slow;
                }
            } else{
                str[slow++] = str[fast];
            }
        }
        return slow;
    }
};

lc977

  • lc977
  • 思路:相向指针,因为负数平方从大到小,正数平方从小到大;两个指针比较即两个数的平方比较,大的一个放到目标数组中
  • 代码
c 复制代码
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        // 暴力:平方后排序
        // for(auto &i : nums){
        //     i = i * i;
        // }
        // sort(nums.begin(), nums.end());
        // return nums;
        // 双指针:两头指针,大的放到后面
        int n_size = nums.size() - 1;
        vector<int> ret(n_size + 1);
        for(int i = 0, j = n_size, pos = n_size; i <= j; ){
            if(nums[i] * nums[i] <= nums[j] * nums[j]){
                ret[pos--] = nums[j] * nums[j];
                j--;
            } else{
                ret[pos--] = nums[i] * nums[i];
                i++;
            }
        }
        return ret;
    }
};
相关推荐
颜酱28 分钟前
二叉树分解问题思路解题模式
javascript·后端·算法
qianpeng8972 小时前
水声匹配场定位原理及实验
算法
董董灿是个攻城狮13 小时前
AI视觉连载8:传统 CV 之边缘检测
算法
blasit20 小时前
笔记:Qt C++建立子线程做一个socket TCP常连接通信
c++·qt·tcp/ip
AI软著研究员20 小时前
程序员必看:软著不是“面子工程”,是代码的“法律保险”
算法
FunnySaltyFish21 小时前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
颜酱1 天前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法
地平线开发者2 天前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮2 天前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者2 天前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶