1. 斐波那契数列的第n项
# -*- coding:utf-8 -*-
class Solution:
def Fibonacci(self, n):
if n==0: return 0
if n==1: return 1
a, b, c = 0, 1, -1
for i in range(2, n + 1):
c = a + b
a = b
b = c
return c
2. 牛客网在线编程专题《剑指offer-面试题9:题目二》跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
方法:考察跳了n个台阶邻近的情况。假设青蛙跳了n格,如果它是跳了1到n格的,那么一共f(n-1)种跳法;如果是跳了2到n格的,那么一共f(n-2)种跳法。所以一共有f(n-1)+f(n-2)种跳法。
\[f(n)= \begin{cases} 1 & n=1 \\ 2 & n=2 \\ f(n-1) + f(n-2) & n>2 \end{cases} \]
这样迭代法就能搞定。
3. [LeetCode]120. Triangle
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
给以上这种三角形,返回从顶到底的元素和最小走法(每次只能走邻近子节点)
比如以上的结果:2 + 3 + 5 + 1 = 11
方法:动归题有一个明显特征,就是可以自底向上求解,所以基本上先找一个任意点状态转移方程(根据依赖关系)。
上图中,从2到底的结果可以被拆解成 min(从3到底的结果, 从4到底的结果) + 2
方程即可确定:
\[dp[row][i] = min(dp[row+1][i], dp[row+1][i+1]) + triagnle[row][i] \]
写代码的时候,可以先写一个递归,初始化dp数组(比如-1),然后每次要递归前先查一下dp数组是否有记录的值;也可以直接迭代法。
4. [LeetCode]64. Minimum Path Sum
Input:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
Output: 7
非负二维数组,找到从左上角到右下角的路径,使得元素和最小
上图这个路径 1→3→1→1→1 元素和最小, 为7
方法:状态转移方程为
\[dp[row][col] = min(dp[row][col-1], dp[row-1][col]) + matrix[row][col] \]
代码如前一题组织,需要剪枝。
5. [LeetCode]343. Integer Break
Input: 10
Output: 36
Explanation: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36.
给一个正数,怎么拆分成至少两个数的和形式,使分解出来的元素积组大。
方法:只要找状态转移方程就行
\[dp[n] = max(i*dp[n-i], i*(n-i)) \]
这里状态约束条件很弱,i需要从1到n-1取,因此复杂度也需要O(n^2),给出迭代法代码实现:
int integerBreak(int n) {
int dp[n];
dp[1] = 1;
dp[2] = 1;
for(int i=3; i<=n; i++){
dp[i] = -1;
for(int j=1; j<i; j++){
dp[i] = max(j*dp[i-j], max(j*(i-j), dp[i])); //注意后面的dp[i]
}
}
return dp[n];
}
6. [LeetCode]279. Perfect Squares
Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.
输入一个正整数n, 输出其最少能由几个完全平方数相加组成(完全平方数为1,4,9,16,...)
方法:跟上题类似,直接上迭代代码
int numSquares(int n) {
int *dp = new int[n + 1];
dp[0] = 0;
for (int i=1; i<=n; i++) {
int _min = INT_MAX;
for (int j=1; j*j<=i; j++) {
_min = min(_min, dp[i-j*j]+1);
}
dp[i] = _min;
}
delete[]dp;
return dp[n];
}
7. [LeetCode]91. Decode Ways
'A'到'Z'用数字1~26表示
Input: "12"
Output: 2
12可以有两种编码方式 "AB" (1 2) or "L" (12).
方法:与上题类似,直接迭代代码
def numDecodings(self, s):
if len(s)==0 or s[0]=='0': return 0
dp = [1,1]
for i in range(2, len(s)+1):
if s[i-2:i]=='10' or s[i-2:i]=='20':
dp.append(dp[i-2])
elif 10<int(s[i-2:i])<=26:
dp.append(dp[i-1]+dp[i-2])
elif s[i-1]!='0':
dp.append(dp[i-1])
else:
return 0
return dp[-1]
8. [LeetCode]62. Unique Paths
给一个m*n矩阵,从左上角到右下角一共多少条路径,要求只能走右边或者左边
方法:非常简单,直接上代码
def uniquePaths(self, m, n):
dp = [[1 for i in range(m)] for i in range(n)]
for i in range(1, n):
for j in range(1,m):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[-1][-1]
9. [LeetCode]63. Unique Paths II
在上题基础上加了障碍,下面1是障碍
[
[0,0,0],
[0,1,0],
[0,0,0]
]
Output: 2
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right
方法:在上题基础上加个剪枝就行了
def uniquePathsWithObstacles(self, obstacleGrid):
# type obstacleGrid: List[List[int]]
row = len(obstacleGrid)
col = len(obstacleGrid[0])
dp = [[1] * col for i in range(row)]
for i in range(0, row):
for j in range(0, col):
if obstacleGrid[i][j]: # 如果这个点是障碍
dp[i][j] = 0
elif i == 0:
dp[i][j] = dp[i][j-1]
elif j == 0:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[-1][-1]