leetcode35

比特逐星人
• 阅读 320

这道题目可以使用暴力的解法,不过暴力的效率不够高,因此可以采用二分查找,题目连接直接给出:https://leetcode.cn/problems/search-insert-position/description/

通常的整数二分模板是如下这样的:

bool check(int x) {/*...*/} // 检查x是否满足某种性质

//区间[l, r]被划分成[l, mid]和[mid+1, r]时使用:
int bsearch_1(int l, int r) {
    while(l < r) {
        int mid = l+r>>1; // 若产生整数溢出 改为 l+(r-l>>1)
        if(check(mid)) r = mid; //check判断mid是否满足性质
        else l = mid+1;
    }
}

//区间[l, r]被划分成[l, mid-1]和[mid, r]时使用:
int bsearch_2(int l, int r) {
    while(l < r) {
        int mid = l+r+1>>1; // 若产生整数溢出 改为 l+(r+1-l>>1)
        if(check(mid)) l = mid;
        else r = mid-1;
    }
}

可以发现区间边界的划分,不是mid+1就是mid-1,因此这个模板对这道题不太可行,所以单独记录下本题目的二分思路。

二分查找涉及的很多的边界条件,逻辑比较简单,就是写不好。相信很多同学对二分查找法中边界条件处理不好。例如到底是while(left < right)还是while(left <= right),到底是right = middle呢,还是要right = middle - 1呢?这里弄不清楚主要是因为对区间的定义没有想清楚,这就是不变量。要在二分查找的过程中,保持不变量,这也就是循环不变量 (感兴趣的同学可以查一查)。

以这道题目来举例,以下的代码中定义target是在一个在左闭右闭的区间里,也就是[left, right](这个很重要)。这就决定了这个二分法的代码如何去写,大家看如下代码。要仔细看注释,思考为什么要写while(l <= r),为什么要写r = m - 1

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        // 1. 暴力版本
        // int n = nums.size();
        // for(int i = 0; i < n; ++i) {
        //     if(nums[i] >= target) return i;
        // }
        // return n;

        // 2. 二分版本
        int n = nums.size();
        int l = 0, r = n-1; // 定义target在左闭右闭的区间里,[l, r]
        while(l <= r) { // 当l == r,区间[l, r]依然有效
            int m = (l+r) >> 1;
            if(nums[m] < target) l = m+1; // target在左区间,所以[l, m-1]
            if(nums[m] > target) r = m-1; // target在右区间,所以[m+1, r]
            if(nums[m] == target) return m;
        }

        // 分为以下三种情况考虑:
        // 目标值在数组所有元素之前,即最左侧,取l
        // 目标值等于数组中元素的值 直接return m
        // 目标值在数组某个元素的右侧以及在所有元素之后,即最右侧 取l
        return l;
    }
};

当然上面的写法是以l为例,且区间为左右均闭,更多写法可参考:https://programmercarl.com/0035.%E6%90%9C%E7%B4%A2%E6%8F%92%E...

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Stella981 Stella981
3年前
Codeforces 862B (二分图染色)
<题目链接(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fvjudge.net%2Fproblem%2FCodeForces862B)\题目大意:给出一个有n个点的二分图和n1条边,问现在最多可以添加多少条边使得这个图中不存在自环,重边,并且此图还是一个二
Stella981 Stella981
3年前
558. Quad Tree Intersection
https://leetcode.com/problems/quadtreeintersection/description/我觉得是用意挺好的一题目。求两个四叉树的逻辑union,可惜测试用例里面居然包含对题目外因素的检查(那个id)懒得弄了。思路其实挺简单,但是很容易忽略一个edgecase,就是当所有children的value都一致
Stella981 Stella981
3年前
851. Loud and Rich —— weekly contest 87
851\.LoudandRich题目链接:https://leetcode.com/problems/loudandrich/description/(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fleetcode.com%2Fpr
Stella981 Stella981
3年前
925. Long Pressed Name
题目链接:https://leetcode.com/problems/longpressedname/description/(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fleetcode.com%2Fproblems%2Flongpressedname%2Fdescript
Wesley13 Wesley13
3年前
83. 删除排序链表中的重复元素
题目描述题目地址:https://leetcodecn.com/problems/removeduplicatesfromsortedlist/给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。示例1:输入:112输出:12示例 2:输入:11233输出:
Wesley13 Wesley13
3年前
C#二分查找算法设计实现
C二分查找算法设计实现1.介绍二分查找也称折半查找(BinarySearch),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。(记住了前提要求是顺序存储结构,而且要有序排序,所以说对于一个无序的是没法用二分查找的)2.查找算法过程
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
贾蔷 贾蔷
2个月前
力扣1137题 解题思路和步骤 C++代码实现,力扣一共多少题
一、题目分析力扣1137题要求我们找到第N个泰波那契数。泰波那契数的定义是:T00,T11,T21,且在n0的条件下Tn3TnTn1Tn2。,当n4时,T4T3T2T14。这道题主要考查我们对递归或动态规划的理解和运用。在思考解题方法时,我们
深度学习 深度学习
2星期前
双指针法解决力扣922题:按奇偶排序数组II的完整指南
一、问题理解题目要求将一个重新,使得:1.所有偶数位于偶数位置(索引0,2,4...)1.所有奇数位于奇数索引位置(索引1,3,5...)1.不要求数字本身的排序,只需满足奇偶位置正确二、解法思路采用,分别维护两个:even指针:负责扫描偶数索引位置odd