• [朝花夕拾] LeetCode刷题记录


    前言:

    20220228

    1. 两数之和

    本来不想做的,无聊点开题解才发现竟然不是简单的 A + B Problem。

    方法一:暴力枚举

     1 class Solution {
     2 public:
     3     vector<int> twoSum(vector<int>& nums, int target) {
     4         int n = nums.size();
     5         for (int i = 0; i < n - 1; i++)
     6             for (int j = i + 1; j < n; j++)
     7                 if (nums[i] + nums[j] == target)
     8                     return {i, j}; 
     9         return {};
    10     }
    11 };

    注意:L9 的 return {} 不能省略,尽管题目说明了不会存在没有结果的情况,但对于编译器而言则必须要求在所有情况下都有返回值。

    方法二:哈希表

    由于答案对是唯一的,我们可以只扫描一次,用 target 减去当前值 nums[i],再判断 nums 中是否有余下的数。由于数据范围远大于数据量,采用哈希表可节省大量空间。在 C++ 中一般使用 map 实现哈希表。

     1 class Solution {
     2 public:
     3     vector<int> twoSum(vector<int>& nums, int t) {
     4         int n = nums.size();
     5         map<int, int> mp;
     6         for (int i = 0; i < n; i++) {
     7             auto it = mp.find(t - nums[i]);
     8             if (it != mp.end())
     9                 return {it -> second, i};
    10             mp[nums[i]] = i;
    11         }
    12         return {};
    13     }
    14 };

    2. 两数相加

    本质上考察链表的处理。

     1 class Solution {
     2 public:
     3     ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
     4         int c = 0;
     5         ListNode *h = NULL, *t = NULL;
     6         while (l1 || l2) {
     7             int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + c;
     8             if (!h)
     9                 h = t = new ListNode(sum % 10);
    10             else {
    11                 t->next = new ListNode(sum % 10);
    12                 t = t->next;
    13             }
    14             c = sum / 10;
    15             if (l1)
    16                 l1 = l1->next;
    17             if (l2)
    18                 l2 = l2->next;
    19         }
    20         if (c > 0)
    21             t->next = new ListNode(c);
    22         return h;
    23     }
    24 };

    3. 无重复字符的最长子串

    方法:双指针法(LC官方写的是滑动窗口)

    设置左指针和右指针,右指针依次向右移动,如果指向字符之前出现在某个位置,且该位置在左指针的左侧,则说明为了维持无重复字符,则左指针需要跳到该位置的后一个位置;

    所以这个过程中需要维护一个数组 a,a[i] 表示字符 i 上次出现的位置。两个指针在移动过程中,其间的区间大小一直在变化,而变化过程中的最大值即为答案。

    (官方的题解的左指针是依次向右移动而非跳跃的,大概是因为使用的 set,这样相当于用更多时间换取了更少空间)

     1 const int N = 130;
     2 
     3 class Solution {
     4 public:
     5     int lengthOfLongestSubstring(string s) {
     6         int l = s.length(), h = 0, t = 0, ans = 0, a[N];
     7         memset(a, -1, sizeof(a));
     8         while (t < l) {
     9             if (a[s[t]] != -1)
    10               h = max(h, a[s[t]] + 1);
    11             a[s[t]] = t;
    12             ans = max(ans, t - h + 1);
    13             t++;
    14         }
    15         return ans;
    16     }
    17 };

    20220301

    4. 不会做

    5. 最长回文子串

    方法一:枚举(LC官方写的中心扩展算法)

    枚举每个字符,以其为回文串的中心点向左向右扩展,直到不满足回文串要求。偶回文串与奇回文串需要分开讨论。

     1 class Solution {
     2 public:
     3     string longestPalindrome(string s) {
     4         int l = s.length(), ans = 1, st = 0;
     5         for (int i = 0; i < l; i++) {
     6             int j = 0;
     7             while (j <= i && i + j < l && s[i - j] == s[i + j])
     8                 j++;
     9             if (2 * j - 1 > ans)
    10                 st = i - j + 1, ans = 2 * j - 1;
    11         }
    12         for (int i = 0; i < l - 1; i++) {
    13             if (s[i] != s[i + 1]) continue;
    14             int j = 1;
    15             while (j <= i && i + j - 1 < l && s[i - j] == s[i + j + 1])
    16                 j++;
    17             if (2 * j > ans)
    18                 st = i - j + 1, ans = 2 * j;
    19         }
    20         return s.substr(st, ans);
    21     }
    22 };

    P.S. string 的截取函数为 substr。

    其他:时间复杂度 O(n) 的 Manacher 算法与 O(n ^ 2) 的动态规划。

    7. 整数反转

    1 class Solution {
    2 public:
    3     int reverse(int x) {
    4         long long o = 0;
    5         while (x) o *= 10, o += x % 10, x /= 10;
    6         if (o < INT_MIN || o > INT_MAX) return 0;
    7         return o;
    8     }
    9 };

    8. 字符串转换整数(atoi)

     1 class Solution {
     2 public:
     3     int myAtoi(string s) {
     4         int o = 0, l = s.length(), f = 0;
     5         long long ans = 0;
     6         while (o < l && s[o] == ' ') o++;
     7         if (o < l && s[o] == '+') f = 0, o++;
     8         else if (o < l && s[o] == '-') f = 1, o++;
     9         while (o < l && s[o] == '0') o++;
    10         while (o < l && s[o] >= '0' && s[o] <= '9') {
    11             ans *= 10, ans += s[o] - '0', o++;
    12             if (ans > INT_MAX) return f ? INT_MIN : INT_MAX;
    13         }
    14         if (f) ans = -ans;
    15         return ans;
    16     }
    17 };

    20220302

    剑指 Offer 3. 数组中重复的数字

    方法一:排序

    将数组排序,然后查找是否存在相邻且相等的元素。

     1 class Solution {
     2 public:
     3     int findRepeatNumber(vector<int>& a) {
     4         int l = a.size();
     5         sort(a.begin(), a.end());
     6         for (int i = 1; i < l; i++)
     7             if (a[i] == a[i - 1])
     8                 return a[i];
     9         return 0;
    10     }
    11 };

    方法二:枚举查重

    把读入的元素进行记录(使用数组、map、set均可),出现记录过的数字即表示重复元素。

     1 class Solution {
     2 public:
     3     int findRepeatNumber(vector<int>& a) {
     4         int l = a.size();
     5         set <int> s;
     6         for (int i = 0; i < l; i++) {
     7             if (s.count(a[i])) return a[i];
     8             s.insert(a[i]);
     9         }
    10         return 0;
    11     }
    12 };

    优化:

    题目有个限定,即值域与定义域均为 n,当且仅当没有重复数字时,元素与其索引编号为一一对应的,均为 0 ~ n - 1;

    于是可以把读入的元素 i 放入大小为 n 的另一个数组 b 的第 i 个位置,如果有两个元素需要放到同一个位置,则说明为重复元素。

    class Solution {
    public:
        int findRepeatNumber(vector<int>& a) {
            map <int, bool> mp;
            for (int i : a) {
                if (mp[i]) return i;
                mp[i] = 1;
            }
            return 0;
        }
    };

    方法三:原地哈希

    在上述优化的基础上,我们发现多开一个数组其实是赘余的:我们可以把上述过程理解成,将打乱的全排列重新排序,通过不停交换元素位置来实现,而唯一不同的是它实际上并非全排列,当且仅当交换过程中出现冲突,即找到了重复元素。

    以样例为例,[2, 3, 1, 0, 2, 5, 3],第一个元素 2 理应放在第 2 个位置,于是将其与第 2 个位置的元素交换,得 [1, 3, 2, 0, 2, 5, 3],同理再将 1 与第 1 个位置元素交换,得 [3, 1, 2, 0, 2, 5, 3],再得 [0, 1, 2, 3, 2, 5, 3],第 0 个位置满足条件;

    依次往后遍历,0, 1, 2, 3 均已就位,第 4 个位置为 2,其理应放在第 2 个位置,但是我们发现第 2 个位置已经有 2 了,说明数组里有多个 2,输出 2 即可。

     1 class Solution {
     2 public:
     3     int findRepeatNumber(vector<int>& a) {
     4         int l = a.size();
     5         for (int i = 0; i < l; i++)
     6             while (i != a[i]) {
     7                 if (a[a[i]] == a[i]) return a[i];
     8                 swap(a[i], a[a[i]]);
     9             } 
    10         return 0;
    11     } 
    12 };

    剑指 Offer 4. 二维数组中的查找

    方法一:DFS + 简单优化

    剪枝剪掉了反向查找,但最坏复杂度依旧是 O(nm)

     1 class Solution {
     2 public:
     3     bool dfs(int x, int y, vector<vector<int>>& a, int target) {
     4         if (x >= a.size() || y >= a[0].size() || x < 0 || y < 0 || f[x][y]) return 0;
     5         f[x][y] = 1;
     6         if (a[x][y] == target) return 1;
     7         if (a[x][y] < target)
     8             return dfs(x + 1, y, a, target) || dfs(x, y + 1, a, target);
     9         else
    10             return dfs(x - 1, y, a, target) || dfs(x, y - 1, a, target);
    11     }
    12     bool findNumberIn2DArray(vector<vector<int>>& a, int target) {
    13         return dfs(0, 0, a, target);
    14     }
    15 };

    方法二:线性查找

    看了题解之后明白了,从左上角出发真是个新奇的思路,大了往左走,小了往下走,必然会找到答案,这样就降到了 O(n + m)。

    class Solution {
    public:
        bool findNumberIn2DArray(vector<vector<int>>& a, int target) {
            if (!a.size() || !a[0].size()) return 0;
            int x = 0, y = a[0].size() - 1;
            while (x < a.size() && y >= 0) {
                if (a[x][y] == target) return 1;
                if (a[x][y] < target) x++;
                else y--;
            }
            return 0;
        }
    };

    注意边界条件。

    其他:直接暴力找

    20220303

    剑指 Offer 5. 替换空格

     1 class Solution {
     2 public:
     3     string replaceSpace(string s) {
     4         int l = s.length();
     5         string ans;
     6         for (auto& c : s)
     7             if (s == ' ') ans += "%20";
     8             else ans += s;
     9         return ans;
    10     }
    11 };

    剑指 Offer 6. 从尾到头打印链表

    方法:栈

     1 class Solution {
     2 public:
     3     vector<int> reversePrint(ListNode* head) {
     4         stack<int> s;
     5         vector<int> a;
     6         ListNode* p = head;
     7         while (p)
     8             s.push(p->val), p = p->next;
     9         while (!s.empty())
    10             a.push_back(s.top()), s.pop();
    11         return a;
    12     }
    13 };

    剑指 Offer 7. 重建二叉树

    方法:递归

    利用前序遍历与中序遍历之间的关系:每从前序遍历中读到一个结点,便在中序遍历中找到该结点(用 map 预处理索引),该结点在中序遍历位置的左侧为以该结点为根的子树的左子树,右侧为右子树,依次构造即可。

     1 class Solution {
     2 private:
     3     map<int, int> ind;
     4 public:
     5     TreeNode* build(vector<int>& p, vector<int>& i, int pl, int pr, int il, int ir) {
     6         if (pl > pr) return nullptr;
     7         int root_p = pl, root_i = ind[p[pl]];
     8         TreeNode* root = new TreeNode(p[pl]);
     9         int size = root_i - il;
    10         root->left = build(p, i, pl + 1, pl + size, il, root_i - 1);
    11         root->right = build(p, i, pl + size + 1, pr, root_i + 1, ir);
    12         return root;
    13     }
    14     
    15     TreeNode* buildTree(vector<int>& p, vector<int>& i) {
    16         int n = p.size();
    17         for (int o = 0; o < n; o++)
    18             ind[i[o]] = o; 
    19         return build(p, i, 0, n - 1, 0, n - 1);
    20     }
    21 };

    20220304

    剑指 Offer 9. 用两个栈实现队列

    考研的时候看到过这道题。栈 A 用来入队;出队时,将栈 A 的元素倒入栈 B,再出栈(出队)。

     1 class CQueue {
     2     stack<int> s1, s2;
     3 public:
     4     CQueue() {
     5         while (!s1.empty())
     6             s1.pop();
     7         while (!s2.empty())
     8             s2.pop();    
     9     }
    10     
    11     void appendTail(int value) {
    12         s1.push(value);
    13     }
    14     
    15     int deleteHead() {
    16         if (s2.empty())
    17             while (!s1.empty())
    18                 s2.push(s1.top()), s1.pop();
    19         if (s2.empty())
    20             return -1;
    21         int res = s2.top();
    22         s.pop();
    23         return res;        
    24     }
    25 };

    剑指 Offer 10. 斐波那契数列 + 青蛙跳台阶问题

     1 const int MOD = 1e9 + 7;
     2 
     3 class Solution {
     4 public:
     5     int fib(int n) {
     6         int a = 0, b = 1;
     7         for (int i = 1; i <= n; i++)
     8             ((i & 1) ? a : b) = (a + b) % MOD;
     9         return n & 1 ? b : a;
    10     }
    11 };

    20220305

    剑指 Offer 11. 旋转数组的最小数字

    方法一:暴力

    1 class Solution {
    2 public:
    3     int minArray(vector<int>& numbers) {
    4         int mi = INT_MAX;
    5         for (int i : numbers)
    6             mi = min(mi, i);
    7         return mi;
    8     }
    9 };

    方法二:二分查找

    根据题意,序列基本是升序的,只有最小值出现的一个位置是降序的,而我们需要找的就是这个位置,不难想到用二分来做。

     1 class Solution {
     2 public:
     3     int minArray(vector<int>& a) {
     4         int n = a.size();
     5         int l = 0, r = n - 1;
     6         while (l < r) {
     7             int m = (l + r) >> 1;
     8             if (a[m] < a[r]) r = m;
     9             else if (a[m] > a[r]) l = m + 1;
    10             else r--;
    11         }
    12         return a[l];
    13     }
    14 };

    剑指 Offer 12. 矩阵中的路径

    方法:DFS + 剪枝

     1 const int vx[4] = {0, 0, 1, -1}, vy[4] = {1, -1, 0, 0};
     2 
     3 class Solution {
     4 public:
     5     bool dfs(vector<vector<char>>& b, vector<vector<char>>& f, int n, int m, string word, int l, int x, int y, int d) {
     6         f[x][y] = 1;
     7         if (d == l - 1)
     8             return 1;
     9         bool res = 0;
    10         for (int i = 0; i < 4; i++) {
    11             int tx = x + vx[i], ty = y + vy[i];
    12             if (tx >= 0 && tx < n && ty >= 0 && ty < m && !f[tx][ty] && b[tx][ty] == word[d + 1])
    13                 res = dfs(b, f, n, m, word, l, tx, ty, d + 1);
    14             if (res) return 1;
    15         }
    16         f[x][y] = 0;
    17         return 0;
    18     }
    19     bool exist(vector<vector<char>>& b, string word) {
    20         int n = b.size(), m = b[0].size(), l = word.length();
    21         vector<vector<char>> f(n, vector<char>(m));
    22         for (int i = 0; i < n; i++)
    23             for (int j = 0; j < m; j++)
    24                 if (b[i][j] == word[0]) {
    25                     for (int k = 0; k < n; k++)
    26                         f[k].assign(m, 0);
    27                     if (dfs(b, f, n, m, word, l, i, j, 0)) return 1;
    28                 }
    29         return 0;
    30     }
    31 };

    20220307 剑指 Offer 13. 机器人的运动范围

    方法:DFS + 剪枝

     1 const int vx[4] = {0, 0, 1, -1}, vy[4] = {1, -1, 0, 0};
     2 const int N = 1e2 + 5;
     3 
     4 class Solution {
     5     int ans = 0, f[N][N];
     6 public:
     7     int calc(int o) {
     8         return o < 10 ? o : o == 100 ? 1 : o % 10 + o / 10;
     9     }
    10     void dfs(int x, int y, int m, int n, int k) {
    11         f[x][y] = 1, ans++;
    12         for (int i = 0; i < 4; i++) {
    13             int tx = x + vx[i], ty = y + vy[i];
    14             if (tx >= 0 && ty >= 0 && tx < m && ty < n && !f[tx][ty] && calc(tx) + calc(ty) <= k)
    15                 dfs(tx, ty, m, n, k);
    16         }
    17     }
    18     int movingCount(int m, int n, int k) {
    19         dfs(0, 0, m, n, k);
    20         return ans;
    21     }
    22 };

    其实还可以剪,对于 > k 的情况在 f 数组中标记个 -1,后面也无需再次判断,不过数据范围太小,影响较小。

    20220310 剑指 Offer 14. 剪绳子

    方法:数学推导

    有意思的数学推导,简而言之就是:求 a = (n / m) ^ m 的最大值,可证明 m = n / e 时有最大值,即长度为 n / m = n / (n / e) = e。又 2 < e < 3,而 2 ^ (1/2) < 3 ^ (1/3),则切分长度为 3 时最优,其次为 2。

    1 class Solution {
    2 public:
    3     int cuttingRope(int n) {
    4         if (n <= 3) return n - 1;
    5         int a = n / 3, b = n % 3;
    6         return !b ? pow(3, a) : b == 1 ? pow(3, a - 1) * 4 : pow(3, a) * 2;
    7     }
    8 };

    进阶:数据扩大到 n <= 1000,且对答案取余。需要用到大数取余。

    方法一:暴力

    已知 xy % p = (x % p) * (y % p) % p,故可以直接循环取余。

    方法二:快速幂

     1 const int MOD = 1e9 + 7;
     2 
     3 class Solution {
     4 public:
     5     long long mypow(int a, int b) {
     6         long long o = a, res = 1;
     7         while (b) {
     8             if (b & 1) (res *= o) %= MOD;
     9             (o *= o) %= MOD;
    10             b >>= 1;
    11         }
    12         return res;
    13     }
    14     int cuttingRope(int n) {
    15         if (n <= 3) return n - 1;
    16         int a = n / 3, b = n % 3;
    17         return !b ? mypow(3, a) : b == 1 ? (mypow(3, a - 1) * 4) % MOD: (mypow(3, a) * 2) % MOD;
    18     }
    19 };

    20220329 剑指 Offer 63. 股票的最大利润

     1 class Solution {
     2 public:
     3     int maxProfit(vector<int>& a) {
     4         int n = a.size();
     5         if (!n) return 0;
     6         int mi = a[0], ans = 0;
     7         for (int i = 1; i < n; i++)
     8             if (a[i] < mi) mi = a[i];
     9             else ans = max(ans, a[i] - mi);
    10         return ans;
    11     }
    12 };

    122. 买卖股票的最佳时机 II

    1 class Solution {
    2 public:
    3     int maxProfit(vector<int>& a) {
    4         int n = a.size(), ans= 0;
    5         for (int i = 1; i < n; i++)
    6             ans += a[i] > a[i - 1] ? a[i] - a[i - 1];
    7         return ans;
    8     }
    9 };

    123. 买卖股票的最佳时机 III

    方法:动态规划

    由于需要买卖两次,直接贪心找最优解不可取,这时候往往是考虑动态规划:

    每天的可选状态很直白:没买;买了 1 次;买了 1 次又卖了;卖了 1 次后又买了第 2 次;买了第 2 次又卖了;

    设 f[i][j] 为前 i 天可能获得的最大利润,状态的转移很直白:买第 i 天的股票即是在原基础上减去 price[i],卖则是加上;

    而由于可以买多次,还需要加上表示已经买了 j 次的一维,那么就是设 f[i][j] 为前 i 天买了 j 次可能获得的最大利润;

    当然这道题限定了 2 次,那么可以简单地设计成多个变量而无需加上一维。

     1 class Solution {
     2 public:
     3     int maxProfit(vector<int>& a) {
     4         int n = a.size();
     5         int b1 = -a[0], s1 = 0, b2 = -a[0], s2 = 0;
     6         for (int i = 1; i < n; i++) {
     7             b1 = max(b1, -a[i]), s1 = max(s1, b1 + a[i]);
     8             b2 = max(b2, s1 - a[i]), s2 = max(s2, b2 + a[i]);
     9         }
    10         return s2;
    11     }
    12 };

    124. 买卖股票的最佳时机 III

    方法:动态规划

    在第 123 题的基础上扩展为二维动态规划数组,用 b[i][j] 和 s[i][j] 分别表示第 i 天买/卖了第 j 次时获得的最大利润,思路同理。

     1 typedef vector<int> arr;
     2 typedef vector<arr> arr2;
     3 
     4 class Solution {
     5 public:
     6     int maxProfit(int k, arr& a) {
     7         if (a.empty()) return 0;
     8         int n = a.size();
     9         k = min(k, n / 2);
    10         arr2 b(n, arr(k + 1));
    11         arr2 s(n, arr(k + 1));
    12         b[0][0] = -a[0], s[0][0] = 0;
    13         for (int i = 1; i <= k; ++i)
    14             b[0][i] = s[0][i] = INT_MIN / 2;
    15         for (int i = 1; i < n; ++i) {
    16             b[i][0] = max(b[i - 1][0], s[i - 1][0] - a[i]);
    17             for (int j = 1; j <= k; ++j) {
    18                 b[i][j] = max(b[i - 1][j], s[i - 1][j] - a[i]);
    19                 s[i][j] = max(s[i - 1][j], b[i - 1][j - 1] + a[i]);   
    20             }
    21         }
    22         return *max_element(s[n - 1].begin(), s[n - 1].end());
    23     }
    24 };

    20220409

    144. 二叉树的前序遍历

    方法一:递归法

     1 /**
     2  * Definition for a binary tree node.
     3  * struct TreeNode {
     4  *     int val;
     5  *     TreeNode *left;
     6  *     TreeNode *right;
     7  *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     8  *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     9  *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
    10  * };
    11  */
    12 class Solution {
    13 public:
    14     vector<int> res;
    15     vector<int> preorderTraversal(TreeNode* root) {
    16         if (root == nullptr)
    17             return res;
    18         res.emplace_back(root->val);
    19         preorderTraversal(root->left);
    20         preorderTraversal(root->right);
    21         return res;
    22     }
    23 };

    方法二:迭代法

     1 class Solution {
     2 public:
     3     vector<int> res;
     4     vector<int> preorderTraversal(TreeNode* root) {
     5         stack<TreeNode*> st;
     6         TreeNode* node = root;
     7         while (!st.empty() || node) {
     8             while (node) {
     9                 st.push(node);
    10                 res.emplace_back(node->val);
    11                 node = node->left;
    12             }
    13             node = st.top();
    14             st.pop();
    15             node = node->right;
    16         }
    17         return res;
    18     }
    19 };

    94. 二叉树的中序遍历

    和前序遍历大同小异。

    方法一:递归法

     1 class Solution {
     2 public:
     3     vector<int> res;
     4     vector<int> inorderTraversal(TreeNode* root) {
     5         if (root == nullptr)
     6             return res;
     7         inorderTraversal(root->left);
     8         res.emplace_back(root->val);
     9         inorderTraversal(root->right);
    10         return res;
    11     }
    12 };

    方法二:迭代法

     1 class Solution {
     2 public:
     3     vector<int> res;
     4     vector<int> inorderTraversal(TreeNode* root) {
     5         stack<TreeNode*> st;
     6         TreeNode* node = root;
     7         while (!st.empty() || node) {
     8             while (node) {
     9                 st.push(node);
    10                 node = node->left;
    11             }
    12             node = st.top();
    13             res.emplace_back(node->val);
    14             st.pop();
    15             node = node->right;
    16         }
    17         return res;
    18     }
    19 };

    145. 二叉树的后序遍历

    方法一:递归法

     1 class Solution {
     2 public:
     3     vector<int> res;
     4     vector<int> postorderTraversal(TreeNode* root) {
     5         if (root == nullptr)
     6             return res;
     7         postorderTraversal(root->left);
     8         postorderTraversal(root->right);
     9         res.emplace_back(root->val);
    10         return res;
    11     }
    12 };

    方法二:迭代法

    和前序、中序有不同,因为遍历只能自上而下遍历,但输出又需要自下而上输出,所以需要两个栈,分别用来遍历和输出。

     1 class Solution {
     2 public:
     3     vector<int> res;
     4     vector<int> postorderTraversal(TreeNode* root) {
     5         stack<TreeNode*> st1, st2;
     6         if (!root) return res;
     7         TreeNode* node = root;
     8         st1.push(root);
     9         while (!st1.empty()){
    10             TreeNode* node = st1.top();
    11             st1.pop();
    12             st2.push(node);
    13             if (node->left) st1.push(node->left);
    14             if (node->right) st1.push(node->right);
    15         }
    16         while (!st2.empty()) {
    17             res.push_back(st2.top()->val);
    18             st2.pop();
    19         }
    20         return res;
    21     }
    22 };

    20220412

    剑指 Offer 26. 树的子结构

     1 class Solution {
     2 public:
     3     bool cmp(TreeNode* A, TreeNode* B) {
     4         if (B == nullptr) return true;
     5         if (A == nullptr || A->val != B->val) return false;
     6         return cmp(A->left, B->left) && cmp(A->right, B->right);
     7     }
     8     bool isSubStructure(TreeNode* A, TreeNode* B) {
     9         if (A == nullptr || B == nullptr) return false;
    10         if (A->val == B->val && cmp(A, B))
    11             return true;
    12         return isSubStructure(A->left, B) || isSubStructure(A->right, B);
    13     }
    14 };

    20220416

    剑指 Offer 17. 打印从1到最大的n位数

     1 class Solution {
     2     vector<int> ans;
     3 public:
     4     void add(string &s) {
     5         int l = s.length() - 1;
     6         s[l]++;
     7         while (l) {
     8             if (s[l] > '9')
     9                 s[l] = '0', s[l - 1]++;
    10             l--;
    11         }
    12     }
    13     void work(int o) {
    14         string s = "1";
    15         for (int i = 1; i < o; i++)
    16             s += '0';
    17         ans.push_back(stoi(s));
    18         int x = 9 * (int)pow(10, o - 1);
    19         for (int i = 1; i < x; i++)
    20             add(s), ans.push_back(stoi(s));
    21     }
    22     vector<int> printNumbers(int n) {
    23         for (int i = 1; i <= n; i++)
    24             work(i);
    25         return ans;
    26     }
    27 };

    在 Dev-c++ 中编译选项加上了-std=c++11,但依旧不识别 stol 函数,不知道为什么。

    1944. 队列中可以看到的人

    方法:单调栈

     1 class Solution {
     2 public:
     3     vector<int>canSeePersonsCount(vector<int>& a) {
     4         int n = a.size();
     5         vector<int> ans(n);
     6         stack<int> s;
     7         for (int i = n - 1; i >= 0; --i) {
     8             while (!s.empty()) {
     9                 ans[i]++;
    10                 if (a[i] > a[s.top()]) s.pop();
    11                 else break;
    12             }
    13             s.push(i);
    14         }
    15         return ans;
    16     }
    17 };
  • 相关阅读:
    BZOJ 4802 欧拉函数(Pollard_Rho)
    Codeforces 804E The same permutation(构造)
    Codeforces 804D Expected diameter of a tree(树形DP+期望)
    BZOJ 3399 [Usaco2009 Mar]Sand Castle城堡(贪心)
    BZOJ 2430 [Poi2003]Chocolate(贪心+归并排序)
    BZOJ 1707 [Usaco2007 Nov]tanning分配防晒霜(扫描线+贪心+优先队列)
    BZOJ 1828 [Usaco2010 Mar]balloc 农场分配(贪心+线段树)
    BZOJ 1827 [Usaco2010 Mar]gather 奶牛大集会(树形DP)
    BZOJ 2697 特技飞行(贪心)
    BZOJ 4883 [Lydsy2017年5月月赛]棋盘上的守卫(最小生成环套树森林)
  • 原文地址:https://www.cnblogs.com/jinkun113/p/15947018.html
Copyright © 2020-2023  润新知