剑指Offer 10、12

92 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

这两题都是之前LeetCode热门100题中重复的题,在此复习一下。

第十题题目:青蛙跳台阶问题,给定一只青蛙,现有一个高度为n的台阶,青蛙每次可以跳一级或两级,求青蛙跳到顶共几种跳法。和之前不同的是本题需要对每次结果进行取模。

解题思路

简单的动态规划问题,并且可以对动态规划的时间复杂度进行优化,首先给出转移方程:

dp[i]=dp[i1]+dp[i2]dp[i] = dp[i-1] + dp[i-2]

学过组合数学很容易理解。空间复杂度为O(n)O(n)的动态规划解法如下:

public int numWays(int n) {
    if(n==0) return 1;
    if(n<=2) return n;
    int[] dp = new int[n+1];
    dp[1] = 1;
    dp[2] = 2;
    for(int i=3;i<n+1;i++){
        dp[i] = (dp[i-1] + dp[i-2])%1000000007;
    }
    return dp[n];
}

因为每次只使用了前面两个元素,那么可以用变量存起来,代码如下:

public int numWays(int n) {
    if(n==0) return 1;
    if(n<=2) return n;
    int a=1, b=2;
    int c = 0 ;
    for(int i=3;i<n+1;i++){
        c=(a+b) %1000000007;
        a = b;
        b = c;
    }
    return c;
}

最终空间复杂度为O(1)O(1)

第十二题题目:矩阵中的路径问题,给定一个m*n的二维网格,每个网格中都有一个字符,先有一个单词word,判断此单词是否可以由这个二维网格中连续字符组成,每个字符只能用一次。

解题思路

每个字符只能用一次,则代表我们需要使用一个变量来表示每个字符的使用情况,之后从头往后遍历这个二维字符数组就能得到结果,需要注意的是边界的判断,当word字符串遍历完之后则代表前面的肯定满足条件,此时可以返回true,如果不满足则在前面直接返回,具体代码如下:

public boolean exist(char[][] board, String word) {
    int row = board.length;
    int column=board[0].length;
    int[][] visited = new int[row][column];
    for(int i=0;i<row;i++){
        for(int j=0;j<column;j++){
            if(board[i][j]==word.charAt(0)){
                if(isExist(board, i, j, word, 0, visited)){
                    return true;
                }
            }
        }
    }
    return false;
}
public boolean isExist(char[][] board, int row, int column, String word, int k, int[][] visited){
    if(k==word.length()) return true;
    if(row<0||column<0||row>=board.length||column>=board[0].length||word.charAt(k)!=board[row][column]||visited[row][column] == 1) return false;
    visited[row][column] = 1;
    boolean up = isExist(board, row-1, column, word, k+1, visited);
    boolean down = isExist(board, row+1, column, word, k+1, visited);
    boolean left = isExist(board, row, column-1, word, k+1, visited);
    boolean right = isExist(board, row, column+1, word, k+1, visited);
    visited[row][column] = 0;
    return up || down || left || right;
}

很可惜超时,原因可能是回溯的时候还要更改visited的状态,我们可以直接修改字符数组中字符,代码如下:

public boolean dfs(char[][] board, int i, int j, String word, int k){
    if(k == word.length()){
        return true;
    }
    if(i<0||j<0||i>=board.length||j>=board[0].length){
        return false;
    }
    if(word.charAt(k)!=board[i][j]){
        return false;
    }
    char c = board[i][j];
    board[i][j] = '#';
    boolean res = dfs(board, i-1, j, word, k+1)||dfs(board, i+1, j, word, k+1)
        || dfs(board, i, j-1, word, k+1) || dfs(board, i, j+1, word, k+1);
    board[i][j] = c;
    return res;
}

最终通过。