力扣基础刷题---二分查找

704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

中心思想:找到中间值,跟中间值比较,如果比中间的大,就在后半部分;如果比中间的小,就在前半部分;如果相等即为所求。当遍历到最后,还不存在,则说明不存在。

方法一:左闭右闭区间( right=nums.size()-1;)

target 是在一个在左闭右闭的区间里,也就是[left, right] ,在这个情况下,while要包含left==right的情况。

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

方法二:左闭右开区间( right=nums.size();)

  • while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
  • if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
cpp 复制代码
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;int right=nums.size();
        if(right<=left) return -1;
        while(left<right){
            int mid=(right+left)/2;
            if(nums[mid]==target)   return mid; 
            else if(nums[mid]<target) left=mid+1;
            else right=mid;   
        }
        return -1;
    }
};

374. 猜数字大小

这道题读懂题目即可。其实和上面一模一样

需要注意:

  • 1 <= n <= - 1
  • 2n其实超出了int的范围,所以需要把left、right、mid设置为long 类型
cpp 复制代码
class Solution {
public:
    int guessNumber(int n) {//左闭右闭区间
        long left=1;long right=n;long mid;
        while(left<=right){
            mid=(left+right)/2;
            if(guess(mid)>0)// pick > num
                left=mid+1;
            else if(guess(mid)==0) break;
            else right=mid-1;
        }
        return mid;
    }
};

35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置.

时间复杂度为 O(log n) 的算法。-----》二分算法

返回按顺序插入的位置,其实就是二分查找的时候,left所在的点。

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

34. 在排序数组中查找元素的第一个和最后一个位置

两个方法:简单点想其实就是找到所有与target相等的值,最小的就是第一个,最大的就是最后一个。全部找出来,复杂度有点高。

方法一:那不妨想,第一个实际上就是不断向前找;最后一个就是不断向前找。可以分为两次查找

cpp 复制代码
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(!nums.size()) return {-1,-1};
        int first=-1;int last=-1;int mid;
        int left=0;int right=nums.size()-1;
        //找first
        while(left<=right){
            mid=(left+right)/2;
            if(nums[mid]==target) {
                first=mid;
                right=mid-1;//不断向前找
            }
            else if(nums[mid]>target) right=mid-1;
            else left=mid+1;
        }
        
        //找last
        left=0; right=nums.size()-1;
        while(left<=right){
            mid=(left+right)/2;
            if(nums[mid]==target) {
                last=mid;
                left=mid+1;//不断向后找
            }
            else if(nums[mid]>target) right=mid-1;
            else left=mid+1;
        }

        return {first,last};
    }
};

方法二:看上面的代码,其实大部分代码都是相同的逻辑,我们不防精简一下:

cpp 复制代码
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int l = 0, r = nums.size() - 1;
        vector<int> ret {-1, -1};
        while(l <= r){
            int mid = (l + r) / 2;
            if(nums[mid] > target){
                r = mid - 1;
            }else if (nums[mid] < target){
                l = mid + 1;
            }else{
                l = r = mid;
                while(--l >= 0 && nums[l] == target){
                    ;
                }
                while(++r < nums.size() &&nums[r] == target){
                    ;
                }
                ret[0] = l + 1;
                ret[1] = r - 1;
                return ret;
            }
        }
        return ret;
    }
};

这个就是找到中间那个相等的值之后,不断像前,向后逼近。(一次二分)

cpp 复制代码
                while(--l >= 0 && nums[l] == target){
                    ;
                }
                while(++r < nums.size() &&nums[r] == target){
                    ;
                }
                ret[0] = l + 1;
                ret[1] = r - 1;

167. 两数之和 II - 输入有序数组

双指针+空间缩减(题解推荐:167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

同样这里注意审题,返回的下标

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {//双指针+缩减空间
        int row=0;int col=numbers.size()-1;
        
        while(row<col){
            int sum=numbers[row]+numbers[col];
            if(sum>target){
                col--;
            }
            else if(sum<target) row++;
            else return vector<int>{row+1,col+1};
        }
        return vector<int>{-1,-1};
    }
};

拓展一下:返回二维数组的情况还可以直接返回

cpp 复制代码
{row+1,col+1};

或者利用veror动态数组的内置函数

cpp 复制代码
        vector<int> res;
                res.push_back(low+1);
                res.push_back(high+1);
        return res;
相关推荐
adam_life4 分钟前
http://noi.openjudge.cn/——2.5基本算法之搜索——200:Solitaire
算法·宽搜·布局唯一码
我想进大厂1 小时前
图论---朴素Prim(稠密图)
数据结构·c++·算法·图论
我想进大厂1 小时前
图论---Bellman-Ford算法
数据结构·c++·算法·图论
AIGC大时代1 小时前
高效使用DeepSeek对“情境+ 对象 +问题“型课题进行开题!
数据库·人工智能·算法·aigc·智能写作·deepseek
lkbhua莱克瓦241 小时前
用C语言实现——一个中缀表达式的计算器。支持用户输入和动画演示过程。
c语言·开发语言·数据结构·链表·学习方法·交友·计算器
CODE_RabbitV1 小时前
【深度强化学习 DRL 快速实践】近端策略优化 (PPO)
算法
Wendy_robot2 小时前
【滑动窗口+哈希表/数组记录】Leetcode 438. 找到字符串中所有字母异位词
c++·算法·leetcode
程序员-King.2 小时前
day49—双指针+贪心—验证回文串(LeetCode-680)
算法·leetcode·贪心算法·双指针
转基因3 小时前
Codeforces Round 1020 (Div. 3)(题解ABCDEF)
数据结构·c++·算法
Forworder4 小时前
[数据结构]树和二叉树
java·数据结构·intellij-idea·idea