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
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)