Leetcode跟着饲养员按数据结构分题型刷题(Python施工中)

b站@爱学习饲养员
(按视频学习刷题的过程记录,不完全是按照up主的思路,有时候会参考热门的题解)

复杂度

  • 时间复杂度
    O(1) < O(logN) (二分查找) < O(N) < O(NlogN) < O(N^2) < O(2^n) < O(n!)
    (注意logN的底可以忽略,阿婆主视频里有证明)

下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择:

n≤30 => 指数级别, dfs+剪枝,状态压缩dp
n≤10^2 => O(n^3),floyd,dp
n≤1000 => O(n2),O(n^2logn),dp,二分
n≤10^4 => O(n∗n),块状链表
n≤10^5 => O(nlogn),各种sort,线段树、树状数组、set/map、heap、dijkstra+heap、spfa、求凸包、求半平面交、二分
n≤10^6 => O(n), 以及常数较小的 O(nlogn)算法, hash、双指针扫描、kmp、AC自动机,常数比较小的 O(nlogn)O(nlogn) 的做法:sort、树状数组、heap、dijkstra、spfa
n≤10^7 => O(n),双指针扫描、kmp、AC自动机、线性筛素数
n≤10^9 => O(n√)O(n),判断质数
n≤10^18 => O(logn),最大公约数
作者:可乐学算法
链接:https://leetcode-cn.com/circle/article/h7DRAr/

  • 空间复杂度
    O(1) < O(N) < O(N^2)
    常量看其与输入值得关系
    递归要考虑递归栈
    (有时候会用空间换时间)

各种数据结构的比较

在这里插入图片描述

各种数据结构的常用操作

在这里插入图片描述

力扣练习题-数据结构

数组

  • LC485
class Solution:
    def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
        if nums is None or len(nums) == 0:
            return 0

        count = 0
        result = 0
        for i in range(len(nums)):
            if nums[i] == 1:
                count += 1
                # result = max([result, count])
                if result < count:
                    result = count
            else:
                count = 0
        return result
  • LC283
class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n = len(nums)
        l = 0
        for r in range(n):
            if nums[r] != 0:
                nums[l] = nums[r]
                l += 1
        for i in range(l, n):
            nums[i] = 0
  • LC27
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # # 双指针
        # l = 0       
        # for r in range(len(nums)):
        #     if nums[r] != val:
        #         nums[l] = nums[r]
        #         l += 1
        # return l                


        # 双指针优化
        l = 0
        r = len(nums) - 1

        while(l<=r):
            if nums[l] == val:
                nums[l] = nums[r]
                r -= 1
            else:
                l += 1
        return l

在这里插入图片描述
??不知道为啥双指针优化的性能没有前面好

链表

  • LC203
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
        dummy = ListNode(0)
        dummy.next = head
        prehead = dummy
        while head:
            if head.val == val:
                prehead.next = head.next
            else:
                prehead = head
            head = head.next
        return dummy.next           
  • LC206

饲养员的思路不太好理解,建议参考老汤的迭代求解思路

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
# 饲养员版本
# class Solution:
#     def reverseList(self, head: ListNode) -> ListNode:
#         dummy = ListNode(0, head)
#         while head and head.next:
#             hNext = head.next
#             dNext = dummy.next

#             dummy.next = hNext
#             head.next = hNext.next
#             hNext.next = dNext
#         return dummy.next

# 老杨迭代求解
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        prev = None
        while head:
            temp = head.next
            head.next = prev
            prev = head
            head = temp
        return prev

# # 老杨递归求解
# class Solution:
#     def reverseList(self, head: ListNode) -> ListNode:
#         if head is None or head.next is None:
#             return head
        
#         p = self.reverseList(head.next)
#         head.next.next = head
#         head = head.next
#         return p

队列

  • LC933
class RecentCounter:

    def __init__(self):
        self.queue = deque()

    def ping(self, t: int) -> int:
        self.queue.append(t)
        while len(self.queue) > 0 and t - self.queue[0] > 3000:
            self.queue.popleft()
        return len(self.queue)

# Your RecentCounter object will be instantiated and called as such:
# obj = RecentCounter()
# param_1 = obj.ping(t)

  • LC20
class Solution:
    def isValid(self, s: str) -> bool:
        if len(s) == 0 or len(s) == 1:
            return False
        
        stack = []
        for i in s:
            if i == '(' or i == '{' or i == '[':
                stack.append(i)
            else:
                if len(stack) == 0:
                    return False
                    
                if stack[-1] == '(' and i == ')':
                    stack.pop()
                elif stack[-1] == '{' and i == '}':
                    stack.pop()
                elif stack[-1] == '[' and i == ']':
                    stack.pop()
                else:
                    return False
        return True if len(stack) == 0 else False
    

哈希表

  • LC217
class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        hashmap = {}
        for i in nums:
            if i in hashmap:
                hashmap[i] += 1
                if hashmap[i] >= 2:
                    return True
            else:
                hashmap[i] = 1

        return False
  • LC389
class Solution:
    def findTheDifference(self, s: str, t: str) -> str:
        if len(s) == 0:
            return t
        
        # 字典
        # hashmap = {}
        # for i in s:
        #     if i not in hashmap:
        #         hashmap[i] = 1
        #     else:
        #         hashmap[i] += 1

        # for i in t:
        #     if i in hashmap:
        #         hashmap[i] += -1
        #     else:
        #         return i
        
        # for key, val in hashmap.items():
        #     if val != 0:
        #         return key
        
        # 数组
        hashmap = [0] * 26
        for i in s:
            hashmap[ord(i)-97] += 1
        for i in t:
            hashmap[ord(i)-97] += -1
        for i in range(26):
            if hashmap[i] != 0:
                return chr(i+97)

  • LC496

用了栈+哈希表

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        if len(nums1) == 0 or len(nums2) == 0:
            return []

        stack = []
        hashmap = {}

        stack.append(nums2[0])
        for i in range(1, len(nums2)):
            while len(stack) != 0 and stack[-1] < nums2[i]:
                hashmap[stack[-1]] = nums2[i]
                stack.pop()
            stack.append(nums2[i])
                
        for i in stack:
            hashmap[i] = -1
        
        return [hashmap[i] for i in nums1]

集合

  • LC217
class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        numsSet = set(nums)
        if len(numsSet) < len(nums):
            return True
        else:
            return False

比用哈希表快

  • LC705
class MyHashSet:

    def __init__(self):
        self.hashSet = []

    def add(self, key: int) -> None:
        if key not in self.hashSet:
            self.hashSet.append(key)


    def remove(self, key: int) -> None:
        if key in self.hashSet:
            self.hashSet.remove(key)

    def contains(self, key: int) -> bool:
        if key in self.hashSet:
            return True
        else:
            return False


# Your MyHashSet object will be instantiated and called as such:
# obj = MyHashSet()
# obj.add(key)
# obj.remove(key)
# param_3 = obj.contains(key)
  • 练习题 LC144
  • 练习题 LC94
  • 练习题 LC145

  • LC215
class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        heap = []
        heapq.heapify(heap)

        for i in nums:
            heapq.heappush(heap, -i)
        
        while k > 1:
            heapq.heappop(heap)
            k -= 1
        
        return -heap[0]

要记得heapq构造的是最小堆

  • LC692
class Solution:
    def topKFrequent(self, words: List[str], k: int) -> List[str]:
        heap = []
        heapq.heapify(heap)
        dic = {}

        for i in words:
            if i not in dic:
                dic[i] = 0
            dic[i] += 1
        
        for key, value in dic.items():
            heapq.heappush(heap, Node(key, value))
            if len(heap) > k:
                heapq.heappop(heap)
        
        res = []
        while len(heap) > 0:
            temp = heapq.heappop(heap)
            res.append(temp.key)
        
        res.reverse()

        return res
                

class Node:
    def __init__(self, key, value):
        self.key = key
        self.value = value

    def __lt__(self, nxt):# True: self被删除
        if self.value > nxt.value: # value大的留下
            return False
        elif self.value < nxt.value:
            return True
        else:
            return self.key > nxt.key # 字母顺序靠前的留下
        # return self.key > nxt.key if self.value == nxt.value else self.value < nxt.value

力扣练习题-算法

双指针

  • LC141
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        if head == None:
            return False
        s = head
        f = head

        while f != None and f.next != None:
            s = s.next
            f = f.next.next
            if s == f:
                return True
        return False
  • LC881
class Solution:
    def numRescueBoats(self, people: List[int], limit: int) -> int:
        if people == None or len(people) == 0:
            return 0
        
        people.sort()

        i, j = 0, len(people) - 1
        boals = 0
        while i <= j:
            if people[i] + people[j] > limit:
                j -= 1
                boals += 1
            else:
                i += 1
                j -= 1
                boals += 1
        return boals

二分查找

  • LC704
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        l, r = 0, len(nums) - 1
        while l < r:
            mid = (l + r) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                l = mid + 1
            elif nums[mid] > target:
                r = mid - 1
        return l if nums[l] == target else -1
  • LC35
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        l, r = 0, len(nums)
        while l < r:
            mid = (l+r) // 2
            if target == nums[mid]:
                return mid
            elif target > nums[mid]:
                l = mid + 1
            elif target < nums[mid]:
                r = mid
        return l
  • LC162
class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        if len(nums) == 0 or nums is None:
            return -1
        l, r = 0, len(nums) - 1

        while l < r:
            mid = l + (r - l) // 2
            if nums[mid] <= nums[mid + 1]:
                l = mid + 1
            else:
                r = mid
        return l
  • LC74
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        rows = len(matrix)
        cols = len(matrix[0])

        l, r = 0, rows * cols - 1
        while l < r:
            mid = l + (r - l) // 2
            val = matrix[mid//cols][mid%cols]
            if val == target:
                return True
            elif val < target:
                l = mid + 1
            else:
                r = mid - 1
        return True if matrix[l//cols][l%cols] == target else False

滑动窗口

  • LC209
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        res = len(nums) + 1
        total, i, j = 0, 0, 0
        while j < len(nums):
            total += nums[j]
            j += 1
            while total >= target:
                res = min(res, j - i)
                total -= nums[i]
                i += 1
        return 0 if res == len(nums) + 1 else res
  • LC1456
class Solution:
    def maxVowels(self, s: str, k: int) -> int:
        target = 'aeiou'
        count = 0
        res = 0
        for i in range(k):
            if s[i] in target:
                count += 1
        res = max(res, count)
        
        # i = 0
        # while (i + k) < len(s):
        #     if s[i] in target:
        #         count -= 1
        #     if s[i+k] in target:
        #         count += 1
        #     i += 1
        #     res = max(res, count)

        for i in range(k, len(s)):
            if s[i-k] in target:
                count -= 1
            if s[i] in target:
                count += 1
            res = max(res, count)
        return res

递归

-LC509

class Solution(object):
    def fib(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n < 2:
            return 0 if n == 0 else 1
        res = self.fib(n - 1) + self.fib(n - 2)
        return res

(最优题解是动态规划,因为f(n-1),f(n-2)在递归中重复被运算,其实可以存下来一些值的)

class Solution:
    def fib(self, n: int) -> int:
        if n < 2:
            return n
        p, q, r = 0, 1, 1
        for i in range(2, n):
            p, q = q, r
            r = p + q
        return r 

  • LC206
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        # 双指针
        l, r = 0, len(s) - 1
        while l <= r:
            s[l], s[r] = s[r], s[l]
            l += 1
            r -= 1

# 饲养员骚骚的递归
# class Solution:
#     def reverseString(self, s: List[str]) -> None:
#         """
#         Do not return anything, modify s in-place instead.
#         """
#         self.reverse(s, 0, len(s)-1)

#     def reverse(self, s, l, r):
#         if l >= r:
#             return
#         self.reverse(s, l+1, r-1)
#         s[l], s[r] = s[r], s[l]

分治法

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        return self.getMajority(nums, 0, len(nums)-1)
    
    def getMajority(self, nums, l, r):
        mid = l + (r - l) // 2
        if l == r:
            return nums[l]
        lm = self.getMajority(nums, l, mid)
        rm = self.getMajority(nums, mid+1, r)
        if lm == rm:
            return lm
        else:
            lCount, rCount = 0, 0
            for i in nums[l:r+1]: # 要包括nums[r]这个值
                if i == lm:
                    lCount += 1
                elif i == rm:
                    rCount += 1
            return lm if lCount > rCount else rm
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        return self.getMaxSums(nums, 0, len(nums)-1)

    def getMaxSums(self, nums, left, right):
        if left == right:
            return nums[left]
        mid = left + (right - left) // 2
        leftMax = self.getMaxSums(nums, left, mid)
        rightMax = self.getMaxSums(nums, mid+1, right)
        crossMax = self.getCrossSums(nums, left, right)
        return max(leftMax, rightMax, crossMax)

    def getCrossSums(self, nums, left, right):
        mid = left + (right - left) // 2
        leftSum, leftMax = nums[mid], nums[mid]
        for i in range(mid-1, left-1, -1):
            leftSum += nums[i]
            leftMax = max(leftSum, leftMax)
        rightSum, rightMax = nums[mid+1], nums[mid+1]
        for i in range(mid+2, right+1):
            rightSum += nums[i]
            rightMax = max(rightSum, rightMax)
        return leftMax + rightMax
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:

         def backTracking(n, res, left, right, str):
            if right > left:
                 return
            if left == right == n:
                res.append(str)
            if left < n:
                backTracking(n, res, left+1, right, str+'(')
            if right < left:
                backTracking(n, res, left, right+1, str+')')

         res = []
         backTracking(n, res, 0, 0, "")
         return res
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值