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

 LeetCode 704.二分查找

题目链接:

LeetCode 704. 二分查找

看到这道题的题目就想到了在之前学习中编过的一个“猜数游戏”。其中就运用到了二分法的思想。后来再看了代码随想录上的思路解析觉得心里就有谱了。

文章链接:

https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html

这道题主要需要的就是坚定一个区间原则,即为左闭右闭,左闭右开……,了解了这两个其他的区间也会理解。从一开始就要选定一种去写代码,不能再改变;

左闭右闭

C++代码如下

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

此种情况下right定义时应该等于 nums.size() - 1。因为右边是闭区间,所以要让nums[right]是有意义的值。while结束条件是left <= right,也是左闭右闭的一个重要特征。然后因为找的是相对的中间值且防止溢出,middle就等于left + ((right - left)/2)。后面的思想就和前面类似了,因为left和right都是有意义的,所以赋值时是middle + 1或者middle - 1。最后就是找到返回middle,没找到返回-1。

左闭右开

代码如下

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

此种情况下right就直接等于nums.size()。因为右边是开区间,所以right可以指向没意义的位置。while的结束条件变为right < left即为左闭右开的特征。因为右边为开区间,所以给right赋值时就直接将middle赋给right。其他思路和左闭右闭类似。

还有两道拓展题目,有一道较简单,另一道

题目链接:

LeetCode 35. 搜索插入位置

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

代码比较厚,写的时候可能多了很多不必要的if语句判断。

这道题我想到用二分法,但是有一个需要注意的条件就是最后循环结束后的两个if判断,这是必要的,否则不一定能返回正确的值,因为是有序数组,所以会有这样的判断。

LeetCode 27. 移除元素

题目链接:

LeetCode 27. 移除元素

看完这道题第一时间想到的就是遍历到目标值的位置,然后一一将后面的元素覆盖过来。也就是暴力解法。但是看了代码随想录的思路后就悟了。

文章链接:

代码随想录

这道题的精髓就是双指针的用法,一前一后指针分别承载不同的功能。慢指针(slow):记录删除目标值后的新数组成员,快指针(fast):寻找目标值,并将其覆盖。

暴力解法

代码如下:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int left = 0, right = 0, size, j = 0;
        size = nums.size();
        for(left = 0; left < size; left ++) {
            if (nums[left] == val) {
                for(right = left; right < size - 1; right++) {
                    nums[right] = nums[right + 1];
                }
                left--;
                size--;
            }
        }
        return size;
    }
};

简单粗暴,两个for循环结束。

双指针法

代码如下:

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

巧妙运用两个指针来进行操作,减小了时间复杂度。

今日学习5小时收获

第一天真正意义上的进行刷题,拓宽了我再算法题上近乎空白的思维,脑中多了很多想法。熟练的掌握了有序数组二分法的使用。对于指针的双指针的用法更精进了一步。后面再遇到数组的题可能会优先考虑双指针。多多重复,百炼成钢。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值