代码随想录算法训练营第一天 | 704. Binary Search & 27. Remove Element

文章讲述了在代码随想录算法训练营的第一天,作者详细介绍了二分查找的实现(左闭右闭和左闭右开版本)以及移除元素(暴力解法和快慢指针解法)的两种方法。作者强调了二分查找的熟练掌握和双指针策略的运用提升。
摘要由CSDN通过智能技术生成

代码随想录算法训练营第一天 | 704. Binary Search & 27. Remove Element

07/03/2024补充:第一轮打卡完全没跟上节奏,光荣加入新的一期打卡,重新开始

704. Binary Search

题目链接:704. Binary Search
题目描述:

Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise, return -1.
You must write an algorithm with O(log n) runtime complexity.

文章讲解:代码随想录:二分查找
视频讲解:手撕二分查找
读完题思路:

因为这道题真的已经刷过很多遍了,可以说是信手拈来了。真的只要记住卡尔学长说的循环不变量,就能轻松的写出来左闭右开[1,1)和左闭右闭[1,1]的两种代码。

左闭右闭写法:

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        #左闭右闭
        left, right = 0, len(nums)-1

        while left <= right:
            mid = (left + right) // 2

            if nums[mid] == target:
                return mid
            if nums[mid] > target:
                right = mid - 1
            else:
                left = mid + 1
        return -1

左闭右开写法:

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        #左闭右开
        left, right = 0, len(nums)

        while left < right:
            mid = (left + right) // 2

            if nums[mid] == target:
                return mid
            if nums[mid] > target:
                right = mid
            else:
                left = mid + 1
        return -1

最近也在练习C++,所以这次打卡正好加入C++的版本:

左闭右闭:

class Solution {
public:
    // 左闭右闭
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;

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

左闭右开:

class Solution {
public:
    // 左闭右开
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size();

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

之前没注意到的是防止溢出的mid计算!太细了5555

35. Search Insert Position

第二次刷加入的补充题
题目链接:35. Search Insert Position
题目描述:

Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You must write an algorithm with O(log n) runtime complexity.

文章讲解:代码随想录:35.搜索插入位置
读完题思路:刚读完觉得好简单,直接二分查找只要改一下最后的return就好,但最终的return一下子突然又想不明白了。看了讲解后才意识到还是要继续从循环不变量去考虑。
这题就只用了C++写了一下。(下面copy的代码随想录的🐎)

暴力解法:

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        for (int i = 0; i < nums.size(); i++) {
        // 分别处理如下三种情况
        // 目标值在数组所有元素之前
        // 目标值等于数组中某一个元素
        // 目标值插入数组中的位置
            if (nums[i] >= target) { // 一旦发现大于或者等于target的num[i],那么i就是我们要的结果
                return i;
            }
        }
        // 目标值在数组所有元素之后的情况
        return nums.size(); // 如果target是最大的,或者 nums为空,则返回nums的长度
    }
};

二分法(左闭右闭):

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int n = nums.size();
        int left = 0;
        int right = n - 1; // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) { // 当left==right,区间[left, right]依然有效
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                return middle;
            }
        }
        // 分别处理如下四种情况
        // 目标值在数组所有元素之前  [0, -1]
        // 目标值等于数组中某一个元素  return middle;
        // 目标值插入数组中的位置 [left, right],return  right + 1
        // 目标值在数组所有元素之后的情况 [left, right], 因为是右闭区间,所以 return right + 1
        return right + 1;
    }
};

34. Find First and Last Position of Element in Sorted Array

题目链接:34. Find First and Last Position of Element in Sorted Array
文章讲解:代码随想录:34. 在排序数组中查找元素的第一个和最后一个位置
这题花了我好久,有点写不动讲解了。。。主要follow这个文章讲解

27. Remove Element

题目链接:27. Remove Element
题目描述:

Given an integer array nums and an integer val, remove all occurrences of val in nums in-place. The order of the elements may be changed. Then return the number of elements in nums which are not equal to val.
Consider the number of elements in nums which are not equal to val be k, to get accepted, you need to do the following things:

  • Change the array nums such that the first k elements of nums contain the elements which are not equal to val. The remaining elements of nums are not important as well as the size of nums.
  • Return k.

文章讲解:代码随想录:移除元素
视频讲解:数组中移除元素并不容易!
读完题思路:

这道题之前也是刷到过的,印象里是要用双指针。但令我惊讶的是一开始写暴力解法居然写不出来,知道大概思路但是implement有问题,还研究了半天。。。

暴力解法:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 暴力解法
        start, end = 0, len(nums)
        while start < end:
            if nums[start] == val:
                for j in range(start+1, len(nums)):
                    nums[j-1] = nums[j]
                start -= 1
                end -= 1
            start += 1
        
        return end

快慢指针解法:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 快慢指针
        slow, fast = 0, 0
        while fast < len(nums): 
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        
        return slow


这题新用C++又写了一遍:

class Solution {
    // Time Complexity: O(n)
    // Space Complexity: O(1)
public:
    int removeElement(vector<int>& nums, int val) {
        int slow = 0;
        int fast = 0;

        for (fast; fast < nums.size(); fast++) {
            if (nums[fast] != val) {
                nums[slow] = nums[fast];
                slow ++;
            }
        }
        return slow;
    }
};

今日收获与总结

Day1 耗时大概1.5h,但是没有做补充衍生的题,只做了要求的两道,再加上都是Easy之前也刷过,所以今天耗时比较短。最近学校里事情比较多,希望之后也能跟上进度继续打卡下去。
今天算是第一次写博客,还是挺好玩的,希望也能养成这个习惯。
感觉二分查找已经完全没有问题了,双指针的运用可能还是需要加强,判断什么时候运用快慢指针,什么时候用左右指针。

Updated:
第二次刷这一课,做了补充题34&35。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值