算法训练Day 1

LeetCode 704.二分查找

曾在快手一面时遇到过,当时下意识用递归做的,事后想一想感觉迭代更好,代码简洁好调试

题目链接:704. 二分查找

思路:因为给定数组是有序的,思路就是中间值小了就右移左边界,中间值大了就左移右边界,python用的是左闭右闭的写法。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        left, right = 0, n-1
        # 注意这里是<=,<的话会忽略left==right的情况,因为是左闭右闭,所以left==right也需要进行判断
        while left <= right:
        	# 这个写法等价于(left+right)//2, 但可以避免(left+right)可能会内存溢出的情况
            mid = left + (right-left)//2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid+1
            else:
                right = mid-1
        return -1

时间复杂度: O ( l o g n ) O(log n) O(logn),空间复杂度: O ( 1 ) O(1) O(1)

go版本(左闭右开的写法):

func search(nums []int, target int) int {
    left := 0
    right := len(nums)
    for left<right{
        mid := left + (right-left)>>1
        if nums[mid] == target{
            return mid
        } else if nums[mid] < target {
            left = mid + 1
        } else {
            right = mid
        }
    }
    return -1
}

感觉go的代码结构比python好看,大括号yyds
————————分割线————————
20230505:这里详细记录一下左闭右开和左闭右闭的区别和在代码上的体现。

左闭右开,字面意思是取值的时候能取到left索引所在的值,但取不到right索引所在的值。这里思考一下,能取到意味着取值需要在索引范围内,并且判断的时候需要考虑在内;反之,取不到的值,其初始定义不应该在索引范围内,因为定义在索引范围内却又不取值的话,就会出现bug,同时判断的时候也不应该考虑在内。

左闭右闭,即left索引和right索引的值都能取到,那两个值如上文所述,初始定义都应该在索引范围内,且判断的时候都需要考虑在内。

初始定义这个事情好理解。判断情况举个例子,比如左闭右开的情况,在大循环判断的时候,因为right取不到,所以判断的时候就不应该考虑在内,那判断逻辑就应该写为 l e f t < r i g h t left<right left<right;同时,因为右开的情况下,right在更改自己值的时候,也不应该“踏足”接下来要判断的区间的索引范围以内,所以是 r i g h t = m i d right=mid right=mid 而不能是 r i g h t = m i d − 1 right=mid-1 right=mid1
 

LeetCode 27. 移除元素

题目链接:27.移除元素

思路:题目需要 “原地移除”,“不要使用额外的数组空间”,看到这些字眼首先想到的就是双指针。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        slow = 0
        for _, v in enumerate(nums):
            if v != val:
                nums[slow] = v
                slow += 1

        return slow 

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( 1 ) O(1) O(1)

go版本:

func removeElement(nums []int, val int) int {
    left, right := 0, 0
    for right <= len(nums)-1 {
        if nums[right]!=val {
            nums[left] = nums[right]
            left++
        }
        right++
    }
    return left
}

————————分割线————————
20230505:right指针正常的顺序遍历整个数组,left指针意味着有多少个跟val不一样的值。left个与val不相同的值就组成了新数组的长度left。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值