[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;
            }
        }
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值