动态规划机试题概览

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]

猜你喜欢

转载自www.cnblogs.com/xytpai/p/12609984.html
今日推荐