组合
给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
思路:回溯,但是要剪枝。
Python 代码:
def combination(n, k):
def dfs(candicates, cur):
if len(cur) == k:
result.append(cur[:])
return
for i in range(len(candicates):
if len(cur) > 0 and candicates[i] < cur[-1]:
continue # 跳出本次循环 进入下一个循环 即 i + 1 的循环
cur.append(candicates[i])
dfs(candicates[:i] + candicates[i+1:], cur)
cur.pop()
nums = [i for i in range(1, n+1)]
result = []
dfs(nums, [])
return result
在写回溯代码的时候,我们会发现,首先要有个路径增加的判断语句。然后循环遍历的时候,会不断去递归调用。
二叉树的层次遍历
要求自底向上去遍历一棵二叉树。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其自底向上的层次遍历为:
[
[15,7],
[9,20],
[3]
]
思路:借助队列。先自顶向下,先把根压到队列中,弹出来,保存到临时队列,然后看左右子树是否为空,不为空的话再压到队列中,再将数组加到 result 数组中。依次直到队列为空,最后反转result列表。
Python代码如下:
def traversal(root):
if not root:
return []
queue = [root]
res = []
while queue:
size = len(queue)
tmp = []
for _ in range(size):
node = queue.pop(0)
tmp.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
res.append(tmp)
return res[::-1]
最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
这道题用动态规划来做。Python代码如下:
def mps(grid):
if not grid:
return 0
row, col = len(grid), len(grid[0])
dp = grid
for i in range(1, row):
dp[i][0] += dp[i-1][0]
for j in range(1, col):
dp[0][j] = dp[0][j-1]
for i in range(1, row):
for j in range(1, col):
dp[i][j] += min(dp[i-1][j], dp[i][j-1])
return dp[-1][-1]
最低票价
这道题意思是一年365天,选择几个时间出去。买票的话,可以买一天的,可以买连续7天的,也可以买连续30天的。问给定计划出行的日期,求最小票价。
示例:
输入:days = [1,4,6,7,8,20], costs = [2,7,15]
输出:11
解释:
例如,这里有一种购买通行证的方法,可以让你完成你的旅行计划:
在第 1 天,你花了 costs[0] = $2 买了一张为期 1 天的通行证,它将在第 1 天生效。
在第 3 天,你花了 costs[1] = $7 买了一张为期 7 天的通行证,它将在第 3, 4, ..., 9 天生效。
在第 20 天,你花了 costs[0] = $2 买了一张为期 1 天的通行证,它将在第 20 天生效。
你总共花了 $11,并完成了你计划的每一天旅行。
思路:动态规划。比较好理解的一种方法是:
- 只要出不行,就不买票。
- dp数组表示从开始到现在的花费。
Python 代码如下:
def minicost(days, costs):
dp = [0] * (days[-1] + 1)
days_idex = 0
for i in range(1, len(dp)):
if i != days[days_idex]:
dp[i] = dp[i-1]
else:
dp[i] = min(max(dp[i-1],0) + costs[0],
max(dp[i-7],0) + costs[1],
max(dp[i-30], 0) + costs[2])
return dp[-1]
等差数列划分
示例:
A = [1, 2, 3, 4]
返回: 3, A 中有三个子等差数组: [1, 2, 3], [2, 3, 4] 以及自身 [1, 2, 3, 4]。
Python 代码如下:
def arithmetics(A):
if len(A) < 3: return 0
diff = [0] * len(A) - 1
dp = [0] * len(A)
diff[0] = A[1] - A[0]
for i in range(2, len(A)):
diff[i-1] = A[i] - A[i-1]
if diff[i-1] == diff[i-2]:
dp[i] = dp[i-1] + 1
return sum(dp)
零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
def changecoin(coins, amount):
dp = [0] * (amount + 1)
for i in range(1, amount + 1):
dp[i] = 1e8
for coin in coins:
if i >= coin and dp[i-coin] != 1e8:
dp[i] = min(dp[i], dp[i-coin] + 1)
return dp[-1] if not 1e8 else -1