代码随想录算法训练营第一天|LeetCode 27 34 35 69 367 704

        金融本转计算机研0,掌握的比较好的是C++,由于未来三年使用更多的是python,就用python,试图不学语法就来刷题,不懂的边查。本博客不打算用写题解的方式,相信官方题解已经足够满足大伙的需求,更多用来记录心得和一些触动我的细节,希望可以得到带佬们的指导!

今天完成数组章节的

704 二分查找

        35 搜索插入位置

        34 在排序数组中查找元素的第一个和最后一个位置

        69 x的平方根

        367 有效的完全平方数

27 移除元素

1、二分法中当区间为左闭右闭[left,right]时,while left <= right的=必不可少,因为left == right是有意义的,比如输入nums=[5],target=5,对应的输出非空

class Solution(object):
    def search(self, nums, target): # 左闭右闭写法
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return -1

if __name__ == '__main__':
    s = Solution()
    array = list([-1, 0, 3, 5, 9, 12])
    target = 2
    print(s.search(array, target))

2、掌握了一种左闭右开[left,right)的方法,即while left < right对应else: right = mid

class Solution(object):

    def search(self, nums, target): # 左闭右开写法
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left = 0
        right = len(nums)
        while left < right:
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1
            else:
                right = mid
        return -1


if __name__ == '__main__':
    s = Solution()
    print(s.search(nums=[-1, 0, 3, 5, 9, 12], target=2))

3、在34 在排序数组中查找元素的第一个和最后一个位置中,掌握了一种在有序数列中(当然二分就是有序数组,前面忘写:)寻找相同元素的左边界和右边界的方法。

找边界问题可以从我们的35 搜索插入位置开始想,找得到nums[mid] == target,直接返回,找不到返回第一个比它大的元素或返回比他小的第一个元素再加1,我们关注找不到的情况,针对这几行

while left <= right:
    mid = (left + right) // 2
    if nums[mid] == target:
        return/break
    elif nums[mid] < target:
        left = mid + 1
    else:
        right = mid - 1

以往一直找不到到底取的是left还是right还是left±1还是right±1,那么下面一劳永逸解决掉

最直观的理解是,结局总是停止在right == left - 1,那么之所以会以这种方式跳出循环,要么target比[nums[left], nums[right]]小,那最后一步就是right = mid - 1(称之为左跳出);要么target比[nums[left], nums[right]]大,那最后一步就是left = mid + 1(称之为右跳出);

若是右跳出,则上一步是left == mid == right,且nums[mid] == nums[left] < target,那么right就是跳出循环前最后一个小于target的元素;所以元素应该放在right+1也就是left处

若是左跳出,则上一步是left == mid == right或right-1,且nums[mid] == nums[left] > target,那么left就是跳出循环前最后一个大于target的元素;元素应该放在left处,然后把从left开始的元素一律向后移

要注意,我们位于[left,right]区间时,任何超出这个区间的我们都可认为是看不见的,去访问区间外的数据都是僭越!这就是为什么我们在右跳出时,我们要强调right,从而计算right+1(虽然right+1==left)而不是直接说应该放在left,因为此时left超出原有区间,访问left可能导致越界(虽然不会去访问它);这就是为什么我们在左跳出时,要强调left,而不是强调right,再用right+1(虽然right+1==left),因为此时right此时超出原有区间,访问nums[right]可能导致越界(虽然我们不会访问它)。

ok,接下来让我们开始找边界

首先找右边界,首先是当我们遇到nums[mid]==target的时候,continue,我们可以直接在判断语句上做手脚,让left尽可能向右移动,于是if nums[mid] <= target: left = mid + 1,接下来是跳出,不管是左跳出还是右跳出,上面说到left是第一个比他大的,那么right == left - 1就是最后一个小于等于他的,返回一个right(此时是僭越态,以为right只会减小,需要判断right是否大于等于0,其实都判断了也不会有问题)

接下来找左边界,同样地,遇到nums[mid]==target的时候continue,直接在判断语句上做手脚,让right尽可能向左移动,于是if nums[mid] >= target: right = mid - 1,接下来是跳出,不管是左跳出还是右跳出,上面说到right是第一个小于他的,那么right + 1 == left就是最后一个小于等于他的,返回一个left(此时是僭越态,因为left只会增大,需要判断left是否小于等于len - 1,其实都判断了也不会有问题)

这道题目的第一种方法是随便找到任何位置的这个元素,然后向左右扩展找边界,复杂度达到O(n),我想这是最直观最暴力的(当然也有更暴力的直接整个开始搜,这就不在我们的高雅范围内了哈:);第二种方法是两次二分分别找到两个边界,找两个边界也就是我上面提到的这堆玩意儿

方法一

class Solution(object):
    def searchRange(self, nums, target):  # 寻找到元素后左右找边界:复杂度On
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        loc = -1
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                loc = mid
                break
            elif nums[mid] < target:
                left = mid + 1
            else:
                right = mid - 1

        loc_s = loc_e = -1
        if loc != -1:
            loc_s = loc_e = loc
            while loc_s >= 0 and nums[loc_s] == target:
                loc_s -= 1
            loc_s += 1
            while loc_e < len(nums) and nums[loc_e] == target:
                loc_e += 1
            loc_e -= 1
        return loc_s, loc_e


if __name__ == '__main__':
    s = Solution()
    loc_s, loc_e = s.searchRange(nums = [], target = 0)
    print(loc_s, loc_e)

方法二

class Solution(object):
    def searchRange(self, nums, target):
        loc_s = loc_e = -1
        # 找右边界
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] <= target:
                left = mid + 1
            else:
                right = mid - 1
        loc_e = right if 0 <= right < len(nums) and nums[right] == target else -1
        # 找左边界
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] >= target:
                right = mid - 1
            else:
                left = mid + 1
        loc_s = left if 0 <= left < len(nums) and nums[left] == target else -1

        return loc_s, loc_e


if __name__ == '__main__':
    s = Solution()
    loc_s, loc_e = s.searchRange(nums = [], target = 0)
    print(loc_s, loc_e)

4、27 移除元素我采用的是双指针方法,准确的是存储两个指针间的差距以及其中一个指针的位置来实现双指针的方法,没啥的,浅浅一贴代码

class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        num_del = 0
        for i in range(len(nums)):
            if nums[i] == val:
                num_del += 1
            else:
                nums[i - num_del] = nums[i]

        return len(nums) - num_del

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

余额充值