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

今日学习的文章链接和视频链接

704. 二分查找

第一想法

题目是二分查找,题干中体现了有序数组字样。
二分查找也是折半查找。
查找规则是:搜索过程从数组中间开始,如果target等于中间数字,搜索停止;如果target大于中间数字,则在右侧继续进行二分查找;如果target小于中间数字,则在左侧继续进行二分查找;如果在这个过程中数组为空,那么查找失败。
原始的想法是比较中间的数字,变量设置的也是数组中间位置的数字。

之后的想法

根据区间的不同,分为两种方法:
1、左闭右闭[left,right]
第一版错误代码:

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)
        while left <= right:
            middle = (left + right) // 2
            if nums[middle] > target:
                right = middle - 1
            elif nums[middle] < target:
                left = middle + 1
            elif nums[middle] == target:
                return middle
        return -1

报错提示:

IndexError: list index out of range
~~~~^^^^^^^^
if nums[middle] > target:
Line 7 in search (Solution.py)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ret = Solution().search(param_1, param_2)
Line 39 in _driver (Solution.py)
_driver()
Line 50 in (Solution.py)

错误原因:
这里是用的是左闭右闭的区间,也就是说数组是从0~len(nums)-1的,所以right初始化=len(nums)-1
正确代码:

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums) - 1
        while left <= right:
            middle = (left + right) // 2
            if nums[middle] > target:
                right = middle - 1
            elif nums[middle] < target:
                left = middle + 1
            elif nums[middle] == target:
                return middle
        return -1

2、左闭右开[left,right)
正确代码:

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)
        while left < right:
            middle = (left + right)// 2
            if nums[middle] > target:
                right = middle
            elif nums[middle] < target:
                left = middle + 1
            elif nums[middle] == target:
                return middle
        return -1

3、两种方法区别
最右侧的值在左闭右开的情况中本身就不包含。

自己实现过程中遇到的困难

从理解二分查找的规则到实现代码还是有一定距离的。
一看就会,一写就废。
虽然比较的是中间数字,但是变量应该设置的是中间数字的下标。

27. 移除元素

第一想法

题干强调原地删除并且输出最后结果就可以,把和目标值一致的数值赋值为空,最后for循环输出前面不为空的值的长度。

之后的想法

1、暴力解法
错误第一版:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        for i in range(len(nums)):
            if nums[i] == val:
                for j in range(i+1,len(nums)):
                    nums[j-1] = nums[j]
        return len(nums) 

输出结果为[2,2,3,3],正确结果是[2,2]
错误原因:
确实是把不等于val的有用的数值移到前面了,但是数组长度的输出并没有改变,还是原始长度。

错误第二版:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        lens = len(nums)
        for i in range(0,lens):
            if nums[i] == val:
                for j in range(i+1,lens):
                    nums[j-1] = nums[j]
                i = i - 1
                lens = lens - 1
        return lens         

输出结果为[2],正确结果是[2,2]
错误原因:
for range 遍历中的 i 是循环开始时就确定了的,在循环体中对其修改是无效的

正确版本:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i,size = 0,len(nums)
        while i < size:
            if nums[i] == val:
                for j in range(i+1,size):
                    nums[j-1] = nums[j]
                size = size - 1
                i = i - 1
            i = i + 1
        return size

2、双指针法
错误第一版

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        fast = 0
        slow = 0
        for i in range(len(nums)):
            if nums[i] != val:
                nums[slow] = nums[fast]
                slow += 1
        return slow

输出结果:输出[3,3]预期结果[2,2]
错误原因:
快慢指针中快的是一直向下找不等于val的元素,慢的是等遇到val就停止,然后fast将后续的元素覆盖到前面。所以一直向下走的不是i是fast。

正确版:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        fast = 0
        slow = 0
        for fast in range(len(nums)):
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
        return slow

自己实现过程中遇到的困难

全是困难呜呜呜呜

今日收获,记录一下自己的学习时长

1、二分查找不仅要满足有序,还要满足没有重复元素,因为一旦出现重复元素,在本题中元素的下标就不唯一了。
2、不要使用额外的数组空间,意思是必须仅使用 O(1) 额外空间并原地修改输入数组。
3、其实快慢指针还不是很了解,为什么这个题就可以用快慢指针,遇到其他的题想不起来这种做法。。。。

  • 16
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值