1. 程式人生 > >[Leetcode] 63, 51, 52

[Leetcode] 63, 51, 52

63. Unique Paths II

Follow up for "Unique Paths":

Now consider if some obstacles are added to the grids. How many unique paths would there be?

An obstacle and empty space is marked as 1 and 0 respectively in the grid.

For example,

There is one obstacle in the middle of a 3x3 grid as illustrated below.

[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]

The total number of unique paths is 2.

Note: m and n will be at most 100.

Solution(1): 深搜+備忘錄法,記得邊界情況(起點和終點)和記錄的資料不能出錯。

Code:

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        if(obstacleGrid.size()==0 || obstacleGrid[0].size()==0) return 0;
        if(obstacleGrid.back().back()==1 || obstacleGrid[0][0]==1) return 0;
        obstacleGrid.back().back() = -1;
        return uniquePathsWithObstacles(obstacleGrid, 0, 0);
    }
private:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid, int x, int y){
        if(obstacleGrid[x][y]==1) return 0;
        if(obstacleGrid[x][y]<0) return -1*obstacleGrid[x][y];
        //已經計算過的部分使用負數標記那一個到終點的種類,數量為0的情況記為1,即值為0時這個位置沒有計算過
        int ans = 0;
        if(x<obstacleGrid.size()-1){
            ans += uniquePathsWithObstacles(obstacleGrid, x+1, y);
        }
        if(y<obstacleGrid[0].size()-1){
            ans += uniquePathsWithObstacles(obstacleGrid, x, y+1);
        }
        if(ans>0)
            obstacleGrid[x][y] = -1*ans;
        else
            obstacleGrid[x][y] = 1;
        return ans;
    }
};

Solution(2): 動規。

Code:

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        if(obstacleGrid[0][0]==1 || obstacleGrid.back().back()==1) return 0;
        obstacleGrid.back().back() = 1;
        int m = obstacleGrid.size();
        int n = obstacleGrid[0].size();
        for(int i=n-2; i>=0; i--){
            if(obstacleGrid[m-1][i]==0)  
                obstacleGrid[m-1][i] = obstacleGrid[m-1][i+1];
            else
                obstacleGrid[m-1][i] = 0;
        }
        for(int i=m-2; i>=0; i--){
            if(obstacleGrid[i][n-1]==0)
                obstacleGrid[i][n-1] = obstacleGrid[i+1][n-1];
            else
                obstacleGrid[i][n-1] = 0;
        }
        for(int i=m-2; i>=0; i--){
            for(int t=n-2; t>=0; t--){
                if(obstacleGrid[i][t]==0)
                    obstacleGrid[i][t] = obstacleGrid[i+1][t]+obstacleGrid[i][t+1];
                else
                    obstacleGrid[i][t] = 0;
            }
        }
        return obstacleGrid[0][0];
    }
};


51. N-Queens

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

For example,
There exist two distinct solutions to the 4-queens puzzle:

[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]

Solution: 經典的回溯題,深搜+剪枝。對於剪枝,我的做法是在原陣列中直接將不能放Queen的位置標記為'.'。

Code:

class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>> ans;
        string s = "";
        for(int i=0; i<n; i++) s.push_back('+');
        vector<string> path(n);
        fill_n(path.begin(), n, s);
        solveNQueens(0, path, ans);
        return ans;
    }
private:
    void solveNQueens(int i, vector<string>& path, vector<vector<string>>& ans){
        //cout<<i<<endl;
        int n = path.size();
        if(i==n){
            ans.push_back(path);
            return;
        }
        //遍歷第i行, '+'表示沒有擺放任何值, 'Q'表示擺放了Queen, '.'表示無法擺放Queen
        for(int t=0; t<n; t++){
            if(path[i][t]=='+'){
                path[i][t] = 'Q';
                vector<string> newpath = setQueen(i, t, path);//TODO
                //for(int i=0; i<newpath.size(); i++)
                    //cout<<newpath[i]<<endl;
                solveNQueens(i+1, newpath, ans);
                path[i][t] = '.';
            }
        }
    }
    vector<string> setQueen(int i, int t, vector<string>& path){
        vector<string> newpath = path;
        int n = path.size();
        for(int j=i+1; j<n; j++)
            newpath[j][t] = '.';
        for(int j=t+1; j<n; j++)
            newpath[i][j] = '.';
        for(int j=i+1,q=t+1; j<n && q<n; j++,q++)
            newpath[j][q] = '.';
        for(int j=i+1,q=t-1; j<n && q>=0; j++,q--)
            newpath[j][q] = '.';
        return newpath;
    }
};


52. N-Queens II

Follow up for N-Queens problem.

Now, instead outputting board configurations, return the total number of distinct solutions.

Solution: 比上面一題要簡單一些,不需要輸出解集,只需要輸出總數即可,在深搜的時候使用一個全域性變數記錄總數,搜到一個解就+1。換了一種記錄的方式,不再直接記錄在原棋盤資料中,因為這題不需要生成解,直接使用是三個陣列來記錄即可,因為棋盤上一個資料可以投影到四個方向,橫向、縱向、主對角線方向、副對角線方向,這四個方向一個點都只能存在一個Queen,因此使用三個陣列記錄三個方向的放棋方式,一個方向用於深搜。

Code:

class Solution {
public:
    int totalNQueens(int n) {
        this->columns = vector<bool>(n,true);
        this->principal_diagonals = vector<bool>(n,true);
        this->counter_diagonals = vector<bool>(n,true);
        totalNQueens(0, n);
        return num;
    }
private:
    vector<bool> columns;//投影:y, true為可以填入Queen, false為不可填入Queen
    vector<bool> principal_diagonals;//投影:x-y+n-1
    vector<bool> counter_diagonals;//投影:x+y
    int num = 0;
    void totalNQueens(int x, int n){
        //第x行往下有多少解
        if(x==n){
            num++;
            return;
        }
        for(int y=0; y<n; y++){
            if(columns[y] && principal_diagonals[x-y+n-1] && counter_diagonals[x+y]){
                columns[y] = false;
                principal_diagonals[x-y+n-1] = false;
                counter_diagonals[x+y] = false;
                totalNQueens(x+1, n);
                columns[y] = true;
                principal_diagonals[x-y+n-1] = true;
                counter_diagonals[x+y] = true;
            }
        }
    }
};