代码随想录算法训练营第一天| LeetCode|C++| 704. 二分查找、27. 移除元素

704.二分查找

使用二分法的前提条件:
1.数组为有序数组
2.数组中无重复元素

思路:
1、双指针法,一前一后,对半查找
2、确定区间不变,[ ] or [ )
3、是个重复的过程,用while循环,确定循环条件

易错点:
1.while循环的条件 left <= right or left < right
2.right = middle - 1 or right = middle
3.采用[left, right) 时还需要注意right的初始值为right = nums.size();(因为区间不包含右边界

区间的一般定义为:
1.[left, right]
2.[left, right) 此处的区间就是我们每次循环的搜索区间
**原则:**选定区间并坚持这个定义!

注意: int middle = (left + right)/2 两个int型相加有时候会越界,可用int middle = left + (right - left)/2 代替。

使用左闭右闭区间的代码如下:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        /*
            1、双指针法,一前一后,对半查找
            2、确定区间不变,[   ]
            3、是个重复的过程,用while循环,确定循环条件
        */
        int left = 0;
        int right = nums.size() - 1;

        while(left <= right){
            int middle = left + (right - left) / 2;
            if(nums[middle] < target){
                left = middle + 1;
            }else if(nums[middle] > target){
                right = middle - 1;
            }else{
                return middle;
            }
        }
        return -1;
    }
};

使用左闭右开区间的代码如下:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        /*
            1、双指针法,一前一后,对半查找
            2、确定区间不变,[   )
            3、是个重复的过程,用while循环,确定循环条件
        */
        int left = 0;
        int right = nums.size();

        while(left < right){
            int middle = left + (right - left) / 2;
            if(nums[middle] < target){
                left = middle + 1;
            }else if(nums[middle] > target){
                right = middle;
            }else{
                return middle;
            }
        }
        return -1;
    }
};

27.移除元素

解法一: 暴力解法,双层for循环

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        /*
            1、暴力解法,双层for循环
            2、一层for循环找val,另一层更新数组
        */
        int size = nums.size();
        for(int i = 0; i < size; i++){
            if(nums[i] == val){
                for(int j = i + 1; j < size; j++){
                    nums[j - 1] = nums[j];
                }
                size--;
                i--;
            }
        }
        return size;
    }
};

自己写的时候出现的问题:
1、循环条件写成 i < nums.size()j < nums.size()。显然是错误的。若满足条件nums[i] == val,则通过内层for循环后,数组后面的元素都会往前进行覆盖,那么数组在nums.size()这个位置就没了意义,于是就会出现问题。错误为:超出时间限制。
2、内层循环写成

for(int j = i; j < size; j++){
	nums[j] = nums[j + 1];
}

一开始觉得和正确的代码没什么区别,其实不然。此处问题在于,当写成 nums[j] = nums[j + 1]时,若 j 到达数组最后一位时,并没有 nums[j+1]可用于赋值,已经超出数组的范围了。错误为:ERROR: AddressSanitizer: heap-buffer-overflow on address。
3、把size--写进了内层for循环里。显然错误。
4、漏掉了i--。每次往前覆盖时,i就应该从原地开始执行if判断。

解法二: 双指针解法

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        /*
            1、双指针解法,快慢指针追逐
        */
        int slow = 0;
        for(int fast = 0; fast < nums.size(); fast++){
            if(nums[fast] != val){
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
};

总结:
记录还是蛮费时间的,而且这两题还是之前都做过了的。不过,自己亲手敲一遍真的能发现很多错误。继续加油。

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值