序號 | 題目 | 難易程度 | 思路 | 備注 |
---|---|---|---|---|
3 | 數組中重復的數字 | 1、桶排序;2、二分法。 | 多寫幾遍 | |
LeetCode 第 287 題:尋找重復數。 | ||||
4 | 二維數組的查找 | 從右上角或者左下角開始找。 | ||
6 | 從尾到頭打印鏈表 | 重點理解:在回溯的時候打印。或者用棧。 | ||
7 | 重建二叉樹 | 遞歸,算好偏移量,拿具體例子分析不會出錯。 | ||
LeetCode 第 105 題、LeetCode 第 106 題。 | ||||
8 | 二叉樹的下一個結點 | 關鍵在于討論是否有右子樹。 | ||
9 | 用兩個棧實現隊列 | 重要 | 得用兩個棧,一定是 stack2 空,才做“翻轉”。 | 多寫幾遍 |
用隊列實現棧 | 重要 | 用一個隊列就可以了。 | ||
10 | 斐波拉契數列數列 | ==思考如何與快速冪扯上關系。== | ||
基礎斐波拉契數列 | 滾動數組,a , b = a + b , a 。 |
|||
變態跳臺階 | 1、動態規劃;2、歸納出通項公式。 | |||
==矩陣求法== | 重要 | |||
11 | ==旋轉數組中的最小數字== | 重要 | 1、二分法;2、分治。 | |
12 | 矩陣中的路徑 | 重要 | floodfill,理解狀態重置,先占位置,如果不符合要求,要把狀態重置。 | |
LeetCode 第 79 題:單詞搜索。 | ||||
13 | 機器人的運動范圍 | 重要 | BFS,只要分析不是,就可以 mark 為 True。 | |
14 | 剪繩子 | 重要 | 1、動態規劃;2、貪心算法。 | 要會畫樹形圖。 |
LeetCode 第 343 題:整數分割。 | ||||
15 | 二進制中 |
重要 | 位運算。n & (n - 1) 把最低位的 |
|
Python 中寫法有點不大一樣:預處理:n = n & 0xFFFFFFFF 。 |
||||
16 | 數值的整數次方 | 特別重要 | 快速冪,“遞歸”和“循環”都要會做。 | |
LeetCode 第 50 題。“循環”的代碼記住就可以了。 | ||||
17 | 打印從 1 到最大的 n 位數 | |||
18 | 刪除鏈表中的結點 | 注意兩個結點非空一起判斷。 | ||
LeetCode 第 82 題:保留 1 個 | ||||
LeetCode 第 83 題:相同不保留 | ||||
19 | 正則表達式匹配 | 困難 | 動態規劃。 | |
20 | 表示數值的字符串 | 困難 | ||
21 | 調整數組使得奇數位于偶數之前 | 兩路快排,l > r 才停止,掌握更通用的寫法。 |
||
22 | 鏈表中倒數第 k 個結點 | 快慢指針。 | ||
23 | 鏈表中環的入口結點 | |||
24 | 反轉鏈表 | |||
25 | 合并排序的鏈表 | |||
26 | 樹的子結構 | |||
27 | 翻轉二叉樹 | |||
28 | 判斷一棵二叉樹是否對稱 | 使用雙端隊列。 | ||
29 | 順時針打印矩陣 | |||
30 | 包含 min 函數的棧 | 設置輔助棧,只有元素比當前所有都小的時候,才 push。 | ||
31 | 棧的壓入、彈出序列 | |||
32 | 不分行從上往下打印二叉樹 | |||
分行從上往下打印二叉樹 | ||||
之字形打印二叉樹 | ||||
33 | 二叉搜索樹的后序遍歷序列 | 易錯 | 遞歸。 | |
34 | 二叉樹中和為某一值的路徑 | 重要 | 回溯,注意狀態要重置。 | |
35 | 復雜鏈表的復制 | |||
36 | 二叉搜索樹與雙向鏈表 | 重點 | 1、遞歸返回 tuple;2、分治。 | |
37 | 序列化二叉樹 | 易錯 | 前序遍歷,定義好分隔符和空結點表示。 | |
38 | 字符串的排列 | 重要 | 掌握如何去掉重復。 | |
39 | 數組中超過一半的數字 | |||
40 | 最小的 K 個數 | 快排,嚴格小于的才放到前面,堆。 | ||
41 | 數據流中的中位數 | 堆。 | ||
42 | 連續子數組的最大和 | 重要 | 狀態:以某個數結尾的。最后要拉通求一遍。 | |
43 | 從 1 到 n 整數中 1 出現的次數 | 困難 | ||
44 | 數字序列中某一位的數字 | 困難 | ||
45 | 把數組排成最小的數 | |||
46 | 把數字翻譯成字符串 | |||
LeetCode 第 91 題:解碼方法。 | ||||
47 | 禮物的最大價值 | |||
48 | 最長不重復字符串的子字符串 | 1、滑動窗口;2、動態規劃;3、隔板法。 | ||
LeetCode 第 3 題:最長不重復字符串 | ||||
49 | 丑數 | |||
50 | 字符串中第一個只出現一次的字符 | |||
字符流中第一個只出現一次的字符 | ||||
51 | 逆序對 | |||
52 | 兩個鏈表的第一個公共結點 | 記住寫法。 | ||
53 | 數字在排序數組中出現的次數 | 二分法。 | ||
54 | 二叉搜索樹的第 |
|||
55 | 二叉樹的深度 | |||
平衡二叉樹 | ||||
56 | 數組中只出現一次的兩個數字 | |||
0 到 n-1 中缺失的數字 | ||||
數組中數值和下標相等的元素 | ||||
數組中唯一只出現一次的數字 | ||||
57 | 和為 S 的兩個數字 | |||
和為 S 的連續正數序列 | ||||
58 | 翻轉單詞順序列 | |||
左旋轉字符串 | ||||
59 | 滑動窗口最大值 | 重要 | ||
60 |
|
|||
61 | 撲克牌順子 | |||
62 | 圓圈中最后剩下的數 | |||
63 | 股票的最大利潤 | 有一些擴展問題。 | ||
64 | 求 1 + 2 + 3 + ... + n | |||
65 | 不用加減乘除做加法 | |||
66 | 構建乘積數組 | |||
67 | 把字符串轉換成整數 | |||
68 | 樹中兩個節點的最近公共祖先 |
第 3 題:數組中重復的數字(桶排序,抽屜原理)
傳送門:AcWing:數組中重復的數字。
給定一個長度為
的整數數組
nums
,數組中所有的數字都在的范圍內。
數組中某些數字是重復的,但不知道有幾個數字重復了,也不知道每個數字重復了幾次。
請找出數組中任意一個重復的數字。
注意:如果某些數字不在
的范圍內,或數組中不包含重復數字,則返回
;
樣例:
給定
nums = [2, 3, 5, 4, 3, 2, 6, 7]
。返回
或
。
思路1:最容易想到用哈希表判重。在 不超過
的時候,使用位運算可以實現
空間復雜度判重。
思路2:排序以后,再遍歷一遍就知道哪個重復了。
思路3:“抽屜原理”。這道題實際上是要求我們使用桶排序的思想(一個蘿卜一個坑),找出重復的數字。
Python 代碼:這個解法會修改原始數組
class Solution(object):
def duplicateInArray(self, nums):
"""
:type nums: List[int]
:rtype int
"""
size = len(nums)
if size < 2:
return -1
# 先統一檢查數字是不是越界了
for i in range(size):
if nums[i] < 0 or nums[i] > size - 1:
return -1
for i in range(size):
# nums[i] 應該在 i 的位置上
while i != nums[i]:
# 發現要交換的那個數和自己一樣,就可以返回了
if nums[i] == nums[nums[i]]:
return nums[i]
self.__swap(nums, i, nums[i])
return -1
def __swap(self, nums, index1, index2):
if index1 == index2:
return
temp = nums[index1]
nums[index1] = nums[index2]
nums[index2] = temp
思路4:下面的問題可以不修改數組找出重復的數字,即使用“二分法”。
LeetCode 第 287 題:尋找重復數
傳送門:287. 尋找重復數。
給定一個包含 n + 1 個整數的數組 nums,其數字都在 1 到 n 之間(包括 1 和 n),可知至少存在一個重復的整數。假設只有一個重復的整數,找出這個重復的數。
示例 1:
輸入:
[1,3,4,2,2]
輸出: 2示例 2:
輸入:
[3,1,3,4,2]
輸出: 3說明:
- 不能更改原數組(假設數組是只讀的)。
- 只能使用額外的
的空間。
- 時間復雜度小于
。
- 數組中只有一個重復的數字,但它可能不止重復出現一次。
思路:分治法,用二分去做,是對“數”做二分,而不是對“索引”做二分。
Python 代碼:使用了二分法的模板,要定位的“數”根據題意在 和
之間
class Solution:
def findDuplicate(self, nums):
"""
【不修改數組找出重復的數字】
給定一個包含 n + 1 個整數的數組 nums,
其數字都在 1 到 n 之間(包括 1 和 n),
可知至少存在一個重復的整數。
假設只有一個重復的整數,找出這個重復的數。
:type nums: List[int]
:rtype: int
"""
left = 1
right = len(nums) - 1
while left < right:
# 取中點有兩種方式,偏左和偏右
mid = left + (right - left + 1) // 2 # 4
count = 0
for num in nums:
if num < mid:
count += 1
if count < mid:
# 比 4 小的個數,最多就只能是 3
# 所以重復的肯定不是 [1,2,3],不能排除 4
# 因為左邊不變,所以取中點的時候,就要偏右
left = mid
else:
# 比 4 小的個數,達到 4 或者更多
# 重復的就落在 [1,2,3]
right = mid - 1
# 跳出循環肯定是因為 start = end
return left
參考資料:《劍指 Offer》(第 2 版)第 3 題:數組中重復的數字。
第 4 題:二維數組中的查找
同 LeetCode 第 240 題,LeetCode 傳送門:搜索二維矩陣 II,AcWing:二維數組中的查找,牛客網傳送門:二維數組中的查找。
在一個二維數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。
請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。
樣例:
輸入數組:
[ [1,2,8,9], [2,4,9,12], [4,7,10,13], [6,8,11,15] ]
如果輸入查找數值為 7,則返回 true,
如果輸入查找數值為 5 ,則返回 false。
分析:有點像 LeetCode 上島嶼的問題,特別之處:從右上角開始找,或者從左下角開始找,為什么不能選左上或者右下開始,因為不能縮小查找范圍。首先選取數組中右上角的數字。如果該數字等于要查找的數字,查找過程結束;如果該數字大于要查找的數組,剔除這個數字所在的列;如果該數字小于要查找的數字,剔除這個數字所在的行。也就是說如果要查找的數字不在數組的右上角,則每一次都在數組的查找范圍中剔除一行或者一列,這樣每一步都可以縮小查找的范圍,直到找到要查找的數字,或者查找范圍為空。
[圖片上傳失敗...(image-54ad66-1549813200679)]
Python 代碼:從右上角開始找,一個一個地找。小了向下面走,大了向左邊走
class Solution(object):
def searchArray(self, array, target):
rows = len(array)
if rows == 0:
return False
cols = len(array[0])
if rows > 0 and cols > 0:
row = 0
col = cols - 1
# 注意:在橫縱坐標都有意義的時候,才可以搜索,因此用 and
while row < rows and col >= 0:
if target == array[row][col]:
return True
elif target < array[row][col]:
# [4, 5, 6, 12, 13] 找 7
col -= 1
else:
# [7]
# [8]
# [12] 找 9
row += 1
# 全部走完都找不到,就說明沒有
return False
說明:其實不管是每行還是每列,都是有序數組,所以可以使用二分法。我寫了個二分法,只是作為練習。但是二分法不能保證一次寫對,所以不建議在面試的時候寫。
Python 代碼:(了解即可)
# 4、二維數組中的查找
class Solution(object):
# 二分法查找規律
# 1、從右到左,找第 1 個小于或者等于 target 的數
# 2、從上到下,找第 1 個大于或者等于 target 的數
def searchArray(self, array, target):
"""
:type array: List[List[int]]
:type target: int
:rtype: bool
"""
rows = len(array)
if rows == 0:
return False
cols = len(array[0])
col = cols - 1
row = 0
while row < rows and col >= 0:
# print('row', row, 'col', col, array[row][0])
# 1、從右到左,找第 1 個小于或者等于 target 的數
if col == 0 and array[row][0] > target:
return False
l = 0
r = col
while l < r:
mid = l + (r - l + 1) // 2
if array[row][mid] <= target:
l = mid
else:
assert array[row][mid] > target
r = mid - 1
col = l
# 2、從上到下,找第 1 個大于或者等于 target 的數
if row == rows - 1 and array[rows - 1][col] < target:
return False
l = row
r = rows - 1
while l < r:
mid = l + (r - l) // 2
if array[mid][col] >= target:
r = mid
else:
assert array[mid][col] < target
l = mid + 1
row = l
if array[row][col] == target:
return True
return False
if __name__ == '__main__':
array = [[1, 2, 8, 9],
[2, 4, 9, 12],
[4, 7, 10, 13],
[6, 8, 11, 15]]
target = 16
solution = Solution()
result = solution.searchArray(array, target)
print(result)
LeetCode 第 74 題:搜索二維矩陣
傳送門:搜索二維矩陣。
編寫一個高效的算法來判斷 m x n 矩陣中,是否存在一個目標值。該矩陣具有如下特性:
- 每行中的整數從左到右按升序排列。
- 每行的第一個整數大于前一行的最后一個整數。
示例 1:
輸入: matrix = [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ] target = 3 輸出: true
示例 2:
輸入: matrix = [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ] target = 13 輸出: false
Python 代碼1:“標準的”二分法
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
m = len(matrix)
if m == 0:
return False
n = len(matrix[0])
if n == 0:
return False
left = 0
# 這里一定要記得減 1
right = m * n - 1
while left <= right:
mid = left + (right - left) // 2
# 定位到矩陣中
num = matrix[mid // n][mid % n]
if num == target:
return True
elif num < target:
left = mid + 1
else:
right = mid - 1
return False
Python 代碼2:“神奇的”二分法模板
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
m = len(matrix)
if m == 0:
return False
n = len(matrix[0])
# [[]] 針對這種情況,要特判
if n == 0:
return False
l = 0
r = m * n - 1
while l < r:
mid = l + (r - l) // 2
if matrix[mid // n][mid % n] < target:
l = mid + 1
else:
r = mid
# 這個模板在退出循環的時候 l == r 成立,但是有可能存在不滿足條件的時候
# 所以要單獨判斷
return matrix[l // n][l % n] == target
第 6 題:從尾到頭打印鏈表
傳送門:AcWing:從尾到頭打印鏈表。
輸入一個鏈表的頭結點,按照 從尾到頭 的順序返回節點的值。
返回的結果用數組存儲。
樣例:
輸入:
[2, 3, 5]
返回:[5, 3, 2]
思路1:首先應該想到,使用棧作為輔助。
Python 代碼1:Python 中的列表有可以在指定位置插入元素,我們就每次在索引 處插入元素好了
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def printListReversingly(self, head):
"""
:type head: ListNode
:rtype: List[int]
"""
p = head
stack = []
while p:
stack.append(p.val)
p = p.next
return stack[::-1]
Python 代碼2:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def printListReversingly(self, head):
"""
:type head: ListNode
:rtype: List[int]
"""
p = head
stack = []
while p:
stack.insert(0, p.val)
p = p.next
return stack
思路2:使用遞歸,關鍵在于遞歸函數的編寫,特別注意:在回溯的時候,添加當前結點的值到結果集中。
Python 代碼:
class Solution(object):
def printListReversingly(self, head):
"""
:type head: ListNode
:rtype: List[int]
"""
res = []
self.helper(res, head)
return res
def helper(self, res, listnode):
if listnode is None:
return
# 應該先判斷下一個結點是否為空,如果不為空,則遞歸調用,在回溯的時候,才添加到結果中
if listnode.next:
self.helper(res, listnode.next)
# 這一步特別關鍵:回溯時添加
res.append(listnode.val)
思考下面這個寫法為什么是錯的。
拿具體的測試用例就可以很容易想明白,不能使用 if else 語句。
第 7 題:重建二叉樹(遞歸)
同 LeetCode 第 105 題,傳送門:從前序與中序遍歷序列構造二叉樹。
傳送門:AcWing:重建二叉樹。
輸入一棵二叉樹前序遍歷和中序遍歷的結果,請重建該二叉樹。
注意:
- 二叉樹中每個節點的值都互不相同;
- 輸入的前序遍歷和中序遍歷一定合法;
樣例:
給定:
前序遍歷是:[3, 9, 20, 15, 7]
中序遍歷是:[9, 3, 15, 20, 7]
返回:
[3, 9, 20, null, null, 15, 7, null, null, null, null]
返回的二叉樹如下所示:3 / \ 9 20 / \ 15 7
思路:遞歸重建。二叉樹的 DFS 有如下三種遍歷方式:
- 前序遍歷:先訪問根結點,再訪問左子結點,最后訪問右子結點。
- 中序遍歷:先訪問左子結點,再訪問根結點,最后訪問右子結點。
- 后序遍歷:先訪問左子結點,再訪問右子結點,最后訪問根結點。
本題為前序遍歷和中序遍歷,最少需要兩種遍歷方式,才能重建二叉樹。
關鍵:前序遍歷數組的第 個數(索引為
)的數一定是二叉樹的根結點,于是可以在中序遍歷中找這個根結點的索引,然后把“前序遍歷數組”和“中序遍歷數組”分為兩個部分,就分別對應二叉樹的左子樹和右子樹,分別遞歸完成就可以了。
注意:1、編寫遞歸方法的時候,先寫特殊情況;
2、索引是多少不好判斷的時候,干脆就用一個具體的例子,就比如我上面畫的這個圖,把具體的數換成我們使用的變量,這樣思考的難度會降低,而且還不容易出錯。
Python 代碼:
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def buildTree(self, preorder, inorder):
"""
返回構造的 TreeNode 根結點
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
# 在編碼過程中,一定要保證 len(pre) == len(tin),否則邏輯一定不正確
if len(preorder) == 0:
return None
if len(preorder) == 1:
# 這里要返回結點,而不是返回具體的數
return TreeNode(preorder[0])
root = TreeNode(preorder[0])
# 直接得到在中序遍歷中的位置,下面算好偏移量就好了,如果容易算錯,記得拿具體例子
pos = inorder.index(preorder[0])
root.left = self.buildTree(preorder[1:pos + 1], inorder[:pos])
root.right = self.buildTree(preorder[pos + 1:], inorder[pos + 1:])
return root
類似問題:LeetCode 第 106 題。
LeetCode 第 106 題:從中序與后序遍歷序列構造二叉樹
傳送門:106. 從中序與后序遍歷序列構造二叉樹。
根據一棵樹的中序遍歷與后序遍歷構造二叉樹。
注意:
你可以假設樹中沒有重復的元素。例如,給出
中序遍歷 inorder =
[9,3,15,20,7]
后序遍歷 postorder =[9,15,7,20,3]
返回如下的二叉樹:
3 / \ 9 20 / \ 15 7
思路:二叉樹的問題,在紙上寫寫畫畫更形象。
Python 代碼:
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def buildTree(self, inorder, postorder):
"""
:type inorder: List[int]
:type postorder: List[int]
:rtype: TreeNode
"""
assert len(inorder) == len(postorder)
if len(inorder) == 0:
return None
if len(inorder) == 1:
# 這里要返回結點,而不是返回具體的數
return TreeNode(inorder[0])
# 最后一個結點是根結點
root = TreeNode(postorder[-1])
pos = inorder.index(postorder[-1])
root.left = self.buildTree(inorder[:pos], postorder[:pos])
root.right = self.buildTree(inorder[pos + 1:], postorder[pos:-1])
return root
# 用于驗證的方法
def validate(node):
if node is None:
return
validate(node.left)
print(node.val, end=' ')
validate(node.right)
if __name__ == '__main__':
inorder = [9, 3, 15, 20, 7]
postorder = [9, 15, 7, 20, 3]
solution = Solution()
root = solution.buildTree(inorder, postorder)
validate(root)
第 8 題:二叉樹的下一個結點
傳送門:AcWing:二叉樹的下一個結點。
給定一棵二叉樹的其中一個節點,請找出中序遍歷序列的下一個節點。
注意:
- 如果給定的節點是中序遍歷序列的最后一個,則返回空節點;
- 二叉樹一定不為空,且給定的節點一定不是空節點;
樣例:
假定二叉樹是:
[2, 1, 3, null, null, null, null]
, 給出的是值等于 2 的節點。則應返回值等于3的節點。
解釋:該二叉樹的結構如下,2 的后繼節點是 3 。
2 / \ 1 3
思路:用《算導》中提出的方法,畫圖分析,把要分類討論的情況分析清楚,編碼就很容易了。這道題的關鍵在于:看是否有右子樹。
畫個清楚的圖幫助理解:
Python 代碼:
class Solution(object):
def inorderSuccessor(self, q):
"""
:type q: TreeNode
:rtype: TreeNode
"""
if q is None:
return None
# 分類討論1:如果這個結點有右子樹,返回這個右子樹的最小者
if q.right:
node = q.right
while node.left:
node = node.left
return node
# 分類討論2:如果這個結點沒有右子樹,向上追溯,追到父親結點的左結點是自己
while q.father:
if q.father.left == q:
return q.father
q = q.father
return None
第 9-1 題:用兩個棧實現隊列
傳送門:AcWing:用兩個棧實現隊列。
請用棧實現一個隊列,支持如下四種操作:
- push(x) – 將元素x插到隊尾;
- pop() – 將隊首的元素彈出,并返回該元素;
- peek() – 返回隊首元素;
- empty() – 返回隊列是否為空;
注意:
- 你只能使用棧的標準操作:
push to top
,peek/pop from top
,size
和is empty
;- 如果你選擇的編程語言沒有棧的標準庫,你可以使用list或者deque等模擬棧的操作;
- 輸入數據保證合法,例如,在隊列為空時,不會進行
pop
或者peek
等操作;樣例
MyQueue queue = new MyQueue(); queue.push(1); queue.push(2); queue.peek(); // returns 1 queue.pop(); // returns 1 queue.empty(); // returns false
注意:下面這個邏輯是錯的,應該是只要 stack2 是空的,才把 stack1 的元素全部搬到 stack2,這里要小心。
def __shift(self):
if self.stack1:
while self.stack1:
self.stack2.append(self.stack1.pop())
Python 代碼:
class MyQueue(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.stack1 = []
self.stack2 = []
def push(self, x):
"""
Push element x to the back of queue.
:type x: int
:rtype: void
"""
self.stack1.append(x)
def __shift(self):
if len(self.stack2) == 0:
while self.stack1:
self.stack2.append(self.stack1.pop())
def pop(self):
"""
Removes the element from in front of queue and returns that element.
:rtype: int
"""
self.__shift()
return self.stack2.pop()
def peek(self):
"""
Get the front element.
:rtype: int
"""
self.__shift()
return self.stack2[-1]
def empty(self):
"""
Returns whether the queue is empty.
:rtype: bool
"""
return len(self.stack1) == 0 and len(self.stack2) == 0
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()
第 9-2 題:用隊列實現棧
同 LeetCode 第 225 題。
傳送門:225. 用隊列實現棧
使用隊列實現棧的下列操作:
- push(x) -- 元素 x 入棧
- pop() -- 移除棧頂元素
- top() -- 獲取棧頂元素
- empty() -- 返回棧是否為空
注意:
- 你只能使用隊列的基本操作-- 也就是
push to back
,peek/pop from front
,size
, 和is empty
這些操作是合法的。- 你所使用的語言也許不支持隊列。 你可以使用 list 或者 deque(雙端隊列)來模擬一個隊列 , 只要是標準的隊列操作即可。
- 你可以假設所有操作都是有效的(例如, 對一個空的棧不會調用 pop 或者 top 操作)。
Python 代碼:
class MyStack:
def __init__(self):
"""
Initialize your data structure here.
"""
self.queue = []
def push(self, x):
"""
Push element x onto stack.
:type x: int
:rtype: void
"""
self.queue.append(x)
# 將隊列中前面已經逆序的元素放在 x 元素后面,使得整體逆序
for _ in range(len(self.queue) - 1):
ele = self.queue.pop(0)
self.queue.append(ele)
def pop(self):
"""
Removes the element on top of the stack and returns that element.
:rtype: int
"""
if self.queue:
return self.queue.pop(0)
def top(self):
"""
Get the top element.
:rtype: int
"""
if self.queue:
return self.queue[0]
def empty(self):
"""
Returns whether the stack is empty.
:rtype: bool
"""
return len(self.queue) == 0
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
第 10 題:跳臺階(斐波拉契數列、滾動變量)
傳送門:AcWing:跳臺階。
輸入一個整數
,求斐波那契數列的第
項。
假定從
開始,第
項為
。(
)
樣例:
輸入整數
返回
。
思路:這題的數據范圍很小,我們直接模擬即可。當數據范圍很大時,就需要采用其他方式了,可以參考求解斐波那契數列的若干方法。
時間復雜度:總共需要計算 次,所以時間復雜度是
。
Python 代碼1:用兩個變量滾動式往后計算, 表示第
項,
表示第
項。則令
表示第
項,然后讓
、
順次往后移一位。
class Solution(object):
def Fibonacci(self, n):
"""
:type n: int
:rtype: int
"""
if n == 0:
return 0
if n == 1:
return 1
a = 0
b = 1
while n:
c = a + b
# “滾動變量”:接下來重新定義 a 和 b
a = b
b = c
n -= 1
return a
Python 代碼2:Python 語法糖,了解即可
class Solution(object):
def Fibonacci(self, n):
"""
:type n: int
:rtype: int
"""
if n == 0:
return 0
if n == 1:
return 1
a = 0
b = 1
while n:
a , b = a + b , a
n -= 1
return a
Python 代碼3:
class Solution:
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
a = 0
b = 1
while n:
a , b = b , a + b
n -= 1
return b
參考資料:面試官問你斐波那契數列的時候不要高興得太早。書上斐波拉契數列數列空間更省的寫法,P76。
第 10-2 題:變態跳臺階
傳送門:牛客網:變態跳臺階。
一只青蛙一次可以跳上
級臺階,也可以跳上
級,……,它也可以跳上
級。求該青蛙跳上一個
級的臺階總共有多少種跳法。
Python 代碼:因為青蛙一次可以跳任意臺階,我們就讓它跳 階,所以初始值設置為
。
class Solution:
def jumpFloorII(self, number):
if number == 0:
return 1
if number == 1:
return 1
dp = [1 for _ in range(number + 1)]
dp[0] = 0
dp[1] = 1
for i in range(2, number + 1):
for j in range(1, i):
dp[i] += dp[j]
return dp[number]
思路2:
當 時,結果為
;
當 時,結果為
;
當 時,結果為
;
……
以此類推,使用數學歸納法不難發現,跳法 。
Python 代碼:
class Solution:
def jumpFloorII(self, number):
# write code here
if number <= 2:
return number
total = 1
for _ in range(1, number):
total *= 2
return total
第 10-3 題:斐波拉契數列矩陣求法
參考資料:求解斐波那契數列的若干方法。
(本節完)