题目描述
给定一个正整数矩阵,找出最长递增路径的长度。
第每个格子,你可以向四个方向移动(上下左右),不能对角线或移出边界。
例子
Example 1:
Input: nums =
[
[9,9,4],
[6,6,8],
[2,1,1]
]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9].
Example 2:
Input: nums =
[
[3,4,5],
[3,2,6],
[2,2,1]
]
Output: 4
Explanation: The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed.
思想
dp[i][j]表示到达(i, j)时的最大长度。
状态方程:有四种状态(a, b)可以到达(i, j),若当前matrix[i][j]比前一个格子大,则更新matrix[i][j] = max(matrix[i][j], dp(a, b)] + 1)
采取记忆化搜索递归的方法,如果当前点更新过了dp[i][j] != 1,则无需状态转移。
解法
递归。复杂度 - 时间O(n^2), 空间O(n^2)。
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: int
"""
if not matrix or not matrix[0]:
return 0
m, n = len(matrix), len(matrix[0])
dp = [[1] * n for _ in range(m)] # dp[i][j]以matrix[i][j]结尾的LIS
dxy = [(-1, 0), (0, -1), (1, 0), (0, 1)]
def dfs(x, y):
if dp[x][y] != 1:
return dp[x][y]
for dx, dy in dxy:
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n and matrix[x][y] > matrix[nx][ny]:
dp[x][y] = max(dp[x][y], dfs(nx, ny) + 1)
return dp[x][y]
res = 1
for i in range(m):
for j in range(n):
res = max(res, dfs(i, j))
return res
(简化版)
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: int
"""
if not matrix or not matrix[0]:
return 0
m, n = len(matrix), len(matrix[0])
dp = [[1] * n for _ in range(m)]
def dfs(i, j):
if dp[i][j] == 1:
dp[i][j] = 1 + max(dfs(i-1, j) if i > 0 and matrix[i][j] > matrix[i-1][j] else 0,
dfs(i+1, j) if i < m-1 and matrix[i][j] > matrix[i+1][j] else 0,
dfs(i, j-1) if j > 0 and matrix[i][j] > matrix[i][j-1] else 0,
dfs(i, j+1) if j < n-1 and matrix[i][j] > matrix[i][j+1] else 0)
return dp[i][j]
return max(dfs(i, j) for i in range(m) for j in range(n))
题目描述
给定不同面值的硬币和总钱数amount。求得到总钱数所需的最小硬币数。如果无法得到总钱数,返回-1。
假设每种硬币有无限个。
例子
Example 1:
Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3
Output: -1
思想
(DP - 背包问题)用amount+1标记无穷。
初始化:前0种组成价值0所需数目为0, 前0种组成价值j(j>0)所需数目为无穷。
转移方程:
当j >= coins[i-1]时,至少取一个coins[i-1]:dp[i][j - coins[i-1]] + 1;或一次也不取coins[i-1]:dp[i-1][j]。即dp[i][j] = min(dp[i][j - coins[i-1]] + 1, dp[i-1][j]);
当j < coins[i-1]时,只能一次也不取coins[i-1]:dp[i-1][j]。即dp[i][j] = dp[i-1][j]。
(优化)
索引coins时的优化和空间优化
解法1
DP。复杂度:时间 - O(mn),空间-O(mn)
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
n = len(coins)
dp = [[amount+1] * (amount+1) for _ in range(n+1)] # dp[i][j]表示用前i种coins组成价值j所需的最小数量
dp[0][0] = 0
for i in range(1, n+1):
for j in range(amount+1):
if j >= coins[i-1]:
dp[i][j] = min(dp[i][j - coins[i-1]] + 1, dp[i-1][j])# 至少用一次coin[i-1]/一次也不用
else:
dp[i][j] = dp[i-1][j]
return -1 if dp[-1][-1] == amount+1 else dp[-1][-1]
解法2 - 优化
DP。复杂度:时间 - O(mn),空间-O(mn)
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
n = len(coins)
dp = [amount+1] * (amount+1)
dp[0] = 0
for coin in coins:
for j in range(amount+1):
if j >= coin:
dp[j] = min(dp[j-coin] + 1, dp[j])
return dp[-1] if dp[-1] != amount + 1 else -1