[朝花夕拾] 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 };

 

posted @ 2022-02-28 18:56  jinkun113  阅读(41)  评论(0编辑  收藏  举报