代码随想录算法训练营第一天 | 704. 二分查找,27. 移除元素 [数组篇]

LeetCode 704. 二分查找

题目链接:704. 二分查找
文章讲解:代码随想录#704. 二分查找
视频讲解:手把手带你撕出正确的二分法

题目描述

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

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例2

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

思路

二分查找法的两个前提条件:有序数组,元素无重复
使用二分法之前,必须得搞明白边界问题,也就是区间问题。
平时遇到最多的两种区间:左闭右闭即[left, right],或者左闭右开即[left, right),※其他组合也可以解决问题
本题使用左闭右闭即[left, right],需要注意以下几点

  • 因为是闭区间,区间范围为[0, numsSize - 1],所以right的初值为numsSize - 1
  • 循环条件中left与right存在两者相等的情况,所以while中要使用<=
  • 当中间元素middle的值大于目标值target时,需要更改right变量,由于middle已经比较过了,所以right应该等于middle-1,left同理
    左闭右开可以参考代码随想录#704. 二分查找,强烈推荐!!!

参考代码

int search(int* nums, int numsSize, int target) {
    // 左闭右闭的区间[left, right]
    int middle;
    int left = 0;
    int right = numsSize - 1; // 因为是闭区间,所以整个区间为[0, numsSize-1]
    while (left <= right) { // 因为是左开右开区间,所以存在left=right的情况
        middle = left + (right - left) / 2;  // 防止两数相加溢出
        if (nums[middle] > target) {
            right = middle - 1;
        } else if (nums[middle] < target) {
            left = middle + 1;
        } else {
            return middle;
        }
    }
    return -1;
}

总结

  1. 一定要搞明白区间的定义,是左闭右闭,还是左闭右开,这决定后面代码的写法。
  2. 两数相加时注意越界、截位、位反转等情况,可以看看这篇文章《地址范围的边界值判断
  3. 在调整left/right时,一定要想明白到底是middle还是middle±1

LeetCode 27. 移除元素

题目链接:727. 移除元素
文章讲解:代码随想录#727. 移除元素
视频讲解:数组中移除元素并不容易!

题目描述

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

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例2

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,3,0,4]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

思路

本题的解法比较多,可以使用暴力解法,需要用两层for循环,外层for循环用来遍历整个数组,里面的for循环用来调整数组(因为在数组中不能直接删除数组中的元素),这样的话时间复杂比较大。
本题可以使用双指针法,这样只需要一层for循环,通过一个快指针和慢指针在一个for循环下完成移除元素,时间复杂度比较低。
想要使用快指针和慢指针,需要搞清楚它俩的含义。

  • 快指针遍历的是不包含目标元素的数组
  • 慢指针用来构造新数组

参考代码

int removeElement(int* nums, int numsSize, int val) {
    int fast, slow;

    slow = 0;
    for (fast = 0; fast < numsSize; fast++) {
        if (nums[fast] != val) { // 遍历目标元素以外的元素
            nums[slow++] = nums[fast]; // slow刚好跳过了目标元素
        }
    }
    return slow;
}

总结

  1. 时刻要明白每个指针的含义。
  2. for循环时在快指针会跑过目标元素时,慢指针会+1。
  3. 此题也可以在一个for循环下将目标元素标记成负数的办法,同时将元素个数减1,这样不使用双指针也可以实现,不过不推荐。
  • 15
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值