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

文章介绍了几个LeetCode问题中的二分查找算法应用,包括搜索插入位置、查找范围、平方根计算等,以及涉及快慢指针优化的删除重复元素和去除非打印字符等问题。
摘要由CSDN通过智能技术生成

二分查找

lc704

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
  • 代码
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总的二分例题一样
  • 代码
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
  • 回忆浮点数二分:保证一定精度内正确;但这题使用整数二分即可
  • 代码
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

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处
  • 代码
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

  • 题目
  • 上一题的变形,主要理解快慢指针的含义和他们之间的关系
  • 代码
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);也可以用栈的思路获取最终的字符串
  • 代码:
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
  • 思路:相向指针,因为负数平方从大到小,正数平方从小到大;两个指针比较即两个数的平方比较,大的一个放到目标数组中
  • 代码
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;
    }
};
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值