Day1|数组算法学习:704. 二分查找、27. 移除元素。

1. 二分查找

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

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

文章讲解:代码随想录

视频讲解:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili

很久之前开始看,看了一会(将近把数组看完)就颓废了,现在重新开始吧,先打复活赛!

思路: 二分查找法, 确定一个中间值 middle,通过比较值nums[middle]和target的大小来判断在左边二分查找还是在右边二分查找, 这里的边界需要注意, right到底是nums.size()还是nums.size() - 1, 不同的值会影响到while中的条件是 left < right 还是 left <= right. 

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right){
            int middle = left + ((right - left) >> 1);
            if (nums[middle] < target){
                left = middle + 1;
            }
            else if (nums[middle] > target){
                right = middle - 1;
            }
            else if (nums[middle] == target){
                return middle;
            }
        }
        return -1;
    }
};

我的错误:

定义 right 的时候是 right = num.size(), 但是 while 语句中的内容并没有修改成 left < right. 可能出现如下的错误

除此之外, 还学到了一些东西:

1. 因为 left 和 right 都是整型元素, 我们计算middle = (left + right) / 2时, left + right 可能产生越界的情况, 如果使用 left + ((right - left) >> 1), 能够达到相同的效果而且不会产生越界的影响.

2. 位运算 >> 相当于左移1位, 除以2的1次方.

2. 移除元素:

力扣题目链接(opens new window)

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。

示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

你不需要考虑数组中超出新长度后面的元素。

《代码随想录》算法视频公开课 (opens new window)数组中移除元素并不容易!LeetCode:27. 移除元素 (opens new window),相信结合视频再看本篇题解,更有助于大家对本题的理解

思路: 定义一个慢指针和一个快指针, 慢指针负责模拟删除,  快指针负责把后面的元素往前移一位

// 第一次的错误代码
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow = 0;
        for(int fast = 1; fast < nums.size(); fast++){ 
            if( nums[fast] != val && nums[slow] == val) {
                nums[slow] == nums[fast];
                slow++;
                }
            if (nums[slow] != val) slow++;
        }
        return slow;
    }
};

 大致这样一个思路吧:slow指针和fast指针一前一后的遍历数组。

 

但是我发现会有一个这样的错误:

  • 执行完第一个 if 判断语句后 slow++ 直接进入了下一个 if 判断语句了, 导致了 slow 反而变成了快指针, 原本的预想直接作废了。

于是我想着, 既然这个 slow++ 语句会影响 slow 指针,我就删掉 if(nums[slow] != val) slow++; 这个语句嘛。于是我自信的又去执行一遍,结果又出现了问题:

  • 我在第一个判断语句里加入了这么一个条件: nums[slow] == val, 我想着如果慢指针指着目标值肯定就得等一下嘛, 但是显然, 这只是我的主观判断, 这会导致后面 slow 语句一直停留在 val 元素的下一个元素处一直停留.

所以, 删去 nums[slow] == val, 再通过上述的图进行Debug, 再去运行, 然后还是出现问题了...

  • 如果fast指针从1开始, 会导致容器内的第1个元素, 也就是nums[0]被直接抹去了

所以最终正确的代码:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow = 0;
        for(int fast = 0; fast < nums.size(); fast++){
            if( nums[fast] != val) {
                nums[slow] = nums[fast];
                slow++;
                }
        }
        return slow;
    }
};

今天代码部分花费时间挺长的将近2个小时, 博客也将近写了2个小时, 不过开始就坚持下去吧.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值