leetcode 61-70

61. 旋转链表

分析

在这里插入图片描述
注意 k >= n, k %= n

code

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if (!head) return NULL;
        auto dummy = new ListNode(-1);
        dummy->next = head;
        int n = 0;
        auto b = dummy;
        // 先找出末尾的节点
        for (auto p = head; p; p = p->next) {
            b = p;
            n ++;
        }
        if (k >= n) k %= n;
        if (k == 0) return head;
        
        k = n - k;
        auto p = dummy;
        for (int i = 0; i < k; i ++ ) p = p->next; // 找出位移后头节点的前一个节点
        auto a = p->next; // 4
        p->next = NULL;
        b->next = dummy->next;
        dummy->next = a;
        return dummy->next;
    }
};

62. 不同路径

分析

dp

code

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> f(m + 1, vector<int>(n + 1));
        for (int i = 0; i < m; i ++ )
            for (int j = 0; j < n; j ++ ){
                if (!i && !j) f[i][j] = 1;
                else if (!i) f[i][j] += f[i][j - 1];
                else if (!j) f[i][j] += f[i - 1][j];
                else f[i][j] += f[i - 1][j] + f[i][j - 1];
            }
        return f[m - 1][n - 1];
    }
};

63. 不同路径 II

分析

同上题

code

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& o) {
        int n = o.size(), m = o[0].size();
        if (o[0][0] || o[n - 1][m - 1]) return 0;
        vector<vector<int>> f(n + 1, vector<int>(m + 1));
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ ){
                if (!i && !j) f[i][j] = 1;
                else if (!i && !o[0][j - 1]) f[i][j] += f[i][j - 1];
                else if (!j && !o[i - 1][0]) f[i][j] += f[i - 1][j];
                else {
                    if (i && !o[i - 1][j]) f[i][j] += f[i - 1][j];
                    if (j && !o[i][j - 1]) f[i][j] += f[i][j - 1];
                }
            }
        return f[n - 1][m - 1];
    }
};

code(优化)

将每层判断都需要用到o的信息, 将o提到循环外

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& o) {
        int n = o.size(), m = o[0].size();
        if (o[0][0] || o[n - 1][m - 1]) return 0;
        vector<vector<int>> f(n + 1, vector<int>(m + 1));
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ ){
                if (!o[i][j]){
                    if (!i && !j) f[i][j] = 1;
                    else if (!i) f[i][j] += f[i][j - 1];
                    else if (!j) f[i][j] += f[i - 1][j];
                    else f[i][j] += f[i - 1][j] + f[i][j - 1];
                }
            }
        return f[n - 1][m - 1];
    }
};

64. 最小路径和

分析

思路同机器人那道题

code

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int n = grid.size(), m = grid[0].size();
        vector<vector<int>> f(n + 1, vector<int>(m + 1));
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= m; j ++ ){
                if (i == 1) f[i][j] += f[i][j - 1] + grid[i - 1][j - 1];
                else if (j == 1) f[i][j] += f[i - 1][j] + grid[i - 1][j - 1];
                else f[i][j] += min(f[i - 1][j], f[i][j - 1]) + grid[i - 1][j - 1];
            }
        return f[n][m];
    }
};

65. 有效数字

分析

DiamondZ大佬的题解
这里用A[.[B]][e|EC]或者.B[e|EC]表示,其中A和C都是整数(可以有正负号也可以没有),B是无符号整数。

[]代表出现0次或1次,e|E代表指数符号,C是带符号整数。

code

class Solution {
public:
    bool isNumber(string s) {
        int i = 0;
        while (i < s.size() && s[i] == ' ') i ++;

        bool numberic = scanInteger(s, i);
        
        if (s[i] == '.') numberic = scanUnsignedInteger(s, ++ i) || numberic; 
        // scan函数一定要在前, numberic || scanUnsignedInter 会因为numbeic = true, 而不执行scan函数, "3." 答案错误
        if (s[i] == 'e' || s[i] == 'E') numberic = scanInteger(s, ++ i) && numberic;

        while (i < s.size() && s[i] == ' ')  i ++;

        return numberic && i == s.size();
    }

    bool scanInteger(string&s, int& pos){
        if (s[pos] == '+' || s[pos] == '-') pos ++;
        return scanUnsignedInteget(s, pos);
    }

    bool scanUnsignedInteger(string& s, int &pos){
        int p = pos;
        while (pos < s.size() && s[pos] >= '0' && s[pos] <= '9') pos ++;
        return pos > p;
    }
};

66. 加一

分析

因为原数组是 高位在前, 低位在后, 不方便进位.

  1. 翻转
  2. 高精度加法
    2.1 for(auto &x : digits)
  3. 翻转结算的结果

code

class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        reverse(digits.begin(), digits.end());
        int t = 1;
        vector<int> res;
        for (auto &x : digits){
            t += x;
            res.push_back(t % 10);
            t /= 10;
        }
        if (t) res.push_back(t);
        reverse(res.begin(), res.end());
        return res;
    }
};

67. 二进制求和

分析

原理同上一题
步骤:

  1. 翻转原字符串
  2. 高精度加法
  3. 翻转计算的结果

code

class Solution {
public:
    string addBinary(string a, string b) {
        reverse(a.begin(), a.end());
        reverse(b.begin(), b.end());
        int t = 0;
        string res;
        for (int i = 0; i < a.size() || i < b.size(); i ++ ){
            if (i < a.size()) t += a[i] - '0';
            if (i < b.size()) t += b[i] - '0';
            res.push_back(t % 2 + '0');
            t /= 2;
        }
        if (t) res.push_back(t + '0');
        reverse(res.begin(), res.end());
        return res;
    }
};

68. 文本左右对齐

分析

一行一行处理,每次先求出这一行最多可以放多少个单词,然后分三种情况处理:

  1. 如果是最后一行,则只实现左对齐:每个单词之间插入一个空格,行尾插入若干空格,使这一行的总长度是 maxWidth;
  2. 如果这一行只有一个单词,则直接在行尾补上空格;
  3. 其他情况,则需计算总共要填补多少空格,然后按题意均分在单词之间;

注意 循环变量i扫尾工作

因为循环内带j变量, j表示最长下一个需要处理的字符串, 因此下一步i需要跳到j - 1的位置, i = j - 1

code

class Solution {
public:
    vector<string> fullJustify(vector<string>& words, int maxWidth) {
        vector<string> res;
        for (int i = 0; i < words.size(); i ++ ){
            int j = i + 1;
            int len = words[i].size();
            while (j < words.size() && len + 1 + words[j].size() <= maxWidth)
                len += 1 + words[j ++].size();
            string line;
            if (j == words.size() || j == i + 1){
                line += words[i];
                for (int k = i + 1; k < j; k ++ ) line += ' ' + words[k];
                while (line.size() < maxWidth) line += ' ';
            }
            else {
                int cnt = j - i - 1, r = maxWidth - len + cnt; // cnt 表示间隔数, r表示空格数
                line += words[i]; // 第一个单词前不用补空格, 直接加
                int k = 0;
                // r % cnt 表示 多余了空格数, 需要平均分给前面几个
                // r / cnt 表示 每个间隔需要分配多少空格数
                // cnt 表示总共有多少个间隔需要分配空格
                while (k < r % cnt) line += string(r / cnt + 1, ' ')  + words[i + k + 1], k ++ ;
                while (k < cnt) line += string(r / cnt, ' ') + words[i + k + 1], k ++;
            }
            res.push_back(line);
            i = j - 1;
        }
        return res;
    }
};

69. x 的平方根

分析

二分

code

class Solution {
public:
    int mySqrt(int x) {
        int l = 0, r = x;
        while (l < r){
            int mid = (long long)l + r + 1 >> 1;
            if (mid <= x / mid) l = mid;
            else r = mid - 1;
        }
        return l;
    }
};

70. 爬楼梯

dp

code

class Solution {
public:
    int climbStairs(int n) {
        vector<int> f(n + 1);
        f[0] = 1, f[1] = 1;
        for (int i = 2; i <= n; i ++ )
            f[i] += f[i - 1] + f[i - 2];
        return f[n];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值