leetcode 51-60

51. N 皇后

分析

与leetcode79 走迷宫方法类似

联动leetcode 79

code

class Solution {
public:
    vector<vector<string>> ans;
    vector<string> res;
    int dg[22], udg[22], col[11];
    vector<vector<string>> solveNQueens(int n) {
        for (int i = 0; i < n; i ++ )
            res.push_back(string(n, '.'));
        for (int i = 0; i < n; i ++ )
            cout << res[i] << endl;
        dfs(0, n);
        return ans;
    }
    void dfs(int u, int n){
        if (u == n){
            ans.push_back(res);
            return ;
        }

        for (int i = 0; i < n; i ++ ){
            if (!dg[u + i] && !udg[i - u + n] && !col[i]){
                res[u][i] = 'Q';
                dg[u + i] = udg[i - u + n] = col[i] = 1;
                dfs(u + 1, n);
                res[u][i] = '.';
                dg[u + i] = udg[i - u + n] = col[i] = 0;
            }
        }
    }
};

LeetCode 52. N皇后 II

分析

递归树, 在递归中创建变量int res = 0, 用于接受下一层递归返回的结果, 也方便将当前的结果返回到上一层.
递归结束条件: u == n 表示0~ n - 1层都放了八皇后, 表示一种方案合法, return 1;
在这里插入图片描述

code

class Solution {
public:
    vector<bool> dg, udg, col;
    int n;
    int totalNQueens(int _n) {
        n = _n;
        int res = 0;
        dg = udg = vector<bool> (2 * n);
        col = vector<bool> (n);
        return dfs(0);
    }
    int dfs(int u){
        if (u == n){
            return 1;
        }
        int res = 0;
        for (int i = 0; i < n; i ++ ){
            if (!dg[i + u] && !udg[i - u + n] && !col[i]){
                dg[i + u] = udg[i - u + n] = col[i] = 1;
                res += dfs(u + 1);
                dg[i + u] = udg[i - u + n] = col[i] = 0;
            }
        }
        return res;
    }
};

53. 最大子序和

分析

在这里插入图片描述

code

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int n = nums.size();
        vector<int> f(n);
        f[0] = nums[0];
        for (int i = 1; i < n; i ++)
            f[i] = max(f[i - 1], 0) + nums[i];
        int res = -1e9;
        for (int i = 0; i < n; i ++ ) res = max(res, f[i]);
        return res;
    }
};

code(优化)

可以用一个变量last保存nums[i] + max(f[i - 1], 0)

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int res = INT_MIN;
        for (int i = 0, last = 0; i < nums.size(); i ++ ){
            last = nums[i] + max(last, 0);
            res = max(res, last);
        }
        return res;
    }
};

54. 螺旋矩阵

分析

因为需要走n * m, 因此先循环n * m 次, 然后需要创建一个bool数组, 去记录哪些点已经走过了, 再创建上右下左方向, 并且指定起点.
在循环中, 现将当前点加入到答案, 再更新当前点, 如果当前点出界或者已经走过, 那么转换到下一个方向, 将下一个位置更新到当前点.

联动每日一题(AcWing 756. 蛇形矩阵)

code

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        int n = matrix.size(), m = matrix[0].size();
        int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
        int x = 0, y = 0, d = 1;
        vector<int> res;
        bool st[n][m];
        memset(st, 0, sizeof st);
        for (int i = 0; i < n * m; i ++ ){
            st[x][y] = true;
            res.push_back(matrix[x][y]); // 加入到答案
            int a = x + dx[d], b = y + dy[d]; // 更新当前点
            if (a < 0 || a >= n || b < 0 || b >= m || st[a][b]) { // 如果不合法, 换方向
                d = (d + 1) % 4;
                a = x + dx[d], b = y + dy[d];
            }
            x = a, y = b;// 更新下一个坐标到当前点
        }
        return res;
    }
};

55. 跳跃游戏

分析

可以证明一个点能跳跃的位置区间, 一定是连续的
证明: 假如存在一个点能跳跃的区间是不连续的, 那么存在如下图的情况
在这里插入图片描述
假定跳跃的位置不连续, 可以找到如图中所示的情况, 使得前一个位置不能跳到, 后一个位置能够跳到, 但是后一个位置由有前面的位置跳跃来的, 那么前面的位置少跳几步一定能够达到图中x点, 矛盾

由能跳跃的位置是连续的区间段, 因此可以从前往后扫描, 扫描的时候记录下, 当前可以跳跃的最右边是什么, 即所有前缀max(i + nums[i])
如果发现前面i - 1个点能跳跃到的最靠右的位置j <i, 那么说明i永远到不了, return false;
否则, 用i + nums[i]更新j

code

class Solution {
public:
    bool canJump(vector<int>& nums) {
        for (int i = 0, j = 0; i < nums.size(); i ++ ){
            if (j < i) return false;
            j = max(j, i + nums[i]);
        }
        return true;
    }
};

56. 合并区间

分析

模板题

code

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& segs) {
        vector<vector<int>> res;
        sort(segs.begin(), segs.end());
        int st = -2e9, ed = -2e9;
        for (auto seg : segs){
            if (ed < seg[0]){
                if (st != -2e9) res.push_back({st, ed});
                st = seg[0], ed = seg[1];
            }else ed = max(ed, seg[1]);
        }
        if (st != -2e9) res.push_back({st, ed});
        return res;
    }
};

57. 插入区间

分析

a[k][1] < b[0]的时候, 左边区间与b没有交集
否则a[k][1] >= b[0] 说明当前区间右边界和b区间左边界有交集, 还需要后面的区间与b有相交&& a[k][0] <= b[1]

在这里插入图片描述

code

class Solution {
public:
    vector<vector<int>> insert(vector<vector<int>>& a, vector<int>& b) {
        vector<vector<int>> res;
        int k = 0;
        while (k < a.size() && a[k][1] < b[0]) res.push_back(a[k ++]);
        if (k < a.size()){
            b[0] = min(b[0], a[k][0]);
            while (k < a.size() && a[k][0] <= b[1]) b[1] = max(b[1], a[k ++ ][1]);
        }
        res.push_back(b);

        while (k < a.size()) res.push_back(a[k ++]);
        return res;
    }
};

58. 最后一个单词的长度

分析

做法1:
可以用stringstream将字符串转化成cin来处理

code

class Solution {
public:
    int lengthOfLastWord(string s) {
        stringstream ssin(s);
        int res = 0;
        string word;
        while (ssin >> word) res = word.size();
        return res;
    }
};

code (双指针)

联动题型

AcWing 799. 最长连续不重复子序列
AcWing 800. 数组元素的目标和

class Solution {
public:
    int lengthOfLastWord(string s) {
        for (int i = s.size() - 1; i >= 0; i -- ){
            if (s[i] == ' ') continue;
            int j = i - 1;
            while (j >= 0 && s[j] != ' ') j --;
            return i - j;
        }
        return 0;
    }
};

59. 螺旋矩阵 II

思路同54题

code

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n));
        int d = 1;
        int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
        int x = 0, y = 0;
        bool st[n][n];
        memset(st, 0, sizeof st);
        for (int i = 1; i <= n * n; i ++ ){
            res[x][y] = i;
            st[x][y] = true;
            int a = x + dx[d], b = y + dy[d];
            if (a < 0 || a >= n || b < 0 || b >= n || st[a][b]){
                d = (d + 1) % 4;
                a = x + dx[d], b = y + dy[d];
            }
            x = a, y = b;
        }
        return res;
    }
};

60. 排列序列

分析

考虑每位分别填什么数字,举个例子
n = 4, k = 10
1_ _ _, 后面总共有3! = 6种填法, 6 < 10, 那么第1位不能填1, 10 - 6 = 4.(表示在1的所有排列后, 还需要前进4)
2_ _ _, 后面总共排列6 > 当前需要步数4, 因此第1位填2,
2 1 _ _, 后面还有2个排列 < 4, 因此第2位不能填1, 4 - 2 = 2
2 3 _ _, 后面还有2个排列 <= 2, 因此第2位填写3,
2 3 1 _, 如果填1, 因为只有1个数, 小于步数2, 因此不能填1, 剩余步数2 - 1 = 1
2 3 4 1, 完成

当前位i填写完毕后, 后面有(n - i - 1)!种可能

联动题目

每日一题(忘了) 等待补充

code

class Solution {
public:
    string getPermutation(int n, int k) {
        string res;
        vector<bool> st(10);
        for (int i = 0; i < n; i ++ ){
            int fact = 1;
            // 当前位置是i的话, 因为下标从0开始, 实际填的是从1开始的 i + 1个数, 
            // 那么剩余 (n - (i + 1))! 排列
            for (int j = 1; j <= n - i - 1; j ++ ) fact *= j;
            
			// 先枚举当前位置填哪个没有填过的数
            for (int j = 1; j <= n; j ++ ){
                if (!st[j]){
                    if (fact < k) k -= fact;
                    else {
                        st[j] = true;
                        res += to_string(j);
                        break; // 重要, 每个位置只能填1次, 填完break;
                    }
                }
            }
        }
        return res;
    }   
};

code(next_permutation)

class Solution {
public:
    string getPermutation(int n, int k) {
        string res;
        for (int i = 1; i <= n; i ++ ) res += to_string(i);
        for (int i = 0; i < k - 1; i ++ ) next_permutation(res.begin(), res.end());
        return res;
    }   
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值