leetcode刷题记录---2020.1.6 八皇后递归困难,螺旋矩阵上下左右边界,合并区间自定义sort,不同路径I和II,加了障碍(dp解决),递归数组记录优化解决

1.N皇后

题目描述:皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。

每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例:

输入: 4
输出: [
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。

解题思路:不能相互攻击即不再同一条直线上,包括横线竖线和斜线

1.类中定义存放结果的vector

2.初始化queen数组,存放n个-1

3.递归核心,参数是第一个皇后对应的下标0,皇后总个数n,已经初始化的queen数组

4.如果皇后下标(第一个参数)==皇后总个数(第二个参数),{

             定义temp临时数组,i从0遍历到n,now为空,j从0遍历到n,如果j和queen中i位置存的值相等,now加Q填充。否则加“.”填充

             把该行now压入temp

             把temp压入ans

}

5.如果不等,col从0到n,queen中第一个参数位置的值为col

                 判断能否摆放,如果可以,递归(下一行,n,queue),不行就回溯到上一行

6.判断是否能摆放,从0到当前row,如果queen在row位置的值等于在j位置的值,或者在一条斜线上(row-queen[row] == j-queen[j]||row+queen[row] == j+queen[j]),返回false,否则返回true。

class Solution {
public:
    vector<vector<string>> ans;
    vector<vector<string>> solveNQueens(int n) {
        vector<int> queen(n,-1);
        Queens(0,n,queen);
        return ans;
    }
    void Queens(int row,int n,vector<int>& queen){
        if(row == n){
            vector<string> temp;
            for(int i = 0;i<n;++i){
                string now = "";
                for(int j = 0;j<n;++j){
                    if(j == queen[i]){
                        now+="Q";
                    }
                    else{
                        now+=".";
                    }
                }
                temp.push_back(now);
            }
            ans.push_back(temp);
        }
        else{
            for(int col=0;col<n;++col){
                queen[row] = col;
                if(isOk(row,n,queen)){
                    Queens(row+1,n,queen);
                }
                //如果row行所有列都不能摆放,回溯到上一行
            }
        }
    }
    bool isOk(int row,int n, vector<int>& queen){
        for(int j = 0;j<row;++j){
            if(queen[row] == queen[j]||row-queen[row] == j-queen[j]||row+queen[row] == j+queen[j]){
                return false;
            }
        }
        return true;    
    }
};

2.螺旋矩阵(该题作业帮遇到过,能解决)

题目描述:

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

示例 1:

输入:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]
示例 2:

输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]

解题思路:

到边界状态会转换。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> ans;
        if(matrix.empty()) return ans;
        int u = 0;
        int d = matrix.size()-1;
        int l = 0;
        int r = matrix[0].size()-1;
        while(true){
            for(int i = l;i<=r;++i) ans.push_back(matrix[u][i]);
            if(++u>d) break;
            for(int i = u;i<=d;++i) ans.push_back(matrix[i][r]);
            if(--r<l) break;
            for(int i = r;i>=l;--i) ans.push_back(matrix[d][i]);
            if(--d<u) break;
            for(int i = d;i>=u;--i) ans.push_back(matrix[i][l]);
            if(++l>r) break;
        }
        return ans;
    }
};

3.合并区间     自定义sort

题目描述:

给出一个区间的集合,请合并所有重叠的区间。

示例 1:

输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:

输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。

解题思路:

1.先排序,根据数组的第一位先升序排序,一旦第一位相等,则按照第二位降序排序。

2.声明二维数组存放结果,一个一维数组暂时存放要插入的数据。

3.因为第一步已经排序过,所以判断的时候

                1.先判断区间下边界是否大于等于下个区间的上边界。是重复,否不重

                 2.继续判断当前区间的下边界是否小于下个区间的下边界,是交叉,否包含

class Solution {
public:
    static bool cmp(vector<int>& a,vector<int>& b){
        if(a[0]==b[0]){
            return a[1]>b[1];
        }
        return a[0]<b[0];
    }
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> res;
        if(intervals.empty()) return res;
        vector<int> temp;
        int count = 0;
        sort(intervals.begin(),intervals.end(),cmp);
        temp.push_back(intervals[0][0]);
        temp.push_back(intervals[0][1]);
        res.push_back(temp);
        for(int i = 1;i<intervals.size();++i){
            if(res[count][1] >= intervals[i][0]){
                if(res[count][1]<=intervals[i][1]){
                    res[count][1] = intervals[i][1];
                }
            }
            else{
                count++;
                temp[0] = intervals[i][0];
                temp[1] = intervals[i][1];
                res.push_back(temp);
            }
        }
        return res;
    }
};

4.不同路径II

题目描述:

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。

说明:m 和 n 的值均不超过 100。

示例 1:

输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

解题思路:

dp,由于只能向右或者向下,因此不用搜索,dp即可

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int w = obstacleGrid.size();
        if(w == 0) return 0;
        int h = obstacleGrid[0].size();
        long long dp[w][h];
        dp[0][0] = obstacleGrid[0][0] == 0 ? 1:0;
        //先处理边界
        for(int i = 1;i<w;++i){
            //第一条竖边,判断i位置是否有障碍物,有的话返回0(到达i位置的路径为0条),没有障碍物返回他的上一个位置的路径条数,边界只有一种情况
            dp[i][0] = obstacleGrid[i][0] == 1 ? 0:dp[i-1][0];
        }
        for(int i = 1;i<h;++i){
            dp[0][i] = obstacleGrid[0][i] == 1 ? 0:dp[0][i-1];
        }
        //在处理内部
        for(int i = 1;i<w;++i){
            for(int j = 1;j<h;++j){
                dp[i][j] = obstacleGrid[i][j] == 1 ? 0:dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[w-1][h-1];
    }
};

 

 

 

5.不同路径,递归记录

static int a[101][101];
class Solution {
public:
    int uniquePaths(int m, int n) {
        if(m <= 0||n <= 0) return 0;
        else if(m == 1||n == 1) return 1;
        else if(m == 2&&n == 2) return 2;
        else if((m==3&&n==2)||(m==2&&n==3)) return 3;
        else if(a[m][n]>0) return a[m][n];
        
        a[m-1][n] = uniquePaths(m-1,n);
        a[m][n-1] = uniquePaths(m,n-1);
        a[m][n] = a[m-1][n]+a[m][n-1];
        return a[m][n];
    }
};

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值