1.70-爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
python
# 空间O(1)
# 时间O(n)
class Solution:
def climbStairs(self, n:int) -> int:
if n==1 or n==2: return n
a, b, temp = 1, 2, 0
for i in range(3, n+1):
temp = a + b
a = b
b = temp
return temp
# 递推空间O(n)
# 时间O(n)
class Solution:
def climbStairs(self, n:int) -> int:
stairs = [0] * (n+1)
stairs[0] = stairs[1] = 1
for i in range(2, n+1):
stairs[i] = stairs[i - 1] + stairs[i - 2]
return stairs[-1]
2. 10-II. 青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
python
# 斐波那契数列
class Solution:
def numWays(self, n: int) -> int:
a, b = 1, 1
mod = 1000000007
for _ in range(n):
a, b = b, a + b
return int(a % mod)
class Solution:
def numWays(self, n: int) -> int:
if n == 0 or n == 1: return 1
a, b = 1, 1
mod = 1000000007
for i in range(2, n+1, 1):
a, b = b, a + b
return int(b % mod)
3. 3-无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
python
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s: return 0
left = 0
lookup = set()
n = len(s)
max_len = 0
cur_len = 0
for i in range(n):
cur_len += 1
while s[i] in lookup:
lookup.remove(s[left])
left += 1
cur_len -= 1
if cur_len > max_len:
max_len = cur_len
lookup.add(s[i])
return max_len
class Solution:
def lengthOfLongestSubstring(self, s:str) -> int:
dic, res, i = {}, 0, -1
for j in range(len(s)):
if s[j] in dic:
i = max(i, dic[s[j]])
dic[s[j]] = j
res = max(res, j - i)
return res
4. 146-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) 的平均时间复杂度运行。
python
## 需要使用一个哈希表和一个双向链表来实现
哈希时间复杂度O(1)、链表O(1),空间复杂度O(capacity)
class LRUCache(collections.OrderedDict):
def __init__(self, capacity: int):
super().__init__()
self.capacity = capacity
def get(self, key: int) -> int:
if key not in self:
return -1
self.move_to_end(key)
return self[key]
def put(self, key: int, value: int) -> None:
if key in self:
self.move_to_end(key)
self[key] = value
if len(self) > self.capacity:
self.popitem(last=False)
## 不适用调用
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.hashmap = {}
self.head = ListNode()
self.tail = ListNode()
self.head.next = self.tail
self.tail.prev = self.head
def move_node_to_tail(self, key):
node = self.hashmap[key]
node.prev.next = node.next
node.next.prev = node.prev
node.prev = self.tail.prev
node.next = self.tail
self.tail.prev.next = node
self.tail.prev = node
def get(self, key: int) -> int:
if key in self.hashmap:
self.move_node_to_tail(key)
res = self.hashmap.get(key, -1)
if res == -1:
return res
else:
return res.value
def put(self, key: int, value: int) -> None:
if key in self.hashmap:
self.hashmap[key].value = value
self.move_node_to_tail(key)
else:
if len(self.hashmap) == self.capacity:
# 去掉哈希表对应项
self.hashmap.pop(self.head.next.key)
self.head.next = self.head.next.next
self.head.next.prev = self.head
new = ListNode(key, value)
self.hashmap[key] = new
new.prev = self.tail.prev
new.next = self.tail
self.tail.prev.next = new
self.tail.prev = new
class ListNode:
def __init__(self, key=None, value=None):
self.key = key
self.value = value
self.prev = None
self.next = None
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
5. 648-单词替换
在英语中,我们有一个叫做 词根(root) 的概念,可以词根后面添加其他一些词组成另一个较长的单词------我们称这个词为 继承词(successor)。例如,词根an,跟随着单词 other(其他),可以形成新的单词 another(另一个)。
现在,给定一个由许多词根组成的词典 dictionary 和一个用空格分隔单词形成的句子 sentence。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根,则用最短的词根替换它。
你需要输出替换之后的句子。
python
时间复杂度。构建字典树消耗 O(d) 时间,字典数的搜索的复杂度为O(1),因此整体的时间复度为O(d)
空间复杂度。哈希集合的占用空间为O(d),分割setence占用空间为O(n),整体的空间复杂度为O(d+n)
class Solution:
def replaceWords(self, dictionary: List[str], sentence: str) -> str:
#利用嵌套字典构建字典树
trie = {}
for word in dictionary:
cur = trie
for c in word:
if c not in cur:
cur[c] = {}
cur = cur[c]
# "#"作为一个word的终止符
cur['#'] = {}
print(trie)
words = sentence.split(' ')
for i, word in enumerate(words):
cur = trie
for j, c in enumerate(word):
if '#' in cur:
words[i] = word[:j]
break
if c not in cur:
break
cur = cur[c]
return ' '.join(words)
if __name__ == '__main__':
dictionary = ["cat","ct","rat"]
sentence = "the cattle was cty rattled by the battery"
# 输出:"the cat was rat by the bat"
# dictionary = ["a","b","c"]
# sentence = "aadsfasf absbs bbab cadsfafs"
# 输出:"a a b c"
res = Solution()
s = res.replaceWords(dictionary, sentence)
print(s)
6. 662- 二叉树最大宽度
两种解法,BFS和DFS。
关键点:结构同满二叉树。
1.对于满二叉树,从根节点开始可以对节点编号1,2,...,某节点p的左子节点的序号为2p,右子节点的序号为2p+1;
2.若令根节点的序号p为0,且左子节点的序号为2p,右子节点的序号为2p+1,则每层节点中,节点的序号即代表节点在这一层中的位置索引。
python
# 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
时间复杂度:O(N),每个节点访问一次; 空间复杂度:O(N),取决于队列;
class Solution:
def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int:
# BFS,队列中记录每个节点的root,pos,按层更新max_width
if not root:
return 0
max_width = 0
queue = [(root, 0)]
while queue:
width = queue[-1][1] - queue[0][1] + 1
if max_width < width:
max_width = width
for _ in range(len(queue)):
node, pos = queue.pop(0)
if node.left:
queue.append((node.left, pos*2))
if node.right:
queue.append((node.right, pos*2 + 1))
return max_width
时间复杂度:O(N),每个节点访问一次; 空间复杂度:O(N),递归栈、字典开销;
# DFS dfs更新最大宽度,用字典记录每层的左侧节点pos,递归时传递当前遍历到的root的pos
def dfs(root, pos=0, level=0):
if not root:
return
dic.setdefault(level, pos)
self.max_width = max(self.max_width, pos - dic[level] + 1)
dfs(root.left, pos*2, level + 1)
dfs(root.right, pos*2 + 1, level + 1)
self.max_width = 0
dic = {}
dfs(root)
return self.max_width
欢迎关注交流与指正!