二分查找、移除元素(Day1)

目录

二分查找题目链接:

正文

移除元素题目链接

二分查找题目链接:

力扣https://leetcode.cn/problems/binary-search/

直接跳转正文

(以下是废话,请跳过)(因为本来就是打算写给自己看的,所以发挥传统废话技能:呃呃,我第一次用力扣,是最近才开始能写C++的,代码框一上来就默认给了我个class Solution,呃呃,我类那边不咋熟,整个人都愣住了,啥玩意儿这是,然后尝试在main函数里创建一个Solution对象,并试图调用成员函数search,呃呃,一堆问题,题目给了n,但是没告诉我n是多少,我一个劲的想着我*这个vector数组怎么输入(大脑未响应)还有给的输入样例,居然带[中括号]和逗号,(我:这是要我判断一下起始是左括号结束是右括号,还得忽略中间输入的逗号(??(因为之前一直用的蓝桥没见过这种()后来实在不行,我把class 删了,自己像以前那样写个main函数,结果执行代码的时候跟我说我用了未定义的solution,我傻了,我都没有solution,哪里使用它了,报错如下图)

 

(后来问了其他人,才知道,原来力扣不要写主函数,也不用输入输出,我**)

(以下错误请跳过)我二分一开始写得不对,居然是用
for(int  i=nums.size()/2;i<nums.size();)
{
        if(nums[i]==target)
                return i;
        if(nums[i]>target)
                nums[i]=i/2;//移到开头和i的中间
        if(nums[i]<target)
                nums[i]=i+(nums.size()-i)/2;//移到i和结尾的中间
}
我想二分的思路好像是这个样子的,但是脑子里模拟一下我这个代码的运行过程,怎么感觉哪不对劲...然后扒拉了一下之前考试写的那个二分法求根的代码,噢!我知道了,于是糊涂地写出以下代码:

正文

 int l=0,r=nums.size()-1;
while(l<r)
{
        int m = (l+r)/2;
        if[nums[m]==target)
                return m;
        else if(nums[m]>target)
                r=m;
        else if(nums[m]<target)
                l=m;

}
在后来的尝试中发现,会陷入死循环!
看了二分的讲解之后,我悟了,是边界条件没确定好()
上述情况是左右都是闭区间,所以 l==r 的时候的区间是有意义的,所以是 l<=r 因此m所在的位置已经和target比较过了,所以下次r或者l的位置就应该是m的位置再向左或者向右偏移一位,即:

class Solution {
public:
    int search(vector<int>& nums, int target){
    int l = 0;                     //letf是数组第一个下标
    int r = nums.size()-1;         //right是数组最后一个下标
    while(r>=l)                    //等于时有意义
    { 
        int m = (l+r)/2;
        if(nums[m] == target)
        {
            return m;
        }
                
        else if(nums[m]<target)
            l=i+1;                //向右偏移一位
        else if(nums[m]>target)
            r=i-1;                //向左偏移一位
    }

    return -1;                    //没找到返回-1

    }
};

同理,如果是左闭右开(很多函数都是这样),代码如下:

class Solution {
public:
    int search(vector<int>& nums, int target){
    int l = 0;                    //letf是数组第一个下标
    int r = nums.size();          //right是数组最后一个下标再往后一位,因为右边是开,如果就是数组最后一个下标那么最后一个值就被忽略了
    while(r>l)                    //左闭右开,l == r 等于时无存在的区间,无意义,所以判断条件是 l<r
    { 
        int m = (l+r)/2;
        if(nums[m] == target)
        {
            return m;
        }
                
        else if(nums[m]<target)
            l=i+1;                //左闭,向右偏移一位
        else if(nums[m]>target)
            r=i;                  //右开,不用偏移,因为右边的没有和target比较过
    }

    return -1;                    //没找到返回-1

    }
};

确实对二分有了更清晰的理解了目前 
噢噢刚刚又get到了一点,上述写的 m = (l+r)/2; 最好可以改为 m = l+(r-l)/2; 原因是 l+r 可能会大于整型所能表示的范围,会溢出!!!!但是 r-l 不会

移除元素题目链接:

贴一段没看题解之前的代码:

 结果如下:

 首先之前我没提交的时候执行代码就报错:


上网查找原因后知道力扣使用了AddressSanitizer检查是否存在内存非法访问,比如数组越界
所以我在判断nums[i-1]和nums[i+1]都加了检查越界的条件,最后erase的时候也加了是否找到再erase的条件,不然删不对(这里非常感谢力扣在我解答错误是给出对应的测试数据,否则我根本不会发现)(也是思维的欠缺
以上采用排序后找到target的起始和终止的位置,再用erase删除
在这之前我还想,这题不简单嘛直接遍历,找到就erase,结果出错(( 原因是在用迭代器遍历vector数组的时候删除操作会使迭代器失效
那我就不用迭代器,直接来个for(int i =0;i<size;i++)的循环,结果还是出错(( 原因是在用erase删除的时候,删除位置后的元素会自动向前移动,就会漏删

题解思考方式如下:
“要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。”
有暴力解法和双指针解法,我就懒得再写一遍了,把题解链接直接拷贝过来(什

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值