代码随想录训练营Day1|力扣704二分查找、27移除元素(C++)

题目链接: . - 力扣(LeetCode)

1.二分法:

状态:没做出来,脑子里很迷糊,只能想到要比较,然后根据比较的结果缩小区间范围。那我该定义什么变量呢?肯定得有left和right,还得有个中间值middle。然后就卡住了,我一直在想要怎么遍历数组,然后我不知道要怎么把遍历数组和这玩意结合起来。

思路:但其实,二分法就是为了减少时间复杂度,就是为了不遍历所有元素。 所以,在接下来的循环也就是我们不断缩小寻找范围中,找循环条件应该是去想这个范围最小缩到多大呢。具体里面的判断条件就是要看,你选取的循环不变量(每次寻找的区间类型是左闭右开,还是左闭右闭)。

代码:(循环不变量是左闭右开)

class Solution {
public:
    // 左闭右开
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size();// 左闭右开,所以right可以取nums.size()
        
        while(left < right){ //这里的条件直接看 left=right时是否有效 
            int middle = left + ((right - left)>>1);
            // middle下标对应的元素不是我们的目标值,那我们下一次的区间范围就要排除它。然后就可以根据我们的循环不变量,来确定下一次区间边界的取值
            if(target < nums[middle]){
                right = middle; // 右边开区间
            }else if(target > nums[middle]){
                left = middle + 1; // 左边闭区间
            }else {
                return middle;
            }
        }
        return -1;
    }
};

(循环不变量是左闭右闭)

class Solution {
public:
    // 左闭右闭
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;// 左闭右闭,所以right不可以取nums.size()
        
        while(left <= right){ //这里的条件直接看 left=right时是否有效 
            int middle = left + ((right - left)>>1);
            // middle下标对应的元素不是我们的目标值,那我们下一次的区间范围就要排除它。然后就可以根据我们的循环不变量,来确定下一次区间边界的取值
            if(target < nums[middle]){
                right = middle - 1; // 右边闭区间
            }else if(target > nums[middle]){
                left = middle + 1; // 左边闭区间
            }else {
                return middle;
            }
        }
        return -1;
    }
};
题目链接: . - 力扣(LeetCode)

2.移除元素

暴力法:

状态:暴力法思路很直接,可以写个大概,但是出现了两处错误。

        一处是,我没有考虑到,在删除元素的过程中,我们的新数组的长度是在跟着变的!所以,我不能靠着“经验”,写 i < nums.size(),而是要用一个新变量size来记录新数组的长度,并且在两层循环的条件里都用size来做判断。

        另一处是,我没有在删除元素后,考虑到 i 的值也要跟着递减,如果我不这样处理,我会漏掉要处理的元素,相当于我跳过了一个元素。

代码:

class Solution {
public:
    // 暴力法
    int removeElement(vector<int>& nums, int 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]; //因为要删除nums[j-1],所以它就是第一个要被覆盖的。
                }
            i--; // 很容易漏掉,因为元素被删除了,所以i也应该减少一位
            size--; 
            }
        }
        return size;
    }
};

双指针法:

状态:我知道我大体思路了,也把循环写出来了。但是收到暴力法的影响,我又开始做什么fast--,size--的操作。但其实,因为这道题,我们没有用到后面的元素要向前移位的操作,所以,不要多想这些,fast就只是遍历一遍原数组,slow才用来修改,而且新数组的长度就正好等于slow。返回即可。

代码:

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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值