过关斩将编程题
1.70-爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
# 空间O(1)
# 时间O(n)
class Solution:def climbStairs(self, n:int) -> int:if n==1 or n==2: return na, b, temp = 1, 2, 0for i in range(3, n+1):temp = a + ba = bb = tempreturn temp # 递推空间O(n)
# 时间O(n)class Solution:def climbStairs(self, n:int) -> int:stairs = [0] * (n+1)stairs[0] = stairs[1] = 1for 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。
# 斐波那契数列class Solution:def numWays(self, n: int) -> int:a, b = 1, 1mod = 1000000007for _ in range(n):a, b = b, a + breturn int(a % mod)class Solution:def numWays(self, n: int) -> int:if n == 0 or n == 1: return 1a, b = 1, 1mod = 1000000007for i in range(2, n+1, 1):a, b = b, a + breturn int(b % mod)
3. 3-无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
class Solution:def lengthOfLongestSubstring(self, s: str) -> int:if not s: return 0left = 0lookup = set()n = len(s)max_len = 0cur_len = 0for i in range(n):cur_len += 1while s[i] in lookup:lookup.remove(s[left])left += 1cur_len -= 1if cur_len > max_len:max_len = cur_lenlookup.add(s[i])return max_lenclass Solution:def lengthOfLongestSubstring(self, s:str) -> int:dic, res, i = {}, 0, -1for j in range(len(s)):if s[j] in dic:i = max(i, dic[s[j]])dic[s[j]] = jres = 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) 的平均时间复杂度运行。
## 需要使用一个哈希表和一个双向链表来实现
哈希时间复杂度O(1)、链表O(1),空间复杂度O(capacity)class LRUCache(collections.OrderedDict):def __init__(self, capacity: int):super().__init__()self.capacity = capacitydef get(self, key: int) -> int:if key not in self:return -1self.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] = valueif len(self) > self.capacity:self.popitem(last=False)## 不适用调用
class LRUCache:def __init__(self, capacity: int):self.capacity = capacityself.hashmap = {}self.head = ListNode()self.tail = ListNode()self.head.next = self.tailself.tail.prev = self.headdef move_node_to_tail(self, key):node = self.hashmap[key]node.prev.next = node.nextnode.next.prev = node.prevnode.prev = self.tail.prevnode.next = self.tailself.tail.prev.next = nodeself.tail.prev = nodedef 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 reselse:return res.valuedef put(self, key: int, value: int) -> None:if key in self.hashmap:self.hashmap[key].value = valueself.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.nextself.head.next.prev = self.headnew = ListNode(key, value)self.hashmap[key] = newnew.prev = self.tail.prevnew.next = self.tailself.tail.prev.next = newself.tail.prev = newclass ListNode:def __init__(self, key=None, value=None):self.key = keyself.value = valueself.prev = Noneself.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。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根,则用最短的词根替换它。
你需要输出替换之后的句子。
时间复杂度。构建字典树消耗 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 = triefor 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 = triefor j, c in enumerate(word):if '#' in cur:words[i] = word[:j]breakif c not in cur:breakcur = 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,则每层节点中,节点的序号即代表节点在这一层中的位置索引。
# 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_widthif not root:return 0max_width = 0queue = [(root, 0)]while queue:width = queue[-1][1] - queue[0][1] + 1if max_width < width:max_width = widthfor _ 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的posdef dfs(root, pos=0, level=0):if not root:returndic.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 = 0dic = {}dfs(root)return self.max_width
欢迎关注交流与指正!
