(二刷)代码随想录算法训练营day1 | 数组理论基础,704 二分查找,27 移除元素,以及相关题目

算法性能分析:

  • 关于时间复杂度和空间复杂度的分析(通用)以及递归算法的复杂度分析

理论基础

  • 数组是存放在连续内存空间上的相同型数据的集合。

  • 因此,增删元素时需要移动后面的元素

704 二分查找

  • index是变量,要放到while内。此处出错,导致index不能动态更新继续查找。

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

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

35 搜索插入位置

  • 实际上与704一样

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        l = 0
        r = len(nums)-1

        while l <= r:
            midIndex = l + (r-l)//2
            if nums[midIndex] > target:
                r = midIndex-1
            elif nums[midIndex] < target:
                l = midIndex+1
            else:
                return midIndex
        return l

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

  • 利用二分法找到target对应的index之后,左右滑动找更小或更大的index

  • 为什么需要判断 left-1>=0?(判断right+1<len(nums)也一样)

    • 因为需要判断的是nums[left-1] == target,那么首先要保证 left-1不能超过左边界,也就是0。
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        index = self.binarySearch(nums, target)
        if index == -1:
            return [-1, -1]

        left = right = index
        while left-1>=0 and nums[left-1] == target:
            left -= 1
        while right+1 < len(nums) and nums[right+1] == target:
            right += 1
        return [left, right]


    def binarySearch(self, nums, target):
        l = 0 
        r = len(nums)-1

        while l <= r:
            midIndex = l + (r-l)//2
            if nums[midIndex] > target:
                r = midIndex-1
            elif nums[midIndex] < target:
                l = midIndex+1
            else:
                return midIndex
        return -1

二刷时写法:

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        if len(nums) < 1:
            return [-1, -1]
        
        found = self.bnarySearch(nums, target)
        if found == -1:
            return [-1, -1]

        l = r = found
        while True:
            while l > 0 and nums[l] == nums[l - 1]:
                l -= 1
            while r < len(nums) - 1 and nums[r] == nums[r + 1]:
                r += 1
            return [l, r]



    def bnarySearch(self, nums, target):
        l = 0
        r = len(nums) - 1

        while l <= r:
            mid = l + (r - l) // 2
            if nums[mid] < target:
                l = mid + 1
            elif nums[mid] > target:
                r = mid - 1
            else:
                return mid
        return -1

69.x 的平方根

自己写的(代码1)问题:超时

  • 没有灵活运用二分法,想着将问题尽量构建成最基本的二分法的状态,但是实际上不必要完全一样,重点是逻辑!
  • 对应代码:没必要创建一个数组
class Solution:
    def mySqrt(self, x: int) -> int:
        nums = [i for i in range(x + 1)]
        l = 0
        r = len(nums) - 1

        while l <= r:
            mid = l + (r - l) // 2
            if nums[mid]*nums[mid] > x:
                r = mid - 1
            elif nums[mid]*nums[mid] < x:
                l = mid + 1
            else:
                return nums[mid]
        return nums[l - 1]


#本地运行可以
if __name__ == '__main__':
    x = 0
    func = Solution()
    print(func.mySqrt(x))

基于二分法逻辑,写出如下代码:

class Solution:
    def mySqrt(self, x: int) -> int:
        l = 0
        r = x

        while l <= r:
            mid = l + (r - l) // 2
            if mid * mid > x:
                r = mid - 1
            elif mid * mid <= x and (mid + 1) * (mid + 1) > x:
                return mid
            else:
                l = mid + 1


# if __name__ == '__main__':
#     x = 0
#     func = Solution()
#     print(func.mySqrt(x))

367.有效的完全平方数

与#69一样

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        l = 0
        r = num

        while l <= r:
            mid = l + (r - l) // 2
            if mid * mid > num:
                r = mid - 1
            elif mid * mid < num:
                l = mid + 1
            else:
                return True
        
        return False

27 移除元素 (双指针)

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

        return slow

26.删除排序数组中的重复项

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        
        slow = fast = 1
        
        while slow < len(nums) and nums[slow] != nums[slow-1]:
            slow += 1
            fast +=1
            
        while fast < len(nums):
            if nums[fast] != nums[slow-1]:
                nums[slow], nums[fast] = nums[fast], nums[slow]
                slow += 1
                
            fast += 1
            
        return slow
  • 代码1使用了swap(nums[slow], nums[fast] = nums[fast], nums[slow]),但是需要判断 if nums[fast] != nums[slow-1]:, 这条语句并不直观。
  • 若将判断语句改为 if nums[fast] != nums[fast - 1]:,那么就不能使用swap,只能进行赋值操作(nums[slow] = numsfast),如代码2(更倾向这种写法)
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        s = 1
        f = 1

        while s < len(nums) and nums[s] != nums[s - 1]:
            s += 1
            f += 1

        while f < len(nums):
            if nums[f] != nums[f - 1]:
                nums[s] = nums[f]
                s += 1
            f += 1
        return s

283.移动零

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        s = f = 0
        
        while f < len(nums):
            if nums[f] != 0:
                nums[s], nums[f] = nums[f], nums[s]
                s += 1
            f += 1
        return nums

844.比较含退格的字符串

class Solution:
    def backspaceCompare(self, s: str, t: str) -> bool:
        stack1 = []
        stack2 = []

        for char in s:
            if stack1 and char == '#':
                stack1.pop()
            else:
                if char != '#':
                    stack1.append(char)
        print(stack1)
        
        for char in t:
            if stack2 and char == '#':
                stack2.pop()
            else:
                if char != '#':
                    stack2.append(char)
        print(stack2)
        
        return stack1 == stack2


if __name__ == '__main__':
    s = "y#fo##f"
    t = "y#f#o##f"
    func = Solution()
    print(func.backspaceCompare(s, t))

Follow up: Can you solve it in O(n) time and O(1) space?

A: try follow the comments of https://www.youtube.com/watch?v=96-d8ZPjHeE

977.有序数组的平方

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        ans = []
        l = 0
        r = len(nums) - 1

        while l <= r:
            if abs(nums[l]) > abs(nums[r]):
                ans.append(nums[l]**2)
                l += 1
            else:
                ans.append(nums[r]**2)
                r -= 1
        return ans[::-1]

小结:

  1. 用vscode刷leetcode:install leetcode extension之后,默认是连接到美版leetcode,想要用中国版本则需要切换一下,然后登录即可。

  2. 以#704为例来探究一下python,想要本地运行:

    • 首先leetcode核心代码模式下的代码不能直接给出结果,需要手动在 if __name__ == '__main__': 给出测试用例
    • 且需要先create an instance of the object of Solution, then use this instance to invoke the method search() (见代码1)
    • 如果想加入全局变量 __init__(self, nums, target), 那么就需要在create an instance of the object of Solution那里给出参数(见代码2)
class Solution:
    def search(self, nums, target) -> int:
        l = 0
        r = len(nums) - 1
        while l <= r:
            mid = l + (r - l) // 2
            if nums[mid] > target:
                r = mid - 1
            elif nums[mid] < target:
                l = mid + 1
            else:
                return mid
        return -1


if __name__ == '__main__':
    test = [-1,0,3,5,9,12]
    target = 9
    find = Solution() #need to create an instance first
    print(find.search(test, target))
class Solution:
    def __init__(self, nums, target) -> None:
        self.nums = nums
        self.target = target

    def search(self, nums, target) -> int:
        l = 0
        r = len(nums) - 1
        while l <= r:
            mid = l + (r - l) // 2
            if nums[mid] > target:
                r = mid - 1
            elif nums[mid] < target:
                l = mid + 1
            else:
                return mid
        return -1


if __name__ == '__main__':
    test = [-1,0,3,5,9,12]
    target = 9
    find = Solution(test, target) #need to create an instance first
    print(find.search(test, target))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第二十二天的算法训练营主要涵盖了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题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二天的算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值