刷题记录 | 组合 + 二叉树遍历 + 动态规划

组合

给定两个整数 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

猜你喜欢

转载自blog.csdn.net/weixin_38746310/article/details/108462473
今日推荐