[Leetcode]Top 150
数组,字符串
最长公共前缀
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
n = len(strs)
length = len(strs[0])
for s in strs:
length = min(length,len(s))
res = ""
for i in range(length):
start = strs[0][i]
for j in range(n):
if strs[j][i] != start:
return res
res += start
return res
整数转罗马数字
class Solution:
def intToRoman(self, num: int) -> str:
digit_to_str = {
"1000":"M","900":"CM",
"500":"D","400":"CD",
"100":"C","90":"XC",
"50":"L","40":"XL",
"10":"X","9":"IX",
"5":"V","4":"IV",
"1":"I",
}
res = ""
while num>=1:
for key,value in digit_to_str.items():
while num >= int(key):
num-=int(key)
res+=value
return res
链表
旋转链表
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
# 首先判断头节点是不是为空,或者整个链表只有一个节点
if not head or not head.next:
return head
# 计算链表长度
cur = head
count = 1
while cur.next:
count += 1
cur = cur.next
# 首尾相连
cur.next = head
# 从count-k处断开连接
k = k % count
cur = head
for _ in range(count - k - 1):
cur = cur.next
res = cur.next
cur.next = None
return res
LRU 缓存
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
class LinkListNode:
def __init__(self, key=None, value=None):
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.length = 0
self.map = {}
self.head = LinkListNode()
self.tail = LinkListNode()
self.head.next = self.tail
self.tail.prev = self.head
def get(self, key: int) -> int:
if key in self.map:
self.removeNode(self.map[key])
self.addToTail(self.map[key])
return self.map[key].value
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.map:
self.map[key].value = value
self.removeNode(self.map[key])
self.addToTail(self.map[key])
else:
if self.length >= self.capacity:
self.removeFirst()
else:
self.length += 1
node = LinkListNode(key, value)
self.map[key] = node
self.addToTail(node)
def removeNode(self, node):
node.next.prev = node.prev
node.prev.next = node.next
def addToTail(self, node):
self.tail.prev.next = node
node.prev = self.tail.prev
node.next = self.tail
self.tail.prev = node
def removeFirst(self):
key = self.head.next.key
del self.map[key]
self.head.next.next.prev = self.head
self.head.next = self.head.next.next
两个链表的第一个公共节点
先将两个链表按照最后一个节点对齐,然后从对齐的起点开始同时遍历。
二叉树
翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
def reverse(root):
if not root or (not root.left and not root.right):
return
else:
root.left,root.right = root.right,root.left
reverse(root.left)
reverse(root.right)
reverse(root)
return root
二叉树的层序遍历
给你二叉树的根节点 root ,返回其节点值的层序遍历。 (即逐层地,从左到右访问所有节点)。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
queue = [root]
res = []
while queue:
levelSize = len(queue)
res_temp = []
for _ in range(levelSize):
temp = queue.pop(0)
res_temp.append(temp.val)
if temp.left:
queue.append(temp.left)
if temp.right:
queue.append(temp.right)
res.append(res_temp)
return res
从前序和中序构造二叉树
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
def build(preorder,inorder):
if not preorder:
return None
root = TreeNode(preorder[0])
root_index = inorder.index(preorder[0])
root.left = build(preorder[1:root_index+1],inorder[0:root_index])
root.right = build(preorder[root_index+1:],inorder[root_index+1:])
return root
return build(preorder,inorder)
从中序和后序构造二叉树
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
def build(inorder,postorder):
if not inorder:
return None
root = TreeNode(postorder[-1])
root_index = inorder.index(postorder[-1])
root.left = build(inorder[0:root_index],postorder[0:root_index])
root.right = build(inorder[root_index+1:],postorder[root_index:-1])
return root
return build(inorder,postorder)
栈
最小栈(最大栈同理)
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
class MinStack:
def __init__(self):
self.stack = []
self.min_stack = []
def push(self, val: int) -> None:
self.stack.append(val)
if not self.min_stack:
self.min_stack.append(val)
elif val <= self.min_stack[-1]:
self.min_stack.append(val)
def pop(self) -> None:
t = self.stack.pop(-1)
if t == self.min_stack[-1]:
self.min_stack.pop(-1)
def top(self) -> int:
return self.stack[-1]
def getMin(self) -> int:
return self.min_stack[-1]
一维动态规划
爬楼梯
Leetcode 70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
class Solution:
def climbStairs(self, n: int) -> int:
dp = [1]*n
dp[0] = 1
dp[1] = 2
for i in range(2,len(dp)):
dp[i] = dp[i-1] + dp[i-2]
return dp[-1]
打家劫舍
Leetcode 198. 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
class Solution:
def rob(self, nums: List[int]) -> int:
dp = nums
for i in range(len(nums)):
if i-2>=0:
dp[i] += dp[i-2]
return max(dp)
回溯
电话号码的字母组合
- 电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return []
length = len(digits)
map = {
"2":['a','b','c'],
"3":['d','e','f'],
"4":['g','h','i'],
"5":['j','k','l'],
"6":['m','n','o'],
"7":['p','q','r','s'],
"8":['t','u','v'],
"9":['w','x','y','z']
}
res = []
def dfs(s,index):
if index == length:
res.append(s)
return
for c in map[digits[index]]:
t = s+c
dfs(t,index + 1)
dfs("",0)
return res
组合
- 组合
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res = []
def dfs(nums,index,n,k):
if len(nums) == k:
res.append(nums[:])
return
for i in range(index+1,n+1):
temp = nums[:]
temp.append(i)
dfs(temp,index+i,n,k)
dfs([],0,n,k)
return res
全排列
- 全排列
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
length = len(nums)
res = []
def dfs(nums,start,length):
if start == length-1:
res.append(nums[:])
for i in range(start,length):
nums[start],nums[i] = nums[i],nums[start]
dfs(nums,start+1,length)
nums[i],nums[start] = nums[start],nums[i]
dfs(nums,0,length)
return res
组合总和
- 组合总和
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
length = len(candidates)
res = []
def dfs(nums, index, sum):
if sum == target:
res.append(nums[:])
return
for j in range(index,length):
if sum + candidates[j] > target:
return
if sum + candidates[j] <= target:
t = nums[:]
t.append(candidates[j])
dfs(t, j, sum + candidates[j])
dfs([], 0, 0)
return res
