1. 程式人生 > >劍指offer題解(四):java&c++

劍指offer題解(四):java&c++

矩陣中的路徑

題目描述

請設計一個函式,用來判斷在一個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則該路徑不能再進入該格子。

例如下面的矩陣包含了一條 bfce 路徑。

解題思路

c++

class Solution {
private:
    bool dfs(char* matrix, vector<bool> visited, char *str, int x, int y, int rows, int cols )
    {
        if
(x<0||x>=rows||y<0||y>=cols) return false; if(matrix[x*cols+y]==*str && visited[x*cols+y]==false) { visited[x*cols+y] = true; if(*(str+1)==0) return true; bool res = dfs(matrix,visited,(str+1),x,y-1,rows,cols) || dfs(matrix,visited,(str+1
),x-1,y,rows,cols) || dfs(matrix,visited,(str+1),x,y+1,rows,cols) || dfs(matrix,visited,(str+1),x+1,y,rows,cols); if(res == false) visited[x*cols+y] = false; return res; } else return false; } public: bool
hasPath(char* matrix, int rows, int cols, char* str) { vector<bool> visited(rows*cols,false); bool res = false; for(int i = 0;i<rows;i++) for(int j = 0;j<cols;j++) res = res||dfs(matrix,visited,str,i,j,rows,cols); return res; } };

java

private final static int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
private int rows;
private int cols;

public boolean hasPath(char[] array, int rows, int cols, char[] str) {
    if (rows == 0 || cols == 0)
        return false;
    this.rows = rows;
    this.cols = cols;
    boolean[][] marked = new boolean[rows][cols];
    char[][] matrix = buildMatrix(array);
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < cols; j++)
            if (backtracking(matrix, str, marked, 0, i, j))
                return true;
    return false;
}

private boolean backtracking(char[][] matrix, char[] str, boolean[][] marked, int pathLen, int r, int c) {
    if (pathLen == str.length)
        return true;
    if (r < 0 || r >= rows || c < 0 || c >= cols || matrix[r][c] != str[pathLen] || marked[r][c])
        return false;
    marked[r][c] = true;
    for (int[] n : next)
        if (backtracking(matrix, str, marked, pathLen + 1, r + n[0], c + n[1]))
            return true;
    marked[r][c] = false;
    return false;
}

private char[][] buildMatrix(char[] array) {
    char[][] matrix = new char[rows][cols];
    for (int i = 0, idx = 0; i < rows; i++)
        for (int j = 0; j < cols; j++)
            matrix[i][j] = array[idx++];
    return matrix;
}

機器人的運動範圍

題目描述

地上有一個 m 行和 n 列的方格。一個機器人從座標 (0, 0) 的格子開始移動,每一次只能向左右上下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於 k 的格子。例如,當 k 為 18 時,機器人能夠進入方格(35, 37),因為 3+5+3+7=18。但是,它不能進入方格(35, 38),因為 3+5+3+8=19。請問該機器人能夠達到多少個格子?

解題思路

c++

class Solution {
public:
    int movingCount(int threshold, int rows, int cols)
    {
       bool *flag = new bool[rows * cols];
        for(int i = 0; i < rows * cols; i++)
            flag[i] = false;
        int count = moving(threshold, rows, cols, 0, 0, flag);
        return count; 
    }
     int moving(int threshold, int rows, int cols, int i, int j, bool* flag)
        {
        int count = 0;
        if(i >= 0 && i < rows && j >= 0 && j < cols && getsum(i) + getsum(j) <= threshold && flag[i * cols + j] == false)
            {
            flag[i * cols + j] = true;
            count =1 + moving(threshold, rows, cols, i + 1, j, flag)
                + moving(threshold, rows, cols, i - 1, j, flag)
                + moving(threshold, rows, cols, i , j - 1, flag)
                + moving(threshold, rows, cols, i, j + 1, flag);
        }
        return count;
    }
    int getsum(int num)
        {
        int sum = 0;
        while(num)
            {
            sum += num % 10;
            num /= 10;

        }
        return sum;
    }
};

java

private static final int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
private int cnt = 0;
private int rows;
private int cols;
private int threshold;
private int[][] digitSum;

public int movingCount(int threshold, int rows, int cols) {
    this.rows = rows;
    this.cols = cols;
    this.threshold = threshold;
    initDigitSum();
    boolean[][] marked = new boolean[rows][cols];
    dfs(marked, 0, 0);
    return cnt;
}

private void dfs(boolean[][] marked, int r, int c) {
    if (r < 0 || r >= rows || c < 0 || c >= cols || marked[r][c])
        return;
    marked[r][c] = true;
    if (this.digitSum[r][c] > this.threshold)
        return;
    cnt++;
    for (int[] n : next)
        dfs(marked, r + n[0], c + n[1]);
}

private void initDigitSum() {
    int[] digitSumOne = new int[Math.max(rows, cols)];
    for (int i = 0; i < digitSumOne.length; i++) {
        int n = i;
        while (n > 0) {
            digitSumOne[i] += n % 10;
            n /= 10;
        }
    }
    digitSum = new int[rows][cols];
    for (int i = 0; i < this.rows; i++)
        for (int j = 0; j < this.cols; j++)
            digitSum[i][j] = digitSumOne[i] + digitSumOne[j];
}

剪繩子

題目描述

把一根繩子剪成多段,並且使得每段的長度乘積最大。

For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4).

解題思路

動態規劃

java

public int integerBreak(int n) {
    int[] dp = new int[n + 1];
    dp[1] = 1;
    for (int i = 2; i <= n; i++)
        for (int j = 1; j < i; j++)
            dp[i] = Math.max(dp[i], Math.max(j * (i - j), dp[j] * (i - j)));
    return dp[n];
}

c++

class Solution {
private:
    vector<int> memo;

    int max3(int a, int b, int c)
    {
        return max(a,max(b,c));
    }

    int getMax(int n)
    {
        if(n == 1)
        {
            return 1;
        }
        if(memo[n]!=-1)
            return memo[n];
        int res = -1;
        for(int i =1;i<n;i++)
        {
            res = max3(res,i*getMax(n-i),i*(n-i));
        }
        memo[n] = res;
        return res;
    }
public:
    int integerBreak(int n) {
        memo = vector<int>(n+1,-1);
        return getMax(n);        
    }
};

貪心演算法

儘可能多剪長度為 3 的繩子,並且不允許有長度為 1 的繩子出現,如果出現了,就從已經切好長度為 3 的繩子中拿出一段與長度為 1 的繩子重新組合,把它們切成兩段長度為 2 的繩子。

證明:當 n >= 5 時,3(n - 3) - 2(n - 2) = n - 5 >= 0。因此把長度大於 5 的繩子切成兩段,令其中一段長度為 3 可以使得兩段的乘積最大。

public int integerBreak(int n) {
    if (n < 2)
        return 0;
    if (n == 2)
        return 1;
    if (n == 3)
        return 2;
    int timesOf3 = n / 3;
    if (n - timesOf3 * 3 == 1)
        timesOf3--;
    int timesOf2 = (n - timesOf3 * 3) / 2;
    return (int) (Math.pow(3, timesOf3)) * (int) (Math.pow(2, timesOf2));
}