├── docs ├── _config.yml ├── 0237.md ├── 0104.md ├── 0171.md ├── 0559.md ├── 0461.md ├── 0136.md ├── 0217.md ├── 0242.md ├── 0279.md ├── 0326.md ├── 0024.md ├── 0122.md ├── 0350.md ├── 0112.md ├── 0141.md ├── 0096.md ├── 0538.md ├── 0116.md ├── 0560.md ├── 0070.md ├── 0001.md ├── 0334.md ├── 0387.md ├── 0406.md ├── 0344.md ├── 0190.md ├── 0048.md ├── 0121.md ├── 0412.md ├── 0124.md ├── 0543.md ├── 0337.md ├── 0078.md ├── 0091.md ├── 0014.md ├── 0101.md ├── 0202.md ├── 0108.md ├── 0179.md ├── 0365.md ├── 0268.md ├── 0038.md ├── 0069.md ├── 0134.md ├── 0322.md ├── 0328.md ├── 0443.md ├── 0513.md ├── 0011.md ├── 0378.md ├── 0437.md ├── 0452.md ├── 0384.md ├── 0419.md ├── 0191.md ├── 0198.md ├── 0020.md ├── 0341.md ├── 0429.md ├── 0049.md ├── 0235.md ├── 0019.md ├── 0454.md ├── 0173.md ├── 0239.md ├── 0240.md ├── 0567.md ├── 0169.md ├── 0347.md ├── 0654.md ├── 0022.md ├── 0189.md ├── 0206.md ├── 0118.md ├── 0125.md ├── 0258.md ├── 0039.md ├── 0309.md ├── 0102.md ├── 0150.md ├── 0025.md ├── 0287.md ├── 0071.md ├── 0162.md ├── 0062.md ├── 0450.md ├── 0165.md ├── 0371.md ├── 0234.md ├── 0007.md ├── 0088.md ├── 0283.md ├── 0722.md ├── 0053.md ├── 0312.md ├── 0131.md ├── 0589.md ├── 0050.md ├── 0213.md ├── 0008.md ├── 0590.md ├── 0278.md ├── 0295.md ├── 0650.md ├── 0380.md ├── 0041.md ├── 0238.md ├── 0055.md ├── 0547.md ├── 0221.md ├── 0021.md ├── 0033.md ├── 0017.md ├── 0026.md ├── 0128.md ├── 0075.md ├── 0056.md ├── 0066.md ├── 0166.md └── 0324.md ├── .gitattributes └── src ├── 0326.cpp ├── 0136.cpp ├── 0172.cpp ├── 0191.cpp ├── 0344.cpp ├── 0268.cpp ├── 0171.cpp ├── 0258.cpp ├── 0461.cpp ├── 0371.cpp ├── 0189.cpp ├── 0190.cpp ├── 0217.cpp ├── 0096.cpp ├── 0365.cpp ├── 0160.cpp ├── 0242.cpp ├── 0279.cpp ├── 0070.cpp ├── 0048.cpp ├── 0122.cpp ├── 0198.cpp ├── 0162.cpp ├── 0237.cpp ├── 0001.cpp ├── 0169.cpp ├── 0153.cpp ├── 0560.cpp ├── 0112.cpp ├── 0283.cpp ├── 0350.cpp ├── 0334.cpp ├── 0121.cpp ├── 0416.cpp ├── 0003.cpp ├── 0026.cpp ├── 0053.cpp ├── 0075.cpp ├── 0278.cpp ├── 0406.cpp ├── 0387.cpp ├── 0128.cpp ├── 0204.cpp ├── 0011.cpp ├── 0050.cpp ├── 0088.cpp ├── 0066.cpp ├── 0069.cpp ├── 0287.cpp ├── 0300.cpp ├── 0104.cpp ├── 0168.cpp ├── 0007.cpp ├── 0091.cpp ├── 0062.cpp ├── 0202.cpp ├── 0238.cpp ├── 0322.cpp ├── 0412.cpp ├── 0125.cpp ├── 0078.cpp ├── 0084.cpp ├── 0134.cpp ├── 0139.cpp ├── 0378.cpp ├── 0049.cpp ├── 0179.cpp ├── 0042.cpp ├── 0014.cpp ├── 0046.cpp ├── 0020.cpp ├── 0038.cpp ├── 0206.cpp ├── 0452.cpp ├── 1226.cpp ├── 0239.cpp ├── 0141.cpp ├── 0567.cpp ├── 0031.cpp ├── 0055.cpp ├── 0309.cpp ├── 0419.cpp ├── 0152.cpp ├── 0240.cpp ├── 0347.cpp ├── 0312.cpp ├── 0443.cpp ├── 0021.cpp ├── 0454.cpp ├── 0029.cpp ├── 0041.cpp ├── 0538.cpp ├── 0559.cpp ├── 0354.cpp ├── 0019.cpp ├── 0324.cpp ├── 0543.cpp ├── 0022.cpp ├── 0024.cpp ├── 0094.cpp ├── 0150.cpp ├── 0108.cpp ├── 0124.cpp ├── 0144.cpp ├── 0337.cpp ├── 0044.cpp ├── 0218.cpp ├── 0118.cpp ├── 0098.cpp ├── 0236.cpp ├── 0017.cpp ├── 0056.cpp ├── 0076.cpp ├── 0039.cpp ├── 0033.cpp ├── 0101.cpp ├── 1117.cpp ├── 0071.cpp ├── 0032.cpp ├── 0621.cpp ├── 0072.cpp ├── 0230.cpp ├── 0328.cpp ├── 0165.cpp ├── 0384.cpp ├── 0028.cpp ├── 0207.cpp ├── 0227.cpp ├── 0235.cpp ├── 0437.cpp ├── 0116.cpp ├── 0912.cpp ├── 0215.cpp ├── 0155.cpp ├── 0589.cpp ├── 0145.cpp ├── 0010.cpp ├── 0722.cpp ├── 0590.cpp ├── 0650.cpp ├── 0047.cpp ├── 0174.cpp ├── 0210.cpp ├── 0114.cpp ├── 0131.cpp ├── 0008.cpp ├── 0213.cpp ├── 0034.cpp ├── 0102.cpp ├── 0234.cpp ├── 0166.cpp ├── 0085.cpp ├── 1115.cpp ├── 0004.cpp ├── 0025.cpp ├── 0221.cpp ├── 0005.cpp ├── 1114.cpp ├── 0513.cpp ├── 0429.cpp ├── 0547.cpp ├── 0015.cpp ├── 0054.cpp ├── 0105.cpp ├── 0450.cpp ├── 0146.cpp ├── 0149.cpp ├── 0002.cpp ├── 0138.cpp ├── 0654.cpp ├── 0106.cpp ├── 0173.cpp └── 0148.cpp /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-midnight -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /src/0326.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isPowerOfThree(int n) { return n > 0 && 1162261467 % n == 0; } 4 | }; 5 | -------------------------------------------------------------------------------- /src/0136.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int singleNumber(vector& nums) { 4 | int res = 0; 5 | for (auto& x : nums) { 6 | res ^= x; 7 | } 8 | return res; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/0172.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int trailingZeroes(int n) { 4 | int res = 0; 5 | while (n) { 6 | n /= 5; 7 | res += n; 8 | } 9 | return res; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/0191.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int hammingWeight(uint32_t n) { 4 | int res = 0; 5 | while (n) { 6 | ++res; 7 | n &= n - 1; 8 | } 9 | return res; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/0344.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void reverseString(vector& s) { 4 | int l = 0; 5 | int r = s.size() - 1; 6 | while (l < r) { 7 | swap(s[l++], s[r--]); 8 | } 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/0268.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int missingNumber(vector& nums) { 4 | int n = nums.size(); 5 | n = n * (n + 1) / 2; 6 | return accumulate(nums.begin(), nums.end(), n, minus{}); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/0171.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int titleToNumber(string s) { 4 | int res = 0; 5 | for (auto& x : s) { 6 | res *= 26; 7 | res += x - 'A' + 1; 8 | } 9 | return res; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/0258.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int addDigits(int num) { 4 | if (!num) { 5 | return 0; 6 | } 7 | int res = num % 9; 8 | if (!res) { 9 | return 9; 10 | } 11 | return res; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/0461.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int hammingDistance(int x, int y) { 4 | int t = x ^ y; 5 | int res = 0; 6 | while (t) { 7 | ++res; 8 | t &= t - 1; 9 | } 10 | return res; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /docs/0237.md: -------------------------------------------------------------------------------- 1 | * 因为删除的是非末尾节点,将下一节点的值拷贝到当前节点,再跳过下一节点即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | void deleteNode(ListNode* node) { 7 | node->val = node->next->val; 8 | node->next = node->next->next; 9 | } 10 | }; 11 | ``` 12 | -------------------------------------------------------------------------------- /src/0371.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int getSum(int a, int b) { 4 | int sum = a ^ b; 5 | int carry = static_cast(a & b) << 1; 6 | if (carry) { 7 | return getSum(sum, carry); 8 | } 9 | return sum; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /docs/0104.md: -------------------------------------------------------------------------------- 1 | * 左右子树深度较大者加 1 即为最大深度 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int maxDepth(TreeNode* root) { 7 | if (!root) { 8 | return 0; 9 | } 10 | return max(maxDepth(root->left), maxDepth(root->right)) + 1; 11 | } 12 | }; 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/0171.md: -------------------------------------------------------------------------------- 1 | * 直接遍历字符串即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int titleToNumber(string s) { 7 | int res = 0; 8 | for (auto& x : s) { 9 | res *= 26; 10 | res += x - 'A' + 1; 11 | } 12 | return res; 13 | } 14 | }; 15 | ``` 16 | -------------------------------------------------------------------------------- /src/0189.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void rotate(vector& nums, int k) { 4 | k %= nums.size(); 5 | reverse(nums.begin(), nums.end()); 6 | reverse(nums.begin(), nums.begin() + k); 7 | reverse(nums.begin() + k, nums.end()); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /src/0190.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | uint32_t reverseBits(uint32_t n) { 4 | uint32_t res = 0; 5 | for (int i = 0; i < 31; ++i) { 6 | res += n & 1; 7 | res <<= 1; 8 | n >>= 1; 9 | } 10 | res += n & 1; 11 | return res; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/0217.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool containsDuplicate(vector& nums) { 4 | unordered_set s; 5 | for (auto& x : nums) { 6 | if (s.count(x)) { 7 | return true; 8 | } 9 | s.emplace(x); 10 | } 11 | return false; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /docs/0559.md: -------------------------------------------------------------------------------- 1 | ```cpp 2 | class Solution { 3 | public: 4 | int maxDepth(Node* root) { 5 | if (!root) { 6 | return 0; 7 | } 8 | int res = 1; 9 | for (auto& x : root->children) { 10 | res = max(res, maxDepth(x) + 1); 11 | } 12 | return res; 13 | } 14 | }; 15 | ``` 16 | -------------------------------------------------------------------------------- /src/0096.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numTrees(int n) { 4 | vector dp(n + 1); 5 | dp[0] = 1; 6 | for (int i = 1; i <= n; ++i) { 7 | for (int j = 1; j <= i; ++j) { 8 | dp[i] += dp[j - 1] * dp[i - j]; 9 | } 10 | } 11 | return dp[n]; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/0365.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canMeasureWater(int jug1Capacity, int jug2Capacity, int targetCapacity) { 4 | if (targetCapacity > jug1Capacity + jug2Capacity) { 5 | return false; 6 | } 7 | return targetCapacity % gcd(jug1Capacity, jug2Capacity) == 0; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /src/0160.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 4 | ListNode *a = headA; 5 | ListNode *b = headB; 6 | while (a != b) { 7 | a = a ? a->next : headB; 8 | b = b ? b->next : headA; 9 | } 10 | return a; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /docs/0461.md: -------------------------------------------------------------------------------- 1 | * 计算异或结果的二进制表示中的 1 的个数即可,计算方法参考 #191 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int hammingDistance(int x, int y) { 7 | int t = x ^ y; 8 | int res = 0; 9 | while (t) { 10 | ++res; 11 | t &= t - 1; // 将最低位的 1 改为 0 12 | } 13 | return res; 14 | } 15 | }; 16 | ``` 17 | -------------------------------------------------------------------------------- /src/0242.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isAnagram(string s, string t) { 4 | vector v(26); 5 | for (auto& x : s) { 6 | ++v[x - 'a']; 7 | } 8 | for (auto& x : t) { 9 | --v[x - 'a']; 10 | } 11 | return all_of(v.begin(), v.end(), [](int x) { return !x; }); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/0279.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numSquares(int n) { 4 | vector dp(n + 1, INT_MAX); 5 | dp[0] = 0; 6 | for (int i = 1; i <= n; ++i) { 7 | for (int j = 1; j * j <= i; ++j) { 8 | dp[i] = min(dp[i], dp[i - j * j] + 1); 9 | } 10 | } 11 | return dp[n]; 12 | } 13 | }; -------------------------------------------------------------------------------- /src/0070.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int climbStairs(int n) { 4 | if (n <= 2) { 5 | return n; 6 | } 7 | vector dp(n + 1); 8 | dp[1] = 1; 9 | dp[2] = 2; 10 | for (int i = 3; i <= n; ++i) { 11 | dp[i] = dp[i - 1] + dp[i - 2]; 12 | } 13 | return dp[n]; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/0048.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void rotate(vector>& matrix) { 4 | int sz = matrix.size(); 5 | for (int i = 0; i < sz; ++i) { 6 | for (int j = i + 1; j < sz; ++j) { 7 | swap(matrix[i][j], matrix[j][i]); 8 | } 9 | reverse(matrix[i].begin(), matrix[i].end()); 10 | } 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/0122.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { 4 | if (prices.size() <= 1) { 5 | return 0; 6 | } 7 | vector dp(prices.size()); 8 | for (int i = 1; i < dp.size(); ++i) { 9 | dp[i] = max(dp[i - 1], dp[i - 1] + prices[i] - prices[i - 1]); 10 | } 11 | return dp.back(); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/0198.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int rob(vector& nums) { 4 | if (nums.empty()) { 5 | return 0; 6 | } 7 | vector dp(nums.size() + 1); 8 | dp[1] = nums[0]; 9 | for (int i = 2; i < dp.size(); ++i) { 10 | dp[i] = max(dp[i - 2] + nums[i - 1], dp[i - 1]); 11 | } 12 | return dp[nums.size()]; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /docs/0136.md: -------------------------------------------------------------------------------- 1 | * 两个相同的数异或结果为 0,任何数与 0 异或都是本身 2 | 3 | ``` 4 | x ^ x = 0 5 | 0 ^ x = x 6 | ``` 7 | 8 | * 对数组中所有数异或,出现两次的数异或结果为 0,最终结果即为只出现一次的数 9 | 10 | ```cpp 11 | class Solution { 12 | public: 13 | int singleNumber(vector& nums) { 14 | int res = 0; 15 | for (auto& x : nums) { 16 | res ^= x; 17 | } 18 | return res; 19 | } 20 | }; 21 | ``` 22 | -------------------------------------------------------------------------------- /src/0162.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findPeakElement(vector& nums) { 4 | int l = 0; 5 | int r = nums.size(); 6 | while (l < r) { 7 | int m = l + (r - l) / 2; 8 | if (m > 0 && nums[m] < nums[m - 1]) { 9 | r = m; 10 | } else { 11 | l = m + 1; 12 | } 13 | } 14 | return l - 1; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /src/0237.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | void deleteNode(ListNode* node) { 12 | node->val = node->next->val; 13 | node->next = node->next->next; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /docs/0217.md: -------------------------------------------------------------------------------- 1 | * 用哈希表保存已遍历元素,遍历时发现元素已存在哈希表中则说明有重复元素,时间复杂度 `O(n)` 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool containsDuplicate(vector& nums) { 7 | unordered_set s; 8 | for (auto& x : nums) { 9 | if (s.count(x)) { 10 | return true; 11 | } 12 | s.emplace(x); 13 | } 14 | return false; 15 | } 16 | }; 17 | ``` 18 | -------------------------------------------------------------------------------- /src/0001.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector twoSum(vector& nums, int target) { 4 | unordered_map m; 5 | for (int i = 0; i < nums.size(); ++i) { 6 | int t = target - nums[i]; 7 | if (m.count(t)) { 8 | return {i, m[t]}; 9 | } 10 | m.emplace(nums[i], i); 11 | } 12 | return {-1, -1}; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /src/0169.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int majorityElement(vector& nums) { 4 | int cnt = 0; 5 | int res = INT_MIN; 6 | for (auto& x : nums) { 7 | if (cnt == 0) { 8 | res = x; 9 | } 10 | if (res == x) { 11 | ++cnt; 12 | } else { 13 | --cnt; 14 | } 15 | } 16 | return res; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/0153.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findMin(vector& nums) { 4 | int l = 1; 5 | int r = nums.size(); 6 | while (l < r) { 7 | int m = l + (r - l) / 2; 8 | if (nums[m] < nums[0]) { 9 | r = m; 10 | } else { 11 | l = m + 1; 12 | } 13 | } 14 | return l != nums.size() ? nums[l] : nums[0]; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /src/0560.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int subarraySum(vector& nums, int k) { 4 | int res = 0; 5 | int sum = 0; 6 | unordered_map m; 7 | m[0] = 1; 8 | for (auto& x : nums) { 9 | sum += x; 10 | if (m.count(sum - k)) { 11 | res += m[sum - k]; 12 | } 13 | ++m[sum]; 14 | } 15 | return res; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /docs/0242.md: -------------------------------------------------------------------------------- 1 | * 计算两个字符串每个字符的数量,如果所有字符数量都相等则是异位词 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool isAnagram(string s, string t) { 7 | vector v(26); 8 | for (auto& x : s) { 9 | ++v[x - 'a']; 10 | } 11 | for (auto& x : t) { 12 | --v[x - 'a']; 13 | } 14 | return all_of(v.begin(), v.end(), [](int x) { return !x; }); 15 | } 16 | }; 17 | ``` 18 | -------------------------------------------------------------------------------- /src/0112.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool hasPathSum(TreeNode* root, int targetSum) { 4 | if (!root) { 5 | return false; 6 | } 7 | if (!root->left && !root->right) { 8 | return root->val == targetSum; 9 | } 10 | return hasPathSum(root->left, targetSum - root->val) || 11 | hasPathSum(root->right, targetSum - root->val); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/0283.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void moveZeroes(vector& nums) { 4 | int l = 0; 5 | int cur = 0; 6 | while (cur < nums.size()) { 7 | if (nums[cur] == 0) { 8 | ++cur; 9 | } else { 10 | nums[l++] = nums[cur++]; 11 | } 12 | } 13 | for (int i = l; i < nums.size(); ++i) { 14 | nums[i] = 0; 15 | } 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/0350.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector intersect(vector& nums1, vector& nums2) { 4 | unordered_map m; 5 | for (auto& x : nums1) { 6 | ++m[x]; 7 | } 8 | vector res; 9 | for (auto& x : nums2) { 10 | if (--m[x] >= 0) { 11 | res.emplace_back(x); 12 | } 13 | } 14 | return res; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /docs/0279.md: -------------------------------------------------------------------------------- 1 | * 动态规划,`dp[i]` 表示和为 `i` 的完全平方数的最少数量 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int numSquares(int n) { 7 | vector dp(n + 1, INT_MAX); 8 | dp[0] = 0; 9 | for (int i = 1; i <= n; ++i) { 10 | for (int j = 1; j * j <= i; ++j) { 11 | dp[i] = min(dp[i], dp[i - j * j] + 1); 12 | } 13 | } 14 | return dp[n]; 15 | } 16 | }; 17 | ``` 18 | -------------------------------------------------------------------------------- /src/0334.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool increasingTriplet(vector& nums) { 4 | int small = INT_MAX; 5 | int mid = INT_MAX; 6 | for (auto& x : nums) { 7 | if (x <= small) { 8 | small = x; 9 | } else if (x <= mid) { 10 | mid = x; 11 | } else { 12 | return true; 13 | } 14 | } 15 | return false; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/0121.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { 4 | if (prices.size() <= 1) { 5 | return 0; 6 | } 7 | vector dp(prices.size()); 8 | int res = 0; 9 | for (int i = 1; i < dp.size(); ++i) { 10 | dp[i] = max(dp[i - 1] + prices[i] - prices[i - 1], 0); 11 | res = max(res, dp[i]); 12 | } 13 | return res; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/0416.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canPartition(vector& nums) { 4 | if (nums.size() < 2) { 5 | return false; 6 | } 7 | int n = accumulate(nums.begin(), nums.end(), 0); 8 | if (n % 2 & 1) { 9 | return false; 10 | } 11 | bitset<10001> b{1}; 12 | for (auto& x : nums) { 13 | b |= (b << x); 14 | } 15 | return b[n / 2]; 16 | } 17 | }; -------------------------------------------------------------------------------- /src/0003.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int lengthOfLongestSubstring(string s) { 4 | int res = 0; 5 | int l = 0; 6 | for (int r = 0; r < s.size(); ++r) { 7 | for (int i = l; i < r; ++i) { 8 | if (s[i] == s[r]) { 9 | l = i + 1; 10 | break; 11 | } 12 | } 13 | res = max(res, r - l + 1); 14 | } 15 | return res; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/0026.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeDuplicates(vector& nums) { 4 | if (nums.empty()) { 5 | return 0; 6 | } 7 | int l = 0; 8 | for (int r = 1; r < nums.size(); ++r) { 9 | if (nums[l] != nums[r]) { 10 | ++l; 11 | if (l < r) { 12 | nums[l] = nums[r]; 13 | } 14 | } 15 | } 16 | return l + 1; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/0053.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxSubArray(vector& nums) { 4 | if (nums.empty()) { 5 | return 0; 6 | } 7 | vector dp(nums.size()); 8 | dp[0] = nums[0]; 9 | int res = dp[0]; 10 | for (int i = 1; i < dp.size(); ++i) { 11 | dp[i] = max(nums[i], dp[i - 1] + nums[i]); 12 | res = max(res, dp[i]); 13 | } 14 | return res; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /docs/0326.md: -------------------------------------------------------------------------------- 1 | * 检查能否整除 int 范围内能被 3 整除的最大数即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool isPowerOfThree(int n) { 7 | int t = pow(3, static_cast(log(INT_MAX) / log(3))); 8 | return n > 0 && t % n == 0; 9 | } 10 | }; 11 | ``` 12 | 13 | * 硬编码该值 14 | 15 | ```cpp 16 | class Solution { 17 | public: 18 | bool isPowerOfThree(int n) { return n > 0 && 1162261467 % n == 0; } 19 | }; 20 | ``` 21 | -------------------------------------------------------------------------------- /src/0075.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void sortColors(vector& nums) { 4 | int cur = 0; 5 | int l = 0; 6 | int r = nums.size(); 7 | while (cur < r) { 8 | if (nums[cur] == 0) { 9 | swap(nums[cur++], nums[l++]); 10 | } else if (nums[cur] == 2) { 11 | swap(nums[cur], nums[--r]); 12 | } else { 13 | ++cur; 14 | } 15 | } 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/0278.cpp: -------------------------------------------------------------------------------- 1 | // Forward declaration of isBadVersion API. 2 | bool isBadVersion(int version); 3 | 4 | class Solution { 5 | public: 6 | int firstBadVersion(int n) { 7 | int l = 1; 8 | int r = n; 9 | while (l <= r) { 10 | int m = l + (r - l) / 2; 11 | if (isBadVersion(m)) { 12 | r = m - 1; 13 | } else { 14 | l = m + 1; 15 | } 16 | } 17 | return l; 18 | } 19 | }; -------------------------------------------------------------------------------- /src/0406.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> reconstructQueue(vector>& people) { 4 | sort(people.begin(), people.end(), [](vector& x, vector& y) { 5 | return tie(y[0], x[1]) < tie(x[0], y[1]); 6 | }); 7 | vector> res; 8 | for (auto& x : people) { 9 | res.emplace(res.begin() + x[1], x); 10 | } 11 | return res; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /docs/0024.md: -------------------------------------------------------------------------------- 1 | * 交换头两个节点,接着递归处理后续节点 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | ListNode* swapPairs(ListNode* head) { 7 | if (!head || !head->next) { 8 | return head; 9 | } 10 | ListNode* second_node = head->next; 11 | ListNode* third_node = second_node->next; 12 | second_node->next = head; 13 | head->next = swapPairs(third_node); 14 | return second_node; 15 | } 16 | }; 17 | ``` 18 | -------------------------------------------------------------------------------- /src/0387.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int firstUniqChar(string s) { 4 | vector v(26); 5 | for (auto& x : s) { 6 | ++v[x - 'a']; 7 | } 8 | int res = INT_MAX; 9 | for (int i = 0; i < v.size(); ++i) { 10 | if (v[i] == 1) { 11 | int pos = s.find(i + 'a'); 12 | res = min(res, pos); 13 | } 14 | } 15 | return res == INT_MAX ? -1 : res; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /docs/0122.md: -------------------------------------------------------------------------------- 1 | * 动态规划,`dp[i]` 表示第 `i + 1` 天可获得的最大利润 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int maxProfit(vector& prices) { 7 | if (prices.size() <= 1) { 8 | return 0; 9 | } 10 | vector dp(prices.size()); 11 | for (int i = 1; i < dp.size(); ++i) { 12 | dp[i] = max(dp[i - 1], dp[i - 1] + prices[i] - prices[i - 1]); 13 | } 14 | return dp.back(); 15 | } 16 | }; 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/0350.md: -------------------------------------------------------------------------------- 1 | * 用哈希表计数即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector intersect(vector& nums1, vector& nums2) { 7 | unordered_map m; 8 | for (auto& x : nums1) { 9 | ++m[x]; 10 | } 11 | vector res; 12 | for (auto& x : nums2) { 13 | if (--m[x] >= 0) { 14 | res.emplace_back(x); 15 | } 16 | } 17 | return res; 18 | } 19 | }; 20 | ``` 21 | -------------------------------------------------------------------------------- /src/0128.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int longestConsecutive(vector& nums) { 4 | unordered_set s(nums.begin(), nums.end()); 5 | int res = 0; 6 | for (auto& x : nums) { 7 | if (!s.count(x - 1)) { 8 | int cnt = 1; 9 | while (s.count(x + cnt)) { 10 | ++cnt; 11 | } 12 | res = max(res, cnt); 13 | } 14 | } 15 | return res; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/0204.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int countPrimes(int n) { 4 | if (n <= 2) { 5 | return 0; 6 | } 7 | vector isPrime(n, true); 8 | int cnt = 0; 9 | for (int i = 2; i < n; ++i) { 10 | if (isPrime[i]) { 11 | ++cnt; 12 | for (int j = i + i; j < n; j += i) { 13 | isPrime[j] = false; 14 | } 15 | } 16 | } 17 | return cnt; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /docs/0112.md: -------------------------------------------------------------------------------- 1 | * 递归往子节点查找即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool hasPathSum(TreeNode* root, int targetSum) { 7 | if (!root) { 8 | return false; 9 | } 10 | if (!root->left && !root->right) { 11 | return root->val == targetSum; 12 | } 13 | return hasPathSum(root->left, targetSum - root->val) || 14 | hasPathSum(root->right, targetSum - root->val); 15 | } 16 | }; 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/0141.md: -------------------------------------------------------------------------------- 1 | * 使用两个指针,快指针一次移动两步,慢指针一次移动一步,若链表有环,则二者必将相遇 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool hasCycle(ListNode* head) { 7 | ListNode* slow = head; 8 | ListNode* fast = head; 9 | while (fast && fast->next) { 10 | slow = slow->next; 11 | fast = fast->next->next; 12 | if (slow == fast) { 13 | return true; 14 | } 15 | } 16 | return false; 17 | } 18 | }; 19 | ``` 20 | -------------------------------------------------------------------------------- /src/0011.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxArea(vector& height) { 4 | int res = 0; 5 | int l = 0; 6 | int r = height.size() - 1; 7 | while (l != r) { 8 | if (height[l] < height[r]) { 9 | res = max(res, (r - l) * height[l]); 10 | ++l; 11 | } else { 12 | res = max(res, (r - l) * height[r]); 13 | --r; 14 | } 15 | } 16 | return res; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/0050.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | double myPow(double x, int n) { 4 | double t = 1; 5 | if (n < 0) { 6 | x = 1 / x; 7 | t = x; 8 | n = -(n + 1); 9 | } 10 | return t * helper(x, n); 11 | } 12 | 13 | double helper(double x, int n) { 14 | if (!n) { 15 | return 1.0; 16 | } 17 | double t = helper(x, n / 2); 18 | return n % 2 & 1 ? t * t * x : t * t; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /src/0088.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void merge(vector& nums1, int m, vector& nums2, int n) { 4 | while (m && n) { 5 | if (nums1[m - 1] > nums2[n - 1]) { 6 | nums1[m + n - 1] = nums1[m - 1]; 7 | --m; 8 | } else { 9 | nums1[m + n - 1] = nums2[n - 1]; 10 | --n; 11 | } 12 | } 13 | while (n--) { 14 | nums1[n] = nums2[n]; 15 | } 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /docs/0096.md: -------------------------------------------------------------------------------- 1 | * 动态规划,`dp[i]` 表示 `i` 个数可以组成的二叉搜索树数量。分别以 `i` 个数的每个数为根节点,每个数为根节点的组合数为其左子树和右子树的组合之积,所有的情况之和即为 `i` 个数的组合数 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int numTrees(int n) { 7 | vector dp(n + 1); 8 | dp[0] = 1; 9 | for (int i = 1; i <= n; ++i) { 10 | for (int j = 1; j <= i; ++j) { 11 | dp[i] += dp[j - 1] * dp[i - j]; 12 | } 13 | } 14 | return dp[n]; 15 | } 16 | }; 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/0538.md: -------------------------------------------------------------------------------- 1 | * 记录每个节点前的累加值,遍历时加上即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | TreeNode* convertBST(TreeNode* root) { 7 | int pre = 0; 8 | dfs(root, pre); 9 | return root; 10 | } 11 | 12 | void dfs(TreeNode* root, int& pre) { 13 | if (!root) { 14 | return; 15 | } 16 | dfs(root->right, pre); 17 | root->val += pre; 18 | pre = root->val; 19 | dfs(root->left, pre); 20 | } 21 | }; 22 | ``` 23 | -------------------------------------------------------------------------------- /src/0066.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector plusOne(vector& digits) { 4 | int carry = 1; 5 | for (auto it = digits.rbegin(); it != digits.rend(); ++it) { 6 | if (!carry) { 7 | break; 8 | } 9 | *it += carry; 10 | carry = *it / 10; 11 | *it %= 10; 12 | } 13 | if (carry) { 14 | digits.emplace(digits.begin(), carry); 15 | } 16 | return digits; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/0069.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int mySqrt(int x) { 4 | if (x <= 1) { 5 | return x; 6 | } 7 | int l = 1; 8 | int r = x; 9 | while (l < r) { 10 | int m = l + (r - l) / 2; 11 | int t = x / m; 12 | if (m == t) { 13 | return m; 14 | } else if (m > t) { 15 | r = m; 16 | } else { 17 | l = m + 1; 18 | } 19 | } 20 | return l - 1; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/0287.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findDuplicate(vector& nums) { 4 | int slow = 0; 5 | int fast = 0; 6 | while (true) { 7 | slow = nums[slow]; 8 | fast = nums[nums[fast]]; 9 | if (slow == fast) { 10 | break; 11 | } 12 | } 13 | fast = 0; 14 | while (slow != fast) { 15 | slow = nums[slow]; 16 | fast = nums[fast]; 17 | } 18 | return slow; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /src/0300.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int lengthOfLIS(vector& nums) { 4 | if (nums.empty()) { 5 | return 0; 6 | } 7 | vector v{nums[0]}; 8 | for (int i = 1; i < nums.size(); ++i) { 9 | if (nums[i] > v.back()) { 10 | v.emplace_back(nums[i]); 11 | } else { 12 | *lower_bound(v.begin(), v.end(), nums[i]) = nums[i]; 13 | } 14 | } 15 | return v.size(); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /docs/0116.md: -------------------------------------------------------------------------------- 1 | * 左节点的下一节点是右节点,右节点的下一节点是其父节点的下一节点的左节点,以此规律递归即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | Node* connect(Node* root) { 7 | if (!root) { 8 | return nullptr; 9 | } 10 | if (root->left) { 11 | root->left->next = root->right; 12 | if (root->next) root->right->next = root->next->left; 13 | } 14 | connect(root->left); 15 | connect(root->right); 16 | return root; 17 | } 18 | }; 19 | ``` 20 | -------------------------------------------------------------------------------- /src/0104.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int maxDepth(TreeNode* root) { 13 | if (!root) { 14 | return 0; 15 | } 16 | return max(maxDepth(root->left), maxDepth(root->right)) + 1; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/0168.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string convertToTitle(int columnNumber) { 4 | string res; 5 | while (columnNumber) { 6 | int t = columnNumber % 26; 7 | if (!t) { 8 | res.insert(res.begin(), 'Z'); 9 | columnNumber = columnNumber / 26 - 1; 10 | } else { 11 | res.insert(res.begin(), 'A' + t - 1); 12 | columnNumber /= 26; 13 | } 14 | } 15 | return res; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /docs/0560.md: -------------------------------------------------------------------------------- 1 | * 记录每个位置的前缀和,如果两个位置之间的元素和为 `k`,则这两个位置的前缀和之差为 `k` 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int subarraySum(vector& nums, int k) { 7 | int res = 0; 8 | int sum = 0; 9 | unordered_map m; 10 | m[0] = 1; 11 | for (auto& x : nums) { 12 | sum += x; 13 | if (m.count(sum - k)) { 14 | res += m[sum - k]; 15 | } 16 | ++m[sum]; 17 | } 18 | return res; 19 | } 20 | }; 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/0070.md: -------------------------------------------------------------------------------- 1 | * 动态规划,`dp[i]` 表示爬到 `i` 阶的方法数,爬到 `i` 阶之前必然先爬到 `i - 1` 或 `i - 2` 阶,因此爬到 `i` 阶的方法数就是爬到 `i - 1` 阶和 `i - 2` 阶的方法数之和 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int climbStairs(int n) { 7 | if (n <= 2) { 8 | return n; 9 | } 10 | vector dp(n + 1); 11 | dp[1] = 1; 12 | dp[2] = 2; 13 | for (int i = 3; i <= n; ++i) { 14 | dp[i] = dp[i - 1] + dp[i - 2]; 15 | } 16 | return dp[n]; 17 | } 18 | }; 19 | ``` 20 | -------------------------------------------------------------------------------- /src/0007.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int reverse(int x) { 4 | int res = 0; 5 | while (x) { 6 | int t = x % 10; 7 | if (res > INT_MAX / 10 || (res == INT_MAX / 10 && t > (INT_MAX % 10))) { 8 | return 0; 9 | } 10 | if (res < INT_MIN / 10 || (res == INT_MIN / 10 && t < (INT_MIN % 10))) { 11 | return 0; 12 | } 13 | res = res * 10 + t; 14 | x /= 10; 15 | } 16 | return res; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /docs/0001.md: -------------------------------------------------------------------------------- 1 | * 用哈希表保存已访问过元素的下标(题目已说明无重复元素),只需要遍历一遍,时间复杂度为 `O(n)`,空间复杂度为 `O(n)` 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector twoSum(vector& nums, int target) { 7 | unordered_map m; 8 | for (int i = 0; i < nums.size(); ++i) { 9 | int t = target - nums[i]; 10 | if (m.count(t)) { 11 | return {i, m[t]}; 12 | } 13 | m.emplace(nums[i], i); 14 | } 15 | return {-1, -1}; 16 | } 17 | }; 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/0334.md: -------------------------------------------------------------------------------- 1 | * 遍历数组,用两个临时变量缓存连续递增的数,只要连续缓存了三个递增数则说明有满足条件的递增序列 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool increasingTriplet(vector& nums) { 7 | int small = INT_MAX; 8 | int mid = INT_MAX; 9 | for (auto& x : nums) { 10 | if (x <= small) { 11 | small = x; 12 | } else if (x <= mid) { 13 | mid = x; 14 | } else { 15 | return true; 16 | } 17 | } 18 | return false; 19 | } 20 | }; 21 | ``` 22 | -------------------------------------------------------------------------------- /src/0091.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numDecodings(string s) { 4 | if (s.empty() || s[0] == '0') { 5 | return 0; 6 | } 7 | vector dp(s.size()); 8 | dp[0] = 1; 9 | for (int i = 1; i < dp.size(); ++i) { 10 | dp[i] = s[i] == '0' ? 0 : dp[i - 1]; 11 | if (s[i - 1] == '1' || (s[i - 1] == '2' && s[i] <= '6')) { 12 | dp[i] += i >= 2 ? dp[i - 2] : 1; 13 | } 14 | } 15 | return dp.back(); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/0062.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int uniquePaths(int m, int n) { 4 | vector> dp(m, vector(n)); 5 | for (int i = 0; i < n; ++i) { 6 | dp[0][i] = 1; 7 | } 8 | for (int i = 0; i < m; ++i) { 9 | dp[i][0] = 1; 10 | } 11 | for (int i = 1; i < m; ++i) { 12 | for (int j = 1; j < n; ++j) { 13 | dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; 14 | } 15 | } 16 | return dp[m - 1][n - 1]; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/0202.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isHappy(int n) { 4 | unordered_set s; 5 | while (n != 1) { 6 | n = helper(n); 7 | if (s.count(n)) { 8 | return false; 9 | } 10 | s.emplace(n); 11 | } 12 | return true; 13 | } 14 | 15 | int helper(int n) { 16 | int sum = 0; 17 | while (n) { 18 | int t = n % 10; 19 | sum += t * t; 20 | n /= 10; 21 | } 22 | return sum; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /src/0238.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector productExceptSelf(vector& nums) { 4 | int n = nums.size(); 5 | vector l(n, 1); 6 | vector r(n, 1); 7 | for (int i = 1; i < n; ++i) { 8 | l[i] = l[i - 1] * nums[i - 1]; 9 | } 10 | for (int i = n - 2; i >= 0; --i) { 11 | r[i] = r[i + 1] * nums[i + 1]; 12 | } 13 | for (int i = 0; i < n; ++i) { 14 | l[i] *= r[i]; 15 | } 16 | return l; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /docs/0387.md: -------------------------------------------------------------------------------- 1 | * 计数每个字符出现次数,出现次数为 1 的最前字符即为结果 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int firstUniqChar(string s) { 7 | vector v(26); 8 | for (auto& x : s) { 9 | ++v[x - 'a']; 10 | } 11 | int res = INT_MAX; 12 | for (int i = 0; i < v.size(); ++i) { 13 | if (v[i] == 1) { 14 | int pos = s.find(i + 'a'); 15 | res = min(res, pos); 16 | } 17 | } 18 | return res == INT_MAX ? -1 : res; 19 | } 20 | }; 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/0406.md: -------------------------------------------------------------------------------- 1 | * 把身高高的先排好位置,这样之后把身高低的插入到前面不会影响计数 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector> reconstructQueue(vector>& people) { 7 | sort(people.begin(), people.end(), [](vector& x, vector& y) { 8 | return tie(y[0], x[1]) < tie(x[0], y[1]); 9 | }); 10 | vector> res; 11 | for (auto& x : people) { 12 | res.emplace(res.begin() + x[1], x); 13 | } 14 | return res; 15 | } 16 | }; 17 | ``` 18 | -------------------------------------------------------------------------------- /src/0322.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int coinChange(vector& coins, int amount) { 4 | if (coins.empty()) { 5 | return -1; 6 | } 7 | vector dp(amount + 1, amount + 1); 8 | dp[0] = 0; 9 | for (int i = 1; i <= amount; ++i) { 10 | for (auto& x : coins) { 11 | if (i >= x) { 12 | dp[i] = min(dp[i], dp[i - x] + 1); 13 | } 14 | } 15 | } 16 | return dp[amount] == amount + 1 ? -1 : dp[amount]; 17 | } 18 | }; -------------------------------------------------------------------------------- /src/0412.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector fizzBuzz(int n) { 4 | vector res; 5 | for (int i = 1; i <= n; ++i) { 6 | if (i % 15 == 0) { 7 | res.emplace_back("FizzBuzz"); 8 | } else if (i % 3 == 0) { 9 | res.emplace_back("Fizz"); 10 | } else if (i % 5 == 0) { 11 | res.emplace_back("Buzz"); 12 | } else { 13 | res.emplace_back(to_string(i)); 14 | } 15 | } 16 | return res; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/0125.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isPalindrome(string s) { 4 | int l = 0; 5 | int r = s.size() - 1; 6 | while (l < r) { 7 | while (l < r && !isalnum(s[l])) { 8 | ++l; 9 | } 10 | while (l < r && !isalnum(s[r])) { 11 | --r; 12 | } 13 | if (toupper(s[l]) == toupper(s[r])) { 14 | ++l; 15 | --r; 16 | } else { 17 | return false; 18 | } 19 | } 20 | return true; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /docs/0344.md: -------------------------------------------------------------------------------- 1 | * 这就是 [std::reverse](https://en.cppreference.com/w/cpp/algorithm/reverse) 的功能 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | void reverseString(vector& s) { reverse(s.begin(), s.end()); } 7 | }; 8 | ``` 9 | 10 | * 不使用 STL 的解法如下 11 | 12 | ```cpp 13 | class Solution { 14 | public: 15 | void reverseString(vector& s) { 16 | int l = 0; 17 | int r = s.size() - 1; 18 | while (l < r) { 19 | swap(s[l++], s[r--]); 20 | } 21 | } 22 | }; 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/0190.md: -------------------------------------------------------------------------------- 1 | * 一个数和 1 与运算的结果即为其二进制最低位 2 | 3 | ``` 4 | 10110 & 1 = 0 5 | 1011 & 1 = 1 6 | 101 & 1 = 1 7 | 10 & 1 = 0 8 | 1 & 1 = 1 9 | 10 | 将低位放在前,01101即为翻转结果 11 | ``` 12 | 13 | * 实现如下 14 | 15 | ```cpp 16 | class Solution { 17 | public: 18 | uint32_t reverseBits(uint32_t n) { 19 | uint32_t res = 0; 20 | for (int i = 0; i < 31; ++i) { 21 | res += n & 1; 22 | res <<= 1; 23 | n >>= 1; 24 | } 25 | res += n & 1; 26 | return res; 27 | } 28 | }; 29 | ``` 30 | -------------------------------------------------------------------------------- /src/0078.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> subsets(vector& nums) { 4 | vector> res; 5 | vector t; 6 | dfs(res, t, nums, 0); 7 | return res; 8 | } 9 | 10 | void dfs(vector>& res, vector& t, vector& nums, int n) { 11 | res.emplace_back(t); 12 | for (int i = n; i < nums.size(); ++i) { 13 | t.emplace_back(nums[i]); 14 | dfs(res, t, nums, i + 1); 15 | t.pop_back(); 16 | } 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/0084.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int largestRectangleArea(vector& heights) { 4 | heights.emplace_back(0); 5 | stack s; 6 | int res = 0; 7 | for (int i = 0; i < heights.size(); ++i) { 8 | while (!s.empty() && heights[i] < heights[s.top()]) { 9 | int t = s.top(); 10 | s.pop(); 11 | res = max(res, heights[t] * (s.empty() ? i : (i - s.top() - 1))); 12 | } 13 | s.emplace(i); 14 | } 15 | return res; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /docs/0048.md: -------------------------------------------------------------------------------- 1 | * 交换对角线元素,再翻转每一行即可 2 | 3 | ``` 4 | 123 147 741 5 | 456 => 258 => 852 6 | 789 369 963 7 | ``` 8 | 9 | * 实现如下 10 | 11 | ```cpp 12 | class Solution { 13 | public: 14 | void rotate(vector>& matrix) { 15 | int sz = matrix.size(); 16 | for (int i = 0; i < sz; ++i) { 17 | for (int j = i + 1; j < sz; ++j) { 18 | swap(matrix[i][j], matrix[j][i]); 19 | } 20 | reverse(matrix[i].begin(), matrix[i].end()); 21 | } 22 | } 23 | }; 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/0121.md: -------------------------------------------------------------------------------- 1 | * 动态规划,除非利润为负,否则必须有一次买入卖出,`dp[i]` 表示第 `i + 1` 天卖出可获得的最大利润,如果最大利润为负,则无买入卖出 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int maxProfit(vector& prices) { 7 | if (prices.size() <= 1) { 8 | return 0; 9 | } 10 | vector dp(prices.size()); 11 | int res = 0; 12 | for (int i = 1; i < dp.size(); ++i) { 13 | dp[i] = max(dp[i - 1] + prices[i] - prices[i - 1], 0); 14 | res = max(res, dp[i]); 15 | } 16 | return res; 17 | } 18 | }; 19 | ``` 20 | -------------------------------------------------------------------------------- /src/0134.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int canCompleteCircuit(vector& gas, vector& cost) { 4 | int res = 0; 5 | int mn = INT_MAX; 6 | int x = 0; 7 | for (int i = 0; i < gas.size(); ++i) { 8 | x += gas[i] - cost[i]; 9 | if (x < mn) { 10 | mn = x; 11 | res = i; 12 | } 13 | } 14 | if (x < 0) { 15 | return -1; 16 | } 17 | if (res == gas.size() - 1) { 18 | return 0; 19 | } 20 | return res + 1; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /docs/0412.md: -------------------------------------------------------------------------------- 1 | ```cpp 2 | class Solution { 3 | public: 4 | vector fizzBuzz(int n) { 5 | vector res; 6 | for (int i = 1; i <= n; ++i) { 7 | if (i % 15 == 0) { 8 | res.emplace_back("FizzBuzz"); 9 | } else if (i % 3 == 0) { 10 | res.emplace_back("Fizz"); 11 | } else if (i % 5 == 0) { 12 | res.emplace_back("Buzz"); 13 | } else { 14 | res.emplace_back(to_string(i)); 15 | } 16 | } 17 | return res; 18 | } 19 | }; 20 | ``` 21 | -------------------------------------------------------------------------------- /src/0139.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool wordBreak(string s, vector& wordDict) { 4 | unordered_set wordSet{wordDict.begin(), wordDict.end()}; 5 | vector dp(s.size() + 1); 6 | dp[0] = true; 7 | for (int i = 1; i < dp.size(); ++i) { 8 | for (int j = 0; j < i; ++j) { 9 | if (dp[j] && wordSet.count(s.substr(j, i - j))) { 10 | dp[i] = true; 11 | break; 12 | } 13 | } 14 | } 15 | return dp.back(); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/0378.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int kthSmallest(vector>& matrix, int k) { 4 | int l = matrix[0][0]; 5 | int r = matrix.back().back(); 6 | while (l < r) { 7 | int m = l + (r - l) / 2; 8 | int cnt = 0; 9 | for (auto& x : matrix) { 10 | cnt += upper_bound(x.begin(), x.end(), m) - x.begin(); 11 | } 12 | if (k <= cnt) { 13 | r = m; 14 | } else { 15 | l = m + 1; 16 | } 17 | } 18 | return l; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /docs/0124.md: -------------------------------------------------------------------------------- 1 | * 遍历每个节点,计算该节点到叶子节点的最长路径和,在此过程中记录最大的总路径和 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int maxPathSum(TreeNode* root) { 7 | int res = INT_MIN; 8 | dfs(root, res); 9 | return res; 10 | } 11 | 12 | int dfs(TreeNode* root, int& res) { 13 | if (!root) { 14 | return 0; 15 | } 16 | int l = max(dfs(root->left, res), 0); 17 | int r = max(dfs(root->right, res), 0); 18 | res = max(res, l + r + root->val); 19 | return root->val + max(l, r); 20 | } 21 | }; 22 | ``` 23 | -------------------------------------------------------------------------------- /src/0049.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> groupAnagrams(vector& strs) { 4 | vector> res; 5 | unordered_map m; 6 | int i = -1; 7 | for (auto& x : strs) { 8 | string t{x}; 9 | sort(t.begin(), t.end()); 10 | if (!m.count(t)) { 11 | res.emplace_back(vector{x}); 12 | m.emplace(t, ++i); 13 | } else { 14 | res[m[t]].emplace_back(x); 15 | } 16 | } 17 | return res; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/0179.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string largestNumber(vector& nums) { 4 | if (all_of(nums.begin(), nums.end(), [](int x) { return !x; })) { 5 | return "0"; 6 | } 7 | vector v; 8 | transform(nums.begin(), nums.end(), back_inserter(v), 9 | [](int x) { return to_string(x); }); 10 | sort(v.begin(), v.end(), 11 | [](const string& x, const string& y) { return y + x < x + y; }); 12 | return accumulate(v.begin(), v.end(), string{""}); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /src/0042.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int trap(vector& height) { 4 | int sz = height.size(); 5 | vector l(sz); 6 | vector r(sz); 7 | for (int i = 1; i < sz; ++i) { 8 | l[i] = max(l[i - 1], height[i - 1]); 9 | } 10 | for (int i = sz - 2; i >= 0; --i) { 11 | r[i] = max(r[i + 1], height[i + 1]); 12 | } 13 | int res = 0; 14 | for (int i = 0; i < sz; i++) { 15 | res += max(0, min(l[i], r[i]) - height[i]); 16 | } 17 | return res; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /docs/0543.md: -------------------------------------------------------------------------------- 1 | * 经过某个根节点的最大直径为 `左子树深度 + 右子树深度 + 1 - 1`(题目定义的直径比路径长度少 1),遍历所有节点的直径,最大的即为结果 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int diameterOfBinaryTree(TreeNode* root) { 7 | int res = 0; 8 | depth(root, res); 9 | return res; 10 | } 11 | 12 | int depth(TreeNode* root, int& res) { 13 | if (!root) { 14 | return 0; 15 | } 16 | int l = depth(root->left, res); 17 | int r = depth(root->right, res); 18 | res = max(res, l + r); 19 | return 1 + max(l, r); 20 | } 21 | }; 22 | ``` 23 | -------------------------------------------------------------------------------- /src/0014.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string longestCommonPrefix(vector& strs) { 4 | if (strs.empty()) { 5 | return ""; 6 | } 7 | string s{strs[0]}; 8 | for (int i = 1; i < strs.size(); ++i) { 9 | const string& x = strs[i]; 10 | int cur = 0; 11 | while (s[cur] == x[cur]) { 12 | ++cur; 13 | if (cur == s.size() || cur == x.size()) { 14 | break; 15 | } 16 | } 17 | s = s.substr(0, cur); 18 | } 19 | return s; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/0046.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> permute(vector& nums) { 4 | vector> res; 5 | dfs(res, nums, 0); 6 | return res; 7 | } 8 | 9 | void dfs(vector>& res, vector& nums, int n) { 10 | if (n == nums.size()) { 11 | res.emplace_back(nums); 12 | return; 13 | } 14 | for (int i = n; i < nums.size(); ++i) { 15 | swap(nums[i], nums[n]); 16 | dfs(res, nums, n + 1); 17 | swap(nums[i], nums[n]); 18 | } 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /docs/0337.md: -------------------------------------------------------------------------------- 1 | * 存储包含根节点和不包含根节点两种状态能获取的最大收益 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int rob(TreeNode* root) { 7 | auto [a, b] = dfs(root); 8 | return max(a, b); 9 | } 10 | 11 | pair dfs(TreeNode* root) { 12 | if (!root) { 13 | return {0, 0}; 14 | } 15 | auto [l1, l2] = dfs(root->left); 16 | auto [r1, r2] = dfs(root->right); 17 | int a = root->val + l2 + r2; // 包含当前根节点则不包含左右子树的根节点 18 | int b = max(l1, l2) + max(r1, r2); 19 | return {a, b}; 20 | } 21 | }; 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/0078.md: -------------------------------------------------------------------------------- 1 | * 回溯法 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector> subsets(vector& nums) { 7 | vector> res; 8 | vector t; 9 | dfs(res, t, nums, 0); 10 | return res; 11 | } 12 | 13 | void dfs(vector>& res, vector& t, vector& nums, int n) { 14 | res.emplace_back(t); 15 | for (int i = n; i < nums.size(); ++i) { 16 | t.emplace_back(nums[i]); 17 | dfs(res, t, nums, i + 1); 18 | t.pop_back(); 19 | } 20 | } 21 | }; 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/0091.md: -------------------------------------------------------------------------------- 1 | * 动态规划,`dp[i]` 表示 `s[0]...s[i]` 的解码方法数 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int numDecodings(string s) { 7 | if (s.empty() || s[0] == '0') { 8 | return 0; 9 | } 10 | vector dp(s.size()); 11 | dp[0] = 1; 12 | for (int i = 1; i < dp.size(); ++i) { 13 | dp[i] = s[i] == '0' ? 0 : dp[i - 1]; 14 | if (s[i - 1] == '1' || (s[i - 1] == '2' && s[i] <= '6')) { 15 | dp[i] += i >= 2 ? dp[i - 2] : 1; 16 | } 17 | } 18 | return dp.back(); 19 | } 20 | }; 21 | ``` 22 | -------------------------------------------------------------------------------- /src/0020.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isValid(string s) { 4 | stack stk; 5 | for (auto& x : s) { 6 | if (x == '(' || x == '{' || x == '[') { 7 | stk.emplace(x); 8 | } else if (!stk.empty() && stk.top() == m.at(x)) { 9 | stk.pop(); 10 | } else { 11 | return false; 12 | } 13 | } 14 | return stk.empty(); 15 | } 16 | 17 | private: 18 | const unordered_map m{ 19 | {')', '('}, 20 | {'}', '{'}, 21 | {']', '['}, 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /src/0038.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string countAndSay(int n) { 4 | vector dp(n + 1); 5 | dp[1] = "1"; 6 | for (int i = 1; i < n; ++i) { 7 | string s; 8 | int j = 0; 9 | while (j < dp[i].size()) { 10 | int k = 1; 11 | while (j + k < dp[i].size() && dp[i][j] == dp[i][j + k]) { 12 | ++k; 13 | } 14 | s += ('0' + k); 15 | s += dp[i][j]; 16 | j += k; 17 | } 18 | dp[i + 1] = s; 19 | } 20 | return dp[n]; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/0206.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* reverseList(ListNode* head) { 12 | if (!head) return nullptr; 13 | ListNode* pre = nullptr; 14 | ListNode* cur = head; 15 | while (cur) { 16 | ListNode* t = cur->next; 17 | cur->next = pre; 18 | pre = cur; 19 | cur = t; 20 | } 21 | return pre; 22 | } 23 | }; -------------------------------------------------------------------------------- /src/0452.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findMinArrowShots(vector>& points) { 4 | if (points.empty()) { 5 | return 0; 6 | } 7 | sort(points.begin(), points.end(), 8 | [](vector& x, vector& y) { return x[1] < y[1]; }); 9 | int res = 1; 10 | int t = points[0][1]; 11 | for (auto& x : points) { 12 | if (t >= x[0] && t <= x[1]) { 13 | continue; 14 | } else { 15 | t = x[1]; 16 | ++res; 17 | } 18 | } 19 | return res; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/1226.cpp: -------------------------------------------------------------------------------- 1 | class DiningPhilosophers { 2 | public: 3 | DiningPhilosophers() {} 4 | 5 | void wantsToEat(int philosopher, function pickLeftFork, 6 | function pickRightFork, function eat, 7 | function putLeftFork, function putRightFork) { 8 | scoped_lock lk(m[philosopher], m[(philosopher + 1) % 5]); 9 | pickLeftFork(); 10 | pickRightFork(); 11 | eat(); 12 | putLeftFork(); 13 | putRightFork(); 14 | } 15 | 16 | private: 17 | mutex m[5]; 18 | }; -------------------------------------------------------------------------------- /docs/0014.md: -------------------------------------------------------------------------------- 1 | ```cpp 2 | class Solution { 3 | public: 4 | string longestCommonPrefix(vector& strs) { 5 | if (strs.empty()) { 6 | return ""; 7 | } 8 | string s{strs[0]}; 9 | for (int i = 1; i < strs.size(); ++i) { 10 | const string& x = strs[i]; 11 | int cur = 0; 12 | while (s[cur] == x[cur]) { 13 | ++cur; 14 | if (cur == s.size() || cur == x.size()) { 15 | break; 16 | } 17 | } 18 | s = s.substr(0, cur); 19 | } 20 | return s; 21 | } 22 | }; 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/0101.md: -------------------------------------------------------------------------------- 1 | * 检查左右子树是否镜像即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool isSymmetric(TreeNode* root) { 7 | if (!root) { 8 | return true; 9 | } 10 | return dfs(root->left, root->right); 11 | } 12 | 13 | bool dfs(TreeNode* l, TreeNode* r) { 14 | if (!l && !r) { 15 | return true; 16 | } 17 | if (!l || !r) { 18 | return false; 19 | } 20 | if (l->val != r->val) { 21 | return false; 22 | } 23 | return dfs(l->left, r->right) && dfs(l->right, r->left); 24 | } 25 | }; 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/0202.md: -------------------------------------------------------------------------------- 1 | * 用哈希表保存出现过的数,如果再次出现,则继续替换也是重复过程,不能满足快乐数的条件 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool isHappy(int n) { 7 | unordered_set s; 8 | while (n != 1) { 9 | n = helper(n); 10 | if (s.count(n)) { 11 | return false; 12 | } 13 | s.emplace(n); 14 | } 15 | return true; 16 | } 17 | 18 | int helper(int n) { 19 | int sum = 0; 20 | while (n) { 21 | int t = n % 10; 22 | sum += t * t; 23 | n /= 10; 24 | } 25 | return sum; 26 | } 27 | }; 28 | ``` 29 | -------------------------------------------------------------------------------- /src/0239.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector maxSlidingWindow(vector& nums, int k) { 4 | vector res; 5 | deque d; 6 | for (int i = 0; i < nums.size(); ++i) { 7 | if (!d.empty() && i - d.front() >= k) { 8 | d.pop_front(); 9 | } 10 | while (!d.empty() && nums[i] >= nums[d.back()]) { 11 | d.pop_back(); 12 | } 13 | d.emplace_back(i); 14 | if (i >= k - 1) { 15 | res.emplace_back(nums[d.front()]); 16 | } 17 | } 18 | return res; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /src/0141.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | bool hasCycle(ListNode* head) { 12 | ListNode* slow = head; 13 | ListNode* fast = head; 14 | while (fast && fast->next) { 15 | slow = slow->next; 16 | fast = fast->next->next; 17 | if (slow == fast) { 18 | return true; 19 | } 20 | } 21 | return false; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/0567.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool checkInclusion(string s1, string s2) { 4 | unordered_map m1; 5 | for (auto& x : s1) { 6 | ++m1[x]; 7 | } 8 | int l = 0; 9 | unordered_map m2; 10 | for (int r = 0; r < s2.size(); ++r) { 11 | char c = s2[r]; 12 | ++m2[c]; 13 | while (m2[c] > m1[c]) { 14 | --m2[s2[l]]; 15 | ++l; 16 | } 17 | if (r - l + 1 == s1.size()) { 18 | return true; 19 | } 20 | } 21 | return false; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/0031.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void nextPermutation(vector& nums) { 4 | if (nums.size() <= 1) { 5 | return; 6 | } 7 | for (int i = nums.size() - 1; i > 0; --i) { 8 | if (nums[i - 1] < nums[i]) { 9 | sort(nums.begin() + i, nums.end()); 10 | for (int j = i; j < nums.size(); ++j) { 11 | if (nums[j] > nums[i - 1]) { 12 | swap(nums[i - 1], nums[j]); 13 | return; 14 | } 15 | } 16 | } 17 | } 18 | reverse(nums.begin(), nums.end()); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /src/0055.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canJump(vector& nums) { 4 | if (nums.empty()) { 5 | return false; 6 | } 7 | if (nums.size() == 1 && nums[0] >= 0) { 8 | return true; 9 | } 10 | vector dp(nums.size()); 11 | dp[0] = nums[0]; 12 | if (dp[0] == 0) { 13 | return false; 14 | } 15 | for (int i = 1; i < dp.size(); ++i) { 16 | dp[i] = max(dp[i - 1] - 1, nums[i - 1]); 17 | if (dp[i] == 0) { 18 | return false; 19 | } 20 | } 21 | return true; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/0309.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { 4 | int sz = prices.size(); 5 | if (sz < 2) { 6 | return 0; 7 | } 8 | vector hold(sz); 9 | vector sold(sz); 10 | vector cool(sz); 11 | hold[0] = -prices[0]; 12 | for (int i = 1; i < sz; ++i) { 13 | hold[i] = max(hold[i - 1], sold[i - 1] - prices[i]); 14 | sold[i] = max(cool[i - 1], sold[i - 1]); 15 | cool[i] = hold[i - 1] + prices[i]; 16 | } 17 | return max(cool[sz - 1], sold[sz - 1]); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/0419.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int countBattleships(vector>& board) { 4 | if (board.empty() || board[0].empty()) { 5 | return 0; 6 | } 7 | int m = board.size(); 8 | int n = board[0].size(); 9 | int res = 0; 10 | for (int i = 0; i < m; ++i) { 11 | for (int j = 0; j < n; ++j) { 12 | if (board[i][j] == 'X' && (i == 0 || board[i - 1][j] != 'X') && 13 | ((j == 0) || board[i][j - 1] != 'X')) { 14 | ++res; 15 | } 16 | } 17 | } 18 | return res; 19 | } 20 | }; -------------------------------------------------------------------------------- /docs/0108.md: -------------------------------------------------------------------------------- 1 | * 二叉搜索树的中序遍历就是升序排序的,因此题目实际就是根据中序遍历构建二叉搜索树。又因为要保持高度平衡,所以每次取中间元素为根节点,左侧元素为左子树,右侧元素为右子树即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | TreeNode* sortedArrayToBST(vector& nums) { 7 | return dfs(nums, 0, nums.size()); 8 | } 9 | 10 | TreeNode* dfs(vector& nums, int l, int r) { 11 | if (l >= r) { 12 | return nullptr; 13 | } 14 | int m = l + (r - l) / 2; 15 | TreeNode* t = new TreeNode(nums[m]); 16 | t->left = dfs(nums, l, m); 17 | t->right = dfs(nums, m + 1, r); 18 | return t; 19 | } 20 | }; 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/0179.md: -------------------------------------------------------------------------------- 1 | * 关键在于想到排序规则,解法如下 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | string largestNumber(vector& nums) { 7 | if (all_of(nums.begin(), nums.end(), [](int x) { return !x; })) { 8 | return "0"; 9 | } 10 | vector v; 11 | transform(nums.begin(), nums.end(), back_inserter(v), 12 | [](int x) { return to_string(x); }); 13 | sort(v.begin(), v.end(), 14 | [](const string& x, const string& y) { return y + x < x + y; }); 15 | return accumulate(v.begin(), v.end(), string{""}); 16 | } 17 | }; 18 | ``` 19 | -------------------------------------------------------------------------------- /src/0152.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProduct(vector& nums) { 4 | int sz = nums.size(); 5 | vector dpMax(sz + 1, INT_MIN); 6 | vector dpMin(sz + 1, INT_MAX); 7 | dpMin[0] = 1; 8 | dpMax[0] = 1; 9 | int res = INT_MIN; 10 | for (int i = 0; i < sz; ++i) { 11 | int a = dpMax[i] * nums[i]; 12 | int b = dpMin[i] * nums[i]; 13 | dpMax[i + 1] = max({a, b, nums[i]}); 14 | dpMin[i + 1] = min({a, b, nums[i]}); 15 | res = max(res, dpMax[i + 1]); 16 | } 17 | return res; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/0240.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool searchMatrix(vector>& matrix, int target) { 4 | if (matrix.empty() || matrix[0].empty()) { 5 | return false; 6 | } 7 | int m = matrix.size(); 8 | int n = matrix[0].size(); 9 | int i = m - 1; 10 | int j = 0; 11 | while (i >= 0 && j <= n - 1) { 12 | if (matrix[i][j] == target) { 13 | return true; 14 | } else if (matrix[i][j] < target) { 15 | ++j; 16 | } else { 17 | --i; 18 | } 19 | } 20 | return false; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /docs/0365.md: -------------------------------------------------------------------------------- 1 | * 该问题相当于判断如下整数方程是否有解 2 | 3 | ``` 4 | a * jug1Capacity + b * jug2Capacity = targetCapacity 5 | ``` 6 | 7 | * 由 [裴蜀定理(Bézout's identity)](https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity),方程有解的条件为 `targetCapacity` 能被 a 和 b 的最大公约数整除 8 | 9 | ```cpp 10 | class Solution { 11 | public: 12 | bool canMeasureWater(int jug1Capacity, int jug2Capacity, int targetCapacity) { 13 | if (targetCapacity > jug1Capacity + jug2Capacity) { 14 | return false; 15 | } 16 | return targetCapacity % gcd(jug1Capacity, jug2Capacity) == 0; 17 | } 18 | }; 19 | ``` 20 | -------------------------------------------------------------------------------- /src/0347.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector topKFrequent(vector& nums, int k) { 4 | unordered_map m; 5 | for (auto& x : nums) { 6 | ++m[x]; 7 | } 8 | priority_queue, vector>, greater<>> q; 9 | for (auto& x : m) { 10 | q.emplace(x.second, x.first); 11 | if (q.size() > k) { 12 | q.pop(); 13 | } 14 | } 15 | vector res; 16 | while (!q.empty()) { 17 | res.emplace_back(q.top().second); 18 | q.pop(); 19 | } 20 | return res; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /docs/0268.md: -------------------------------------------------------------------------------- 1 | * 求出 `0` 到 `nums.size()` 和,再减去数组中所有元素即为结果 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int missingNumber(vector& nums) { 7 | int n = nums.size(); 8 | n = n * (n + 1) / 2; 9 | return accumulate(nums.begin(), nums.end(), n, minus{}); 10 | } 11 | }; 12 | ``` 13 | 14 | * 如果考虑溢出 15 | 16 | ```cpp 17 | class Solution { 18 | public: 19 | int missingNumber(vector& nums) { 20 | int res = nums.size(); 21 | for (int i = 0; i < nums.size(); ++i) { 22 | res += i - nums[i]; 23 | } 24 | return res; 25 | } 26 | }; 27 | ``` 28 | -------------------------------------------------------------------------------- /src/0312.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxCoins(vector& nums) { 4 | nums.emplace(nums.begin(), 1); 5 | nums.emplace_back(1); 6 | int sz = nums.size(); 7 | vector> dp(sz, vector(sz)); 8 | for (int n = 2; n < sz; ++n) { 9 | for (int i = 0; i + n < sz; ++i) { 10 | for (int j = i + 1; j < i + n; ++j) { 11 | int t = dp[i][j] + dp[j][i + n] + nums[i] * nums[j] * nums[i + n]; 12 | dp[i][i + n] = max(dp[i][i + n], t); 13 | } 14 | } 15 | } 16 | return dp[0][sz - 1]; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/0443.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int compress(vector& chars) { 4 | int sz = chars.size(); 5 | int l = 0; 6 | int r = 0; 7 | int cur = 0; 8 | while (l != sz) { 9 | while (r < sz && chars[l] == chars[r]) { 10 | ++r; 11 | } 12 | chars[cur] = chars[l]; 13 | if (r - l > 1) { 14 | string cnt = to_string(r - l); 15 | for (int i = 0; i < cnt.size(); ++i) { 16 | chars[++cur] = cnt[i]; 17 | } 18 | } 19 | l = r; 20 | ++cur; 21 | } 22 | return cur; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /docs/0038.md: -------------------------------------------------------------------------------- 1 | * 找出上一个字符串到下一个字符串的规律即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | string countAndSay(int n) { 7 | vector dp(n + 1); 8 | dp[1] = "1"; 9 | for (int i = 1; i < n; ++i) { 10 | string s; 11 | int j = 0; 12 | while (j < dp[i].size()) { 13 | int k = 1; 14 | while (j + k < dp[i].size() && dp[i][j] == dp[i][j + k]) { 15 | ++k; 16 | } 17 | s += ('0' + k); 18 | s += dp[i][j]; 19 | j += k; 20 | } 21 | dp[i + 1] = s; 22 | } 23 | return dp[n]; 24 | } 25 | }; 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/0069.md: -------------------------------------------------------------------------------- 1 | * 二分查找即可,注意判断过程中,值的平方可能产生溢出,因此判断应该用除法而非乘法 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int mySqrt(int x) { 7 | if (x <= 1) { 8 | return x; 9 | } 10 | int l = 1; 11 | int r = x; 12 | while (l < r) { 13 | int m = l + (r - l) / 2; 14 | int t = x / m; // m * m 可能溢出 15 | if (m == t) { 16 | return m; 17 | } else if (m > t) { 18 | r = m; 19 | } else { 20 | l = m + 1; 21 | } 22 | } // l 是第一个满足 x / m < m 的值 23 | return l - 1; // 商应该向下取整,因此返回 l - 1 24 | } 25 | }; 26 | ``` 27 | -------------------------------------------------------------------------------- /src/0021.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 12 | if (!l1) { 13 | return l2; 14 | } 15 | if (!l2) { 16 | return l1; 17 | } 18 | if (l1->val < l2->val) { 19 | l1->next = mergeTwoLists(l1->next, l2); 20 | return l1; 21 | } 22 | l2->next = mergeTwoLists(l2->next, l1); 23 | return l2; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /docs/0134.md: -------------------------------------------------------------------------------- 1 | * 记录到达每个位置的理论剩余油量,如果遍历一边后剩余量为负数则无法行驶一周。如果能行驶一周,其过程中剩余油量最少的位置即为终点 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int canCompleteCircuit(vector& gas, vector& cost) { 7 | int res = 0; 8 | int mn = INT_MAX; 9 | int x = 0; 10 | for (int i = 0; i < gas.size(); ++i) { 11 | x += gas[i] - cost[i]; 12 | if (x < mn) { 13 | mn = x; 14 | res = i; 15 | } 16 | } 17 | if (x < 0) { 18 | return -1; 19 | } 20 | if (res == gas.size() - 1) { 21 | return 0; 22 | } 23 | return res + 1; 24 | } 25 | }; 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/0322.md: -------------------------------------------------------------------------------- 1 | * 动态规划,`dp[i]` 表示要凑成金额 `i` 最少需要的硬币数 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int coinChange(vector& coins, int amount) { 7 | if (coins.empty()) { 8 | return -1; 9 | } 10 | // 假设全用 1 也不可能用 amout + 1 个,用初始值表示无法组合 11 | vector dp(amount + 1, amount + 1); 12 | dp[0] = 0; 13 | for (int i = 1; i <= amount; ++i) { 14 | for (auto& x : coins) { 15 | if (i >= x) { 16 | dp[i] = min(dp[i], dp[i - x] + 1); 17 | } 18 | } 19 | } 20 | return dp[amount] == amount + 1 ? -1 : dp[amount]; 21 | } 22 | }; 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/0328.md: -------------------------------------------------------------------------------- 1 | ```cpp 2 | class Solution { 3 | public: 4 | ListNode* oddEvenList(ListNode* head) { 5 | if (!head || !head->next) { 6 | return head; 7 | } 8 | ListNode* odd = head; 9 | ListNode* even = head->next; 10 | ListNode* evenStart = head->next; 11 | while (odd->next && odd->next->next) { 12 | odd->next = even->next; 13 | odd = odd->next; 14 | even->next = odd->next; 15 | even = even->next; 16 | } 17 | if (even) { 18 | even->next = nullptr; 19 | } 20 | odd->next = evenStart; 21 | return head; 22 | } 23 | }; 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/0443.md: -------------------------------------------------------------------------------- 1 | ```cpp 2 | class Solution { 3 | public: 4 | int compress(vector& chars) { 5 | int sz = chars.size(); 6 | int l = 0; 7 | int r = 0; 8 | int cur = 0; 9 | while (l != sz) { 10 | while (r < sz && chars[l] == chars[r]) { 11 | ++r; 12 | } 13 | chars[cur] = chars[l]; 14 | if (r - l > 1) { 15 | string cnt = to_string(r - l); 16 | for (int i = 0; i < cnt.size(); ++i) { 17 | chars[++cur] = cnt[i]; 18 | } 19 | } 20 | l = r; 21 | ++cur; 22 | } 23 | return cur; 24 | } 25 | }; 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/0513.md: -------------------------------------------------------------------------------- 1 | * 层序遍历即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int findBottomLeftValue(TreeNode* root) { 7 | queue q; 8 | q.emplace(root); 9 | int res; 10 | while (!q.empty()) { 11 | int n = q.size(); 12 | res = q.front()->val; 13 | for (int i = 0; i < n; ++i) { 14 | TreeNode* t = q.front(); 15 | q.pop(); 16 | if (t->left) { 17 | q.emplace(t->left); 18 | } 19 | if (t->right) { 20 | q.emplace(t->right); 21 | } 22 | } 23 | } 24 | return res; 25 | } 26 | }; 27 | ``` 28 | -------------------------------------------------------------------------------- /src/0454.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int fourSumCount(vector& A, vector& B, vector& C, 4 | vector& D) { 5 | unordered_map m; 6 | int sz = A.size(); 7 | for (int i = 0; i < sz; ++i) { 8 | for (int j = 0; j < sz; ++j) { 9 | ++m[A[i] + B[j]]; 10 | } 11 | } 12 | int res = 0; 13 | for (int i = 0; i < sz; ++i) { 14 | for (int j = 0; j < sz; ++j) { 15 | if (m.count(-C[i] - D[j])) { 16 | res += m[-C[i] - D[j]]; 17 | } 18 | } 19 | } 20 | return res; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /docs/0011.md: -------------------------------------------------------------------------------- 1 | * 设置左右边界 `l` 和 `r`,盛水容量为 `(r - l) * min(height[l], height[r])`,每次右移 `l` 或左移 `r`(移动的应该是高度更小的那个,比如如果 `height[l]` 大,右移 `l` 乘积肯定缩小)来缩小范围,时间复杂度 `O(n)` 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int maxArea(vector& height) { 7 | int res = 0; 8 | int l = 0; 9 | int r = height.size() - 1; 10 | while (l != r) { 11 | if (height[l] < height[r]) { 12 | res = max(res, (r - l) * height[l]); 13 | ++l; 14 | } else { 15 | res = max(res, (r - l) * height[r]); 16 | --r; 17 | } 18 | } 19 | return res; 20 | } 21 | }; 22 | ``` 23 | -------------------------------------------------------------------------------- /src/0029.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int divide(int dividend, int divisor) { 4 | if (dividend == 0) { 5 | return 0; 6 | } 7 | if (dividend == INT_MIN && divisor == -1) { 8 | return INT_MAX; 9 | } 10 | long x = labs(dividend); 11 | long y = labs(divisor); 12 | long res = 0; 13 | while (x >= y) { 14 | long t = y; 15 | long cnt = 1; 16 | while (x >= t + t) { 17 | t <<= 1; 18 | cnt <<= 1; 19 | } 20 | res += cnt; 21 | x -= t; 22 | } 23 | return (dividend ^ divisor) < 0 ? -res : res; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/0041.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int firstMissingPositive(vector& nums) { 4 | if (nums.empty()) { 5 | return 1; 6 | } 7 | int sz = nums.size(); 8 | for (int i = 0; i < sz; ++i) { 9 | while (nums[i] != i + 1 && nums[i] - 1 >= 0 && nums[i] - 1 < sz) { 10 | if (nums[i] == nums[nums[i] - 1]) { 11 | break; 12 | } 13 | swap(nums[i], nums[nums[i] - 1]); 14 | } 15 | } 16 | for (int i = 0; i < sz; ++i) { 17 | if (nums[i] != i + 1) { 18 | return i + 1; 19 | } 20 | } 21 | return sz + 1; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /docs/0378.md: -------------------------------------------------------------------------------- 1 | * 每行每列均为升序,第一行第一个元素即为最小元素,最后一行最后一列即为最大元素,在最小元素到最大元素中二分查找即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int kthSmallest(vector>& matrix, int k) { 7 | int l = matrix[0][0]; 8 | int r = matrix.back().back(); 9 | while (l < r) { 10 | int m = l + (r - l) / 2; 11 | int cnt = 0; // 记录不大于 m 的元素数 12 | for (auto& x : matrix) { 13 | cnt += upper_bound(x.begin(), x.end(), m) - x.begin(); 14 | } 15 | if (k <= cnt) { 16 | r = m; 17 | } else { 18 | l = m + 1; 19 | } 20 | } 21 | return l; 22 | } 23 | }; 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/0437.md: -------------------------------------------------------------------------------- 1 | * 以每个节点为根节点往下遍历检查即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int pathSum(TreeNode* root, int sum) { 7 | if (!root) { 8 | return 0; 9 | } 10 | int res = 0; 11 | dfs(root, res, sum); 12 | res += pathSum(root->left, sum); 13 | res += pathSum(root->right, sum); 14 | return res; 15 | } 16 | 17 | void dfs(TreeNode* root, int& res, int n) { 18 | if (!root) { 19 | return; 20 | } 21 | if (root->val == n) { 22 | ++res; 23 | } 24 | dfs(root->left, res, n - root->val); 25 | dfs(root->right, res, n - root->val); 26 | } 27 | }; 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/0452.md: -------------------------------------------------------------------------------- 1 | * 按右边界排序,从第一个右边界开始射箭,计算能引爆的气球数量,不能引爆时再换成下一个未引爆的气球的右边界 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int findMinArrowShots(vector>& points) { 7 | if (points.empty()) { 8 | return 0; 9 | } 10 | sort(points.begin(), points.end(), 11 | [](vector& x, vector& y) { return x[1] < y[1]; }); 12 | int res = 1; 13 | int t = points[0][1]; 14 | for (auto& x : points) { 15 | if (t >= x[0] && t <= x[1]) { 16 | continue; 17 | } else { 18 | t = x[1]; 19 | ++res; 20 | } 21 | } 22 | return res; 23 | } 24 | }; 25 | ``` 26 | -------------------------------------------------------------------------------- /src/0538.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* convertBST(TreeNode* root) { 13 | int pre = 0; 14 | dfs(root, pre); 15 | return root; 16 | } 17 | 18 | void dfs(TreeNode* root, int& pre) { 19 | if (!root) { 20 | return; 21 | } 22 | dfs(root->right, pre); 23 | root->val += pre; 24 | pre = root->val; 25 | dfs(root->left, pre); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/0559.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | // Definition for a Node. 3 | class Node { 4 | public: 5 | int val; 6 | vector children; 7 | 8 | Node() {} 9 | 10 | Node(int _val) { 11 | val = _val; 12 | } 13 | 14 | Node(int _val, vector _children) { 15 | val = _val; 16 | children = _children; 17 | } 18 | }; 19 | */ 20 | class Solution { 21 | public: 22 | int maxDepth(Node* root) { 23 | if (!root) { 24 | return 0; 25 | } 26 | int res = 1; 27 | for (auto& x : root->children) { 28 | res = max(res, maxDepth(x) + 1); 29 | } 30 | return res; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /docs/0384.md: -------------------------------------------------------------------------------- 1 | * 每次从右侧取一个元素放到最左边,这样每个元素被放到指定位置的概率都相同 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | Solution(vector& nums) { v.assign(nums.begin(), nums.end()); } 7 | 8 | /** Resets the array to its original configuration and return it. */ 9 | vector reset() { return v; } 10 | 11 | /** Returns a random shuffling of the array. */ 12 | vector shuffle() { 13 | vector res{v}; 14 | for (int i = 0; i < res.size(); ++i) { 15 | int t = i + rand() % (res.size() - i); 16 | swap(res[i], res[t]); 17 | } 18 | return res; 19 | } 20 | 21 | private: 22 | vector v; 23 | }; 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/0419.md: -------------------------------------------------------------------------------- 1 | * 如果一个位置是 `X`,若其左侧和上侧也为 `X`,则该位置不是战舰头部 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int countBattleships(vector>& board) { 7 | if (board.empty() || board[0].empty()) { 8 | return 0; 9 | } 10 | int m = board.size(); 11 | int n = board[0].size(); 12 | int res = 0; 13 | for (int i = 0; i < m; ++i) { 14 | for (int j = 0; j < n; ++j) { 15 | if (board[i][j] == 'X' && (i == 0 || board[i - 1][j] != 'X') && 16 | ((j == 0) || board[i][j - 1] != 'X')) { 17 | ++res; 18 | } 19 | } 20 | } 21 | return res; 22 | } 23 | }; 24 | ``` 25 | -------------------------------------------------------------------------------- /src/0354.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxEnvelopes(vector>& envelopes) { 4 | if (envelopes.empty()) { 5 | return 0; 6 | } 7 | sort(envelopes.begin(), envelopes.end(), 8 | [](auto& x, auto& y) { return tie(x[0], y[1]) < tie(y[0], x[1]); }); 9 | vector v{envelopes[0][1]}; 10 | for (int i = 1; i < envelopes.size(); ++i) { 11 | if (envelopes[i][1] > v.back()) { 12 | v.emplace_back(envelopes[i][1]); 13 | } else { 14 | *lower_bound(v.begin(), v.end(), envelopes[i][1]) = envelopes[i][1]; 15 | } 16 | } 17 | return v.size(); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /docs/0191.md: -------------------------------------------------------------------------------- 1 | * 对一个数和比它小 1 的数做与运算,即可消除这个数二进制最低位的 1 2 | 3 | ``` 4 | 最低位是 1,则等价于把最低位的 1 改为 0 5 | 1111 & 1110 = 1110 6 | 1011 & 1010 = 1010 7 | xxx1 & xxx0 = xxx0 8 | 9 | 最低位不是 1,则找到最低位的 1,比它小 1 的数该位为 0,之后为 1 10 | 1110 & 1101 = 1100 11 | 1100 & 1011 = 1000 12 | 1000 & 0111 = 0000 13 | 14 | xxx100000...(n 个 0) 15 | & xxx011111...(n 个 1) 16 | = xxx000000(n + 1 个 0) 17 | ``` 18 | 19 | * 逐次消除最低位的 1 直到值为 0,消除的次数即为结果 20 | 21 | ```cpp 22 | class Solution { 23 | public: 24 | int hammingWeight(uint32_t n) { 25 | int res = 0; 26 | while (n) { 27 | ++res; 28 | n &= n - 1; 29 | } 30 | return res; 31 | } 32 | }; 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/0198.md: -------------------------------------------------------------------------------- 1 | * 动态规划,`dp[i]` 表示对于 `i` 间房能获取的最大收益,如果有 1 间房,则最大收益即为该间房的现金,若有 2 间房则为两者中较大者,若有多间房,则对最后一间房 `nums[i - 1]` 有偷和不偷两种选择,若不偷最后一间房则最大收益等于对 `i - 1` 间房的最大收益 `dp[i - 1]`,若偷最后一间房则不能偷前一间房,最大收益为对 `i - 2` 间房的最大收益与最后一间房收益之和,即 `dp[i - 2] + nums[i - 1]`,两种选择较大者即为 `dp[i]` 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int rob(vector& nums) { 7 | if (nums.empty()) { 8 | return 0; 9 | } 10 | vector dp(nums.size() + 1); 11 | dp[1] = nums[0]; 12 | for (int i = 2; i < dp.size(); ++i) { 13 | dp[i] = max(dp[i - 2] + nums[i - 1], dp[i - 1]); 14 | } 15 | return dp[nums.size()]; 16 | } 17 | }; 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/0020.md: -------------------------------------------------------------------------------- 1 | * 遍历字符串,如果是左括号则压到栈中,如果是右括号则检查是否与栈顶的左括号匹配,如果匹配则弹出栈顶元素。遍历完字符串,如果栈为空则说明所有括号均匹配成功 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool isValid(string s) { 7 | stack stk; 8 | for (auto& x : s) { 9 | if (x == '(' || x == '{' || x == '[') { 10 | stk.emplace(x); 11 | } else if (!stk.empty() && stk.top() == m.at(x)) { 12 | stk.pop(); 13 | } else { 14 | return false; 15 | } 16 | } 17 | return stk.empty(); 18 | } 19 | 20 | private: 21 | const unordered_map m{ 22 | {')', '('}, 23 | {'}', '{'}, 24 | {']', '['}, 25 | }; 26 | }; 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/0341.md: -------------------------------------------------------------------------------- 1 | * 不断递归直到获取单元素即可 2 | 3 | ```cpp 4 | class NestedIterator { 5 | public: 6 | NestedIterator(vector& nestedList) { append(nestedList, q); } 7 | 8 | void append(vector& nestedList, queue& q) { 9 | for (auto& x : nestedList) { 10 | if (x.isInteger()) { 11 | q.emplace(x.getInteger()); 12 | } else { 13 | append(x.getList(), q); 14 | } 15 | } 16 | } 17 | 18 | int next() { 19 | int res = q.front(); 20 | q.pop(); 21 | return res; 22 | } 23 | 24 | bool hasNext() { return !q.empty(); } 25 | 26 | private: 27 | queue q; 28 | }; 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/0429.md: -------------------------------------------------------------------------------- 1 | ```cpp 2 | class Solution { 3 | public: 4 | vector> levelOrder(Node* root) { 5 | vector> res; 6 | if (!root) { 7 | return res; 8 | } 9 | queue q; 10 | q.emplace(root); 11 | while (!q.empty()) { 12 | vector line; 13 | int n = q.size(); 14 | for (int i = 0; i < n; ++i) { 15 | Node* t = q.front(); 16 | q.pop(); 17 | line.emplace_back(t->val); 18 | for (auto& x : t->children) { 19 | q.emplace(x); 20 | } 21 | } 22 | res.emplace_back(line); 23 | } 24 | return res; 25 | } 26 | }; 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/0049.md: -------------------------------------------------------------------------------- 1 | * 对于字母相同的字符串的判断法是,对字符串排序,排序结果相同则字符串含有相同单词 2 | * 对于字符串所在组,需要一个值记录其索引。每次有新的异位字符串时,递增记录值作为新的索引 3 | * 解法如下 4 | 5 | ```cpp 6 | class Solution { 7 | public: 8 | vector> groupAnagrams(vector& strs) { 9 | vector> res; 10 | unordered_map m; 11 | int i = -1; 12 | for (auto& x : strs) { 13 | string t{x}; 14 | sort(t.begin(), t.end()); 15 | if (!m.count(t)) { 16 | res.emplace_back(vector{x}); 17 | m.emplace(t, ++i); 18 | } else { 19 | res[m[t]].emplace_back(x); 20 | } 21 | } 22 | return res; 23 | } 24 | }; 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/0235.md: -------------------------------------------------------------------------------- 1 | * 利用二叉搜索树性质,当前节点值比两个节点值都大时则往左子树查找,比两个节点值都小时往右子树查找,位于两者之间则就是最近公共祖先 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 7 | if (!root) { 8 | return nullptr; 9 | } 10 | if (!p) { 11 | return q; 12 | } 13 | if (!q) { 14 | return p; 15 | } 16 | if (root->val > p->val && root->val > q->val) { 17 | return lowestCommonAncestor(root->left, p, q); 18 | } 19 | if (root->val < p->val && root->val < q->val) { 20 | return lowestCommonAncestor(root->right, p, q); 21 | } 22 | return root; 23 | } 24 | }; 25 | ``` 26 | -------------------------------------------------------------------------------- /src/0019.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* removeNthFromEnd(ListNode* head, int n) { 12 | ListNode* dummy = new ListNode(-1); 13 | dummy->next = head; 14 | ListNode* p = dummy; 15 | ListNode* q = dummy; 16 | for (int i = 0; i < n + 1; ++i) { 17 | p = p->next; 18 | } 19 | while (p) { 20 | p = p->next; 21 | q = q->next; 22 | } 23 | q->next = q->next->next; 24 | return dummy->next; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/0324.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void wiggleSort(vector& nums) { 4 | if (nums.empty()) { 5 | return; 6 | } 7 | int sz = nums.size(); 8 | nth_element(nums.begin(), nums.begin() + sz / 2, nums.end()); 9 | int m = nums[sz / 2]; 10 | #define a(i) nums[(2 * (i) + 1) % (sz | 1)] 11 | int i = 0; 12 | int j = 0; 13 | int k = sz - 1; 14 | while (j <= k) { 15 | if (a(j) > m) { 16 | swap(a(i), a(j)); 17 | ++i; 18 | ++j; 19 | } else if (a(j) < m) { 20 | swap(a(j), a(k)); 21 | --k; 22 | } else { 23 | ++j; 24 | } 25 | } 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/0543.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int diameterOfBinaryTree(TreeNode* root) { 13 | int res = 0; 14 | depth(root, res); 15 | return res; 16 | } 17 | 18 | int depth(TreeNode* root, int& res) { 19 | if (!root) { 20 | return 0; 21 | } 22 | int l = depth(root->left, res); 23 | int r = depth(root->right, res); 24 | res = max(res, l + r); 25 | return 1 + max(l, r); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /docs/0019.md: -------------------------------------------------------------------------------- 1 | * 解法如下 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | ListNode* removeNthFromEnd(ListNode* head, int n) { 7 | ListNode* dummy = new ListNode(-1); 8 | dummy->next = head; 9 | ListNode* p = dummy; 10 | ListNode* q = dummy; 11 | for (int i = 0; i < n + 1; ++i) { 12 | p = p->next; 13 | } // p 移动 n + 1 次指向第 n + 1 个节点 14 | // 此时 p 与 q 距离为 n + 1 15 | while (p) { 16 | p = p->next; // p 到达最后的空节点时 17 | q = q->next; // q 到达倒数第 n + 1 个节点 18 | } 19 | // 要删除倒数第 n 个节点 20 | // 让倒数第 n + 1 个节点的下一节点指向倒数第 n - 1 个节点即可 21 | q->next = q->next->next; 22 | return dummy->next; 23 | } 24 | }; 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/0454.md: -------------------------------------------------------------------------------- 1 | * 记录前两组的各种和的数量,然后找后两组和为其相反数的次数 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int fourSumCount(vector& A, vector& B, vector& C, 7 | vector& D) { 8 | unordered_map m; 9 | int sz = A.size(); 10 | for (int i = 0; i < sz; ++i) { 11 | for (int j = 0; j < sz; ++j) { 12 | ++m[A[i] + B[j]]; 13 | } 14 | } 15 | int res = 0; 16 | for (int i = 0; i < sz; ++i) { 17 | for (int j = 0; j < sz; ++j) { 18 | if (m.count(-C[i] - D[j])) { 19 | res += m[-C[i] - D[j]]; 20 | } 21 | } 22 | } 23 | return res; 24 | } 25 | }; 26 | ``` 27 | -------------------------------------------------------------------------------- /src/0022.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector generateParenthesis(int n) { 4 | vector res; 5 | dfs(res, "", n, n); 6 | return res; 7 | } 8 | 9 | void dfs(vector& res, string s, int l_parenthese, int r_parenthese) { 10 | if (l_parenthese == 0 && r_parenthese == 0) { 11 | res.emplace_back(s); 12 | return; 13 | } 14 | if (l_parenthese <= r_parenthese) { 15 | if (l_parenthese > 0) { 16 | dfs(res, s + '(', l_parenthese - 1, r_parenthese); 17 | } 18 | if (r_parenthese > 0) { 19 | dfs(res, s + ')', l_parenthese, r_parenthese - 1); 20 | } 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/0024.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | class Solution { 12 | public: 13 | ListNode* swapPairs(ListNode* head) { 14 | if (!head || !head->next) { 15 | return head; 16 | } 17 | ListNode* second_node = head->next; 18 | ListNode* third_node = second_node->next; 19 | second_node->next = head; 20 | head->next = swapPairs(third_node); 21 | return second_node; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/0094.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector inorderTraversal(TreeNode* root) { 13 | vector res; 14 | stack s; 15 | TreeNode* t = root; 16 | while (t || !s.empty()) { 17 | while (t) { 18 | s.emplace(t); 19 | t = t->left; 20 | } 21 | t = s.top(); 22 | s.pop(); 23 | res.emplace_back(t->val); 24 | t = t->right; 25 | } 26 | return res; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/0150.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int evalRPN(vector& tokens) { 4 | stack s; 5 | for (auto& x : tokens) { 6 | if (x == "+" || x == "-" || x == "*" || x == "/") { 7 | int b = s.top(); 8 | s.pop(); 9 | int a = s.top(); 10 | s.pop(); 11 | if (x == "+") { 12 | s.emplace(a + b); 13 | } else if (x == "-") { 14 | s.emplace(a - b); 15 | } else if (x == "*") { 16 | s.emplace(a * b); 17 | } else { 18 | s.emplace(a / b); 19 | } 20 | } else { 21 | s.emplace(stoi(x)); 22 | } 23 | } 24 | return s.top(); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /docs/0173.md: -------------------------------------------------------------------------------- 1 | * 用栈保存中序遍历左侧序列即可 2 | 3 | ```cpp 4 | class BSTIterator { 5 | public: 6 | BSTIterator(TreeNode* root) { 7 | TreeNode* t = root; 8 | while (t) { 9 | s.emplace(t); 10 | t = t->left; 11 | } 12 | } 13 | 14 | /** @return the next smallest number */ 15 | int next() { 16 | TreeNode* t = s.top(); 17 | int res = t->val; 18 | s.pop(); 19 | t = t->right; 20 | while (t) { 21 | s.emplace(t); 22 | t = t->left; 23 | } 24 | return res; 25 | } 26 | 27 | /** @return whether we have a next smallest number */ 28 | bool hasNext() { return !s.empty(); } 29 | 30 | private: 31 | stack s; 32 | }; 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/0239.md: -------------------------------------------------------------------------------- 1 | * 用一个双端队列来保存索引,保持队首为窗口最大值的索引即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector maxSlidingWindow(vector& nums, int k) { 7 | vector res; 8 | deque d; 9 | for (int i = 0; i < nums.size(); ++i) { 10 | if (!d.empty() && i - d.front() >= k) { // 不在窗口范围内则弹出 11 | d.pop_front(); 12 | } 13 | while (!d.empty() && nums[i] >= nums[d.back()]) { 14 | d.pop_back(); // 弹出所有不可能为窗口最大值的索引 15 | } 16 | d.emplace_back(i); // nums[i] 可能成为窗口最大值 17 | if (i >= k - 1) { // 从第 k 个数开始才有窗口 18 | res.emplace_back(nums[d.front()]); 19 | } 20 | } 21 | return res; 22 | } 23 | }; 24 | ``` 25 | -------------------------------------------------------------------------------- /src/0108.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* sortedArrayToBST(vector& nums) { 13 | return dfs(nums, 0, nums.size()); 14 | } 15 | 16 | TreeNode* dfs(vector& nums, int l, int r) { 17 | if (l >= r) { 18 | return nullptr; 19 | } 20 | int m = l + (r - l) / 2; 21 | TreeNode* t = new TreeNode(nums[m]); 22 | t->left = dfs(nums, l, m); 23 | t->right = dfs(nums, m + 1, r); 24 | return t; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/0124.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int maxPathSum(TreeNode* root) { 13 | int res = INT_MIN; 14 | dfs(root, res); 15 | return res; 16 | } 17 | 18 | int dfs(TreeNode* root, int& res) { 19 | if (!root) { 20 | return 0; 21 | } 22 | int l = max(dfs(root->left, res), 0); 23 | int r = max(dfs(root->right, res), 0); 24 | res = max(res, l + r + root->val); 25 | return root->val + max(l, r); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/0144.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector preorderTraversal(TreeNode* root) { 13 | vector res; 14 | stack s; 15 | TreeNode* t = root; 16 | while (t || !s.empty()) { 17 | while (t) { 18 | res.emplace_back(t->val); 19 | s.emplace(t); 20 | t = t->left; 21 | } 22 | t = s.top(); 23 | s.pop(); 24 | t = t->right; 25 | } 26 | return res; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/0337.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int rob(TreeNode* root) { 13 | auto [a, b] = dfs(root); 14 | return max(a, b); 15 | } 16 | 17 | pair dfs(TreeNode* root) { 18 | if (!root) { 19 | return {0, 0}; 20 | } 21 | auto [l1, l2] = dfs(root->left); 22 | auto [r1, r2] = dfs(root->right); 23 | int a = root->val + l2 + r2; 24 | int b = max(l1, l2) + max(r1, r2); 25 | return {a, b}; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /docs/0240.md: -------------------------------------------------------------------------------- 1 | * 从最后一列第一个数开始查找,如果目标值比它大,则删除其所在列,如果目标值比它小,则删除其所在行,如果删除所有行列后仍未找到,则不存在目标值 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool searchMatrix(vector>& matrix, int target) { 7 | if (matrix.empty() || matrix[0].empty()) { 8 | return false; 9 | } 10 | int m = matrix.size(); 11 | int n = matrix[0].size(); 12 | int i = m - 1; // 下边界 13 | int j = 0; // 左边界 14 | while (i >= 0 && j <= n - 1) { 15 | if (matrix[i][j] == target) { 16 | return true; 17 | } else if (matrix[i][j] < target) { 18 | ++j; 19 | } else { 20 | --i; 21 | } 22 | } 23 | return false; 24 | } 25 | }; 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/0567.md: -------------------------------------------------------------------------------- 1 | * 对 `s1` 的字符计数,用滑动窗口检测 `s2`,若窗口中的子串能用 `s1` 提供的字符表示,则移动窗口右边界,若不能满足,则移动左边界直至满足,若子串使用了 `s1` 所有字符,则子串即为 `s1` 的一个排列 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool checkInclusion(string s1, string s2) { 7 | unordered_map m1; 8 | for (auto& x : s1) { 9 | ++m1[x]; 10 | } 11 | int l = 0; 12 | unordered_map m2; 13 | for (int r = 0; r < s2.size(); ++r) { 14 | char c = s2[r]; 15 | ++m2[c]; 16 | while (m2[c] > m1[c]) { 17 | --m2[s2[l]]; 18 | ++l; 19 | } 20 | if (r - l + 1 == s1.size()) { 21 | return true; 22 | } 23 | } 24 | return false; 25 | } 26 | }; 27 | ``` 28 | -------------------------------------------------------------------------------- /src/0044.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isMatch(string s, string p) { 4 | int i = 0; 5 | int j = 0; 6 | int markS = -1; 7 | int markP = -1; 8 | while (i < s.size()) { 9 | if (j < p.size() && (s[i] == p[j] || p[j] == '?')) { 10 | ++i; 11 | ++j; 12 | } else if (j < p.size() && p[j] == '*') { 13 | markS = i; 14 | markP = j; 15 | ++j; 16 | } else if (markP != -1) { 17 | i = ++markS; 18 | j = markP + 1; 19 | } else { 20 | return false; 21 | } 22 | } 23 | while (j < p.size() && p[j] == '*') { 24 | ++j; 25 | } 26 | return j == p.size(); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /docs/0169.md: -------------------------------------------------------------------------------- 1 | * 因为目标元素占数组一半以上,因此可以让任意不相同的两个数抵消,最后剩余的必然是目标元素 2 | 3 | ``` 4 | [2, 2, 1, 1, 1, 2, 2] 5 | 22 和 11 抵消 6 | [1, 2, 2] 7 | 1 和 2 抵消 8 | [2] 9 | 2 即为答案 10 | 11 | [2, 3, 1, 4, 1, 1, 1, 1] 12 | 2 和 3 抵消 13 | [1, 4, 1, 1, 1, 1] 14 | 1 和 4 抵消 15 | [1, 1, 1, 1] 16 | 1 即为答案 17 | ``` 18 | 19 | * 实现如下 20 | 21 | ```cpp 22 | class Solution { 23 | public: 24 | int majorityElement(vector& nums) { 25 | int cnt = 0; 26 | int res = INT_MIN; 27 | for (auto& x : nums) { 28 | if (cnt == 0) { 29 | res = x; 30 | } 31 | if (res == x) { 32 | ++cnt; 33 | } else { 34 | --cnt; 35 | } 36 | } 37 | return res; 38 | } 39 | }; 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/0347.md: -------------------------------------------------------------------------------- 1 | * 用最小堆保存 `k` 个元素,当元素数超出 `k` 时则从堆中弹出最小元素。插入一个元素到堆的时间复杂度 `O(log k)`,总体时间复杂度 `O(n log k)` 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector topKFrequent(vector& nums, int k) { 7 | unordered_map m; 8 | for (auto& x : nums) { 9 | ++m[x]; 10 | } 11 | priority_queue, vector>, greater<>> q; 12 | for (auto& x : m) { 13 | q.emplace(x.second, x.first); 14 | if (q.size() > k) { 15 | q.pop(); 16 | } 17 | } 18 | vector res; 19 | while (!q.empty()) { 20 | res.emplace_back(q.top().second); 21 | q.pop(); 22 | } 23 | return res; 24 | } 25 | }; 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/0654.md: -------------------------------------------------------------------------------- 1 | * 按题意递归即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | TreeNode* constructMaximumBinaryTree(vector& nums) { 7 | return constructMaximumBinaryTree(nums, 0, nums.size()); 8 | } 9 | 10 | TreeNode* constructMaximumBinaryTree(vector& nums, int l, int r) { 11 | if (l == r) { 12 | return nullptr; 13 | } 14 | int max_index = 15 | max_element(nums.begin() + l, nums.begin() + r) - nums.begin(); 16 | TreeNode* root = new TreeNode(nums[max_index]); 17 | root->left = constructMaximumBinaryTree(nums, l, max_index); 18 | root->right = constructMaximumBinaryTree(nums, max_index + 1, r); 19 | return root; 20 | } 21 | }; 22 | ``` 23 | -------------------------------------------------------------------------------- /src/0218.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> getSkyline(vector>& buildings) { 4 | vector> res; 5 | multiset> s; 6 | for (auto& x : buildings) { 7 | s.emplace(x[0], -x[2]); 8 | s.emplace(x[1], x[2]); 9 | } 10 | multiset m{0}; 11 | int pre = 0; 12 | int mx = 0; 13 | for (auto& [x, y] : s) { 14 | if (y < 0) { 15 | m.emplace(-y); 16 | } else { 17 | m.erase(m.find(y)); 18 | } 19 | mx = *m.rbegin(); 20 | if (mx != pre) { 21 | res.emplace_back(vector{x, mx}); 22 | pre = mx; 23 | } 24 | } 25 | return res; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /docs/0022.md: -------------------------------------------------------------------------------- 1 | * 回溯法 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector generateParenthesis(int n) { 7 | vector res; 8 | dfs(res, "", n, n); 9 | return res; 10 | } 11 | 12 | void dfs(vector& res, string s, int l_parenthese, int r_parenthese) { 13 | if (l_parenthese == 0 && r_parenthese == 0) { 14 | res.emplace_back(s); 15 | return; 16 | } 17 | if (l_parenthese <= r_parenthese) { 18 | if (l_parenthese > 0) { 19 | dfs(res, s + '(', l_parenthese - 1, r_parenthese); 20 | } 21 | if (r_parenthese > 0) { 22 | dfs(res, s + ')', l_parenthese, r_parenthese - 1); 23 | } 24 | } 25 | } 26 | }; 27 | ``` 28 | -------------------------------------------------------------------------------- /src/0118.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> generate(int numRows) { 4 | vector> dp; 5 | if (numRows == 0) { 6 | return dp; 7 | } 8 | dp.emplace_back(vector{1}); 9 | if (numRows == 1) { 10 | return dp 11 | }; 12 | dp.emplace_back(vector{1, 1}); 13 | if (numRows == 2) { 14 | return dp; 15 | } 16 | for (int i = 2; i < numRows; ++i) { 17 | vector t(i + 1); 18 | t.back() = 1; 19 | t.front() = 1; 20 | for (int j = 1; j < t.size() - 1; ++j) { 21 | t[j] = dp[i - 1][j - 1] + dp[i - 1][j]; 22 | } 23 | dp.emplace_back(t); 24 | } 25 | return dp; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /docs/0189.md: -------------------------------------------------------------------------------- 1 | * 这就是 [std::rotate](https://en.cppreference.com/w/cpp/algorithm/rotate) 的功能,它可以交换两个区间范围内的元素 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | void rotate(vector& nums, int k) { 7 | std::rotate(nums.rbegin(), nums.rbegin() + k % nums.size(), nums.rend()); 8 | } 9 | }; 10 | ``` 11 | 12 | * 原理是三次翻转 13 | 14 | ``` 15 | 1234 567 => 目标 567 1234 16 | 765 4321 17 | 567 1234 18 | ``` 19 | 20 | * 实现如下 21 | 22 | ```cpp 23 | class Solution { 24 | public: 25 | void rotate(vector& nums, int k) { 26 | k %= nums.size(); 27 | reverse(nums.begin(), nums.end()); 28 | reverse(nums.begin(), nums.begin() + k); 29 | reverse(nums.begin() + k, nums.end()); 30 | } 31 | }; 32 | ``` 33 | -------------------------------------------------------------------------------- /src/0098.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | bool isValidBST(TreeNode* root) { 13 | if (!root) { 14 | return true; 15 | } 16 | if (!isValidBST(root->left)) { 17 | return false; 18 | } 19 | if (pre && pre->val >= root->val) { 20 | return false; 21 | } 22 | pre = root; 23 | if (!isValidBST(root->right)) { 24 | return false; 25 | } 26 | return true; 27 | } 28 | 29 | private: 30 | TreeNode* pre = nullptr; 31 | }; 32 | -------------------------------------------------------------------------------- /src/0236.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 13 | if (!root || root == p || root == q) { 14 | return root; 15 | } 16 | TreeNode* l = lowestCommonAncestor(root->left, p, q); 17 | TreeNode* r = lowestCommonAncestor(root->right, p, q); 18 | if (l && r) { // if ((l == p && r == q) || (l == q && r == p)) 19 | return root; 20 | } 21 | return l ? l : r; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/0017.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector letterCombinations(string digits) { 4 | vector res; 5 | if (digits.empty()) { 6 | return res; 7 | } 8 | dfs(digits, res, 0, ""); 9 | return res; 10 | } 11 | 12 | void dfs(string digits, vector& res, int n, string s) { 13 | if (n == digits.size()) { 14 | res.emplace_back(s); 15 | return; 16 | } 17 | for (auto& x : key[digits[n] - '2']) { 18 | s += x; 19 | dfs(digits, res, n + 1, s); 20 | s.pop_back(); 21 | } 22 | } 23 | 24 | private: 25 | const vector key{"abc", "def", "ghi", "jkl", 26 | "mno", "pqrs", "tuv", "wxyz"}; 27 | }; 28 | -------------------------------------------------------------------------------- /src/0056.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> merge(vector>& intervals) { 4 | vector> res; 5 | if (intervals.empty()) { 6 | return res; 7 | } 8 | sort(intervals.begin(), intervals.end(), 9 | [](auto& x, auto& y) { return x[0] < y[0]; }); 10 | for (int i = 0; i < intervals.size() - 1; ++i) { 11 | if (intervals[i][1] < intervals[i + 1][0]) { 12 | res.emplace_back(intervals[i]); 13 | } else { 14 | intervals[i + 1][0] = intervals[i][0]; 15 | intervals[i + 1][1] = max(intervals[i][1], intervals[i + 1][1]); 16 | } 17 | } 18 | res.emplace_back(intervals.back()); 19 | return res; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/0076.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string minWindow(string s, string t) { 4 | unordered_map m; 5 | for (auto& x : t) { 6 | ++m[x]; 7 | } 8 | int minLen = INT_MAX; 9 | int start = 0; 10 | int l = 0; 11 | int cnt = 0; 12 | for (int r = 0; r < s.size(); ++r) { 13 | if (--m[s[r]] >= 0) { 14 | ++cnt; 15 | } 16 | while (cnt == t.size()) { 17 | if (r - l + 1 < minLen) { 18 | minLen = r - l + 1; 19 | start = l; 20 | } 21 | if (++m[s[l]] > 0) { 22 | --cnt; 23 | } 24 | ++l; 25 | } 26 | } 27 | return minLen == INT_MAX ? "" : s.substr(start, minLen); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /src/0039.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> combinationSum(vector& candidates, int target) { 4 | vector> res; 5 | vector t; 6 | dfs(res, t, candidates, 0, target); 7 | return res; 8 | } 9 | 10 | void dfs(vector>& res, vector& t, vector& candidates, 11 | int n, int target) { 12 | if (!target) { 13 | res.emplace_back(t); 14 | return; 15 | } 16 | for (int i = n; i < candidates.size(); ++i) { 17 | if (target - candidates[i] >= 0) { 18 | t.emplace_back(candidates[i]); 19 | dfs(res, t, candidates, i, target - candidates[i]); 20 | t.pop_back(); 21 | } 22 | } 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /src/0033.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int search(vector& nums, int target) { 4 | if (nums.empty()) { 5 | return -1; 6 | } 7 | int l = 0; 8 | int r = nums.size(); 9 | while (l != r) { 10 | int m = l + (r - l) / 2; 11 | if (target == nums[m]) { 12 | return m; 13 | } 14 | if (nums[m] >= nums[l]) { 15 | if (target < nums[m] && target >= nums[l]) { 16 | r = m; 17 | } else { 18 | l = m + 1; 19 | } 20 | } else { 21 | if (target > nums[m] && target <= nums[r - 1]) { 22 | l = m + 1; 23 | } else { 24 | r = m; 25 | } 26 | } 27 | } 28 | return -1; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /docs/0206.md: -------------------------------------------------------------------------------- 1 | * 递归解法 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | ListNode* reverseList(ListNode* head) { 7 | if (!head || !head->next) { 8 | return head; 9 | } 10 | ListNode* t = reverseList(head->next); 11 | head->next->next = head; 12 | head->next = nullptr; 13 | return t; 14 | } 15 | }; 16 | ``` 17 | 18 | * 非递归解法 19 | 20 | ```cpp 21 | class Solution { 22 | public: 23 | ListNode* reverseList(ListNode* head) { 24 | if (!head) return nullptr; 25 | ListNode* pre = nullptr; 26 | ListNode* cur = head; 27 | while (cur) { 28 | ListNode* t = cur->next; 29 | cur->next = pre; 30 | pre = cur; 31 | cur = t; 32 | } 33 | return pre; 34 | } 35 | }; 36 | ``` 37 | -------------------------------------------------------------------------------- /src/0101.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | bool isSymmetric(TreeNode* root) { 13 | if (!root) { 14 | return true; 15 | } 16 | return dfs(root->left, root->right); 17 | } 18 | 19 | bool dfs(TreeNode* l, TreeNode* r) { 20 | if (!l && !r) { 21 | return true; 22 | } 23 | if (!l || !r) { 24 | return false; 25 | } 26 | if (l->val != r->val) { 27 | return false; 28 | } 29 | return dfs(l->left, r->right) && dfs(l->right, r->left); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /src/1117.cpp: -------------------------------------------------------------------------------- 1 | class H2O { 2 | public: 3 | H2O() {} 4 | 5 | void hydrogen(function releaseHydrogen) { 6 | unique_lock l{m1}; 7 | cv.wait(l, [this] { return n < 2; }); 8 | ++n; 9 | // releaseHydrogen() outputs "H". Do not change or remove this line. 10 | releaseHydrogen(); 11 | cv.notify_one(); 12 | } 13 | 14 | void oxygen(function releaseOxygen) { 15 | unique_lock l{m2}; 16 | cv.wait(l, [this] { return n >= 0; }); 17 | n -= 2; 18 | // releaseOxygen() outputs "O". Do not change or remove this line. 19 | releaseOxygen(); 20 | cv.notify_one(); 21 | } 22 | 23 | private: 24 | int n = 0; 25 | mutex m1; 26 | mutex m2; 27 | condition_variable cv; 28 | }; 29 | -------------------------------------------------------------------------------- /src/0071.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string simplifyPath(string path) { 4 | string res; 5 | vector t{split(path, '/')}; 6 | for (auto& x : t) { 7 | res += '/'; 8 | res += x; 9 | } 10 | return res.empty() ? "/" : res; 11 | } 12 | 13 | vector split(const string& s, char delemiter) { 14 | vector res; 15 | istringstream ss{s}; 16 | string t; 17 | while (getline(ss, t, delemiter)) { 18 | if (t.empty() || t == "." || (t == ".." && res.empty())) { 19 | continue; 20 | } else if (t == ".." && !res.empty()) { 21 | res.pop_back(); 22 | } else { 23 | res.emplace_back(t); 24 | } 25 | } 26 | return res; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/0032.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int longestValidParentheses(string s) { 4 | int res = 0; 5 | vector dp(s.size()); 6 | for (int i = 1; i < s.size(); ++i) { 7 | if (s[i] == ')') { 8 | if (s[i - 1] == '(') { 9 | if (i == 1) { 10 | dp[i] = 2; 11 | } else { 12 | dp[i] = dp[i - 2] + 2; 13 | } 14 | } else if (i - dp[i - 1] > 0 && s[i - dp[i - 1] - 1] == '(') { 15 | if (i - dp[i - 1] < 2) { 16 | dp[i] = dp[i - 1] + 2; 17 | } else { 18 | dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2; 19 | } 20 | } 21 | res = max(res, dp[i]); 22 | } 23 | } 24 | return res; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/0621.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int leastInterval(vector& tasks, int n) { 4 | unordered_map m; 5 | for (auto& x : tasks) { 6 | ++m[x]; 7 | } 8 | priority_queue q; 9 | for (auto& x : m) { 10 | q.emplace(x.second); 11 | } 12 | int res = 0; 13 | while (!q.empty()) { 14 | vector v; 15 | int cnt = 0; 16 | for (int i = 0; i < n + 1; ++i) { 17 | if (!q.empty()) { 18 | v.emplace_back(q.top()); 19 | q.pop(); 20 | ++cnt; 21 | } 22 | } 23 | for (auto& x : v) { 24 | if (--x > 0) q.emplace(x); 25 | } 26 | res += q.empty() ? cnt : n + 1; 27 | } 28 | return res; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /docs/0118.md: -------------------------------------------------------------------------------- 1 | * 根据上一行构建下一行即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector> generate(int numRows) { 7 | vector> dp; 8 | if (numRows == 0) { 9 | return dp; 10 | } 11 | dp.emplace_back(vector{1}); 12 | if (numRows == 1) { 13 | return dp 14 | }; 15 | dp.emplace_back(vector{1, 1}); 16 | if (numRows == 2) { 17 | return dp; 18 | } 19 | for (int i = 2; i < numRows; ++i) { 20 | vector t(i + 1); 21 | t.back() = 1; 22 | t.front() = 1; 23 | for (int j = 1; j < t.size() - 1; ++j) { 24 | t[j] = dp[i - 1][j - 1] + dp[i - 1][j]; 25 | } 26 | dp.emplace_back(t); 27 | } 28 | return dp; 29 | } 30 | }; 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/0125.md: -------------------------------------------------------------------------------- 1 | * 用双指针从两侧往中间移动,如果其中出现两侧不等的情况,则不是回文串 2 | 3 | ``` 4 | abcddba 5 | | | 6 | l r 7 | 8 | abcddba 9 | | | 10 | l r 11 | 12 | abcddba 13 | | | 14 | l r 15 | 不等,因此不是回文串 16 | ``` 17 | 18 | * 题目只考虑字母和数字字符,忽略大小写,对这些情况进行处理即可 19 | 20 | ```cpp 21 | class Solution { 22 | public: 23 | bool isPalindrome(string s) { 24 | int l = 0; 25 | int r = s.size() - 1; 26 | while (l < r) { 27 | while (l < r && !isalnum(s[l])) { 28 | ++l; 29 | } 30 | while (l < r && !isalnum(s[r])) { 31 | --r; 32 | } 33 | if (toupper(s[l]) == toupper(s[r])) { 34 | ++l; 35 | --r; 36 | } else { 37 | return false; 38 | } 39 | } 40 | return true; 41 | } 42 | }; 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/0258.md: -------------------------------------------------------------------------------- 1 | * 任意整数与它的各数位上数字的和对 9 同余 2 | 3 | ``` 4 | 若 a ≡ b (mod m),x ≡ y (mod m),则 a + x ≡ b + y (mod m) 5 | 显然对任意自然数 n,a ≡ a * 10 ^ n (mod 9) 6 | 因此对 A = a[0] + a[1] * 10 + a[2] * 100 + ... + a[n] * 10 ^ n 7 | 其各数位上数字和 B = a[0] + a[1] + a[2] + ... + a[n] 8 | 有 A ≡ B (mod 9),即 (A - B) % 9 == 0 9 | ``` 10 | 11 | * 重复相加各数位的过程,最终得到的是一位数 12 | 13 | ``` 14 | (A - B) % 9 == 0 15 | 若 B < 9,则 B = A % 9 16 | 若 B == 9,则 A % 9 == 0 17 | ``` 18 | 19 | * 因此对任意正整数,若能被 9 整除,则各位相加即为 9,否则即为除以 9 的余数,对于 0 则结果为 0 20 | 21 | ```cpp 22 | class Solution { 23 | public: 24 | int addDigits(int num) { 25 | if (!num) { 26 | return 0; 27 | } 28 | int res = num % 9; 29 | if (!res) { 30 | return 9; 31 | } 32 | return res; 33 | } 34 | }; 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/0039.md: -------------------------------------------------------------------------------- 1 | * 回溯法 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector> combinationSum(vector& candidates, int target) { 7 | vector> res; 8 | vector t; 9 | dfs(res, t, candidates, 0, target); 10 | return res; 11 | } 12 | 13 | void dfs(vector>& res, vector& t, vector& candidates, 14 | int n, int target) { 15 | if (!target) { 16 | res.emplace_back(t); 17 | return; 18 | } 19 | for (int i = n; i < candidates.size(); ++i) { 20 | if (target - candidates[i] >= 0) { 21 | t.emplace_back(candidates[i]); 22 | dfs(res, t, candidates, i, target - candidates[i]); 23 | t.pop_back(); 24 | } 25 | } 26 | } 27 | }; 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/0309.md: -------------------------------------------------------------------------------- 1 | * 动态规划,记录第 `i` 天结束时状态为持仓、空仓(非冷冻期)、冷冻期能获得的最大收益。持仓的前一天结束状态只能是持仓或空仓,不能是冷冻期,因为冷冻期的后一天不能买入。空仓的前一天结束状态只能是空仓或冷冻期,不能是持仓,否则当天必须卖出,结束状态是冷冻期。冷冻期的前一天状态必须是持仓,并且当天必须卖出 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int maxProfit(vector& prices) { 7 | int sz = prices.size(); 8 | if (sz < 2) { 9 | return 0; 10 | } 11 | vector hold(sz); // 持仓 12 | vector sold(sz); // 空仓 13 | vector cool(sz); // 冷冻期 14 | hold[0] = -prices[0]; 15 | for (int i = 1; i < sz; ++i) { 16 | hold[i] = max(hold[i - 1], sold[i - 1] - prices[i]); 17 | sold[i] = max(cool[i - 1], sold[i - 1]); 18 | cool[i] = hold[i - 1] + prices[i]; 19 | } 20 | return max(cool[sz - 1], sold[sz - 1]); 21 | } 22 | }; 23 | ``` 24 | -------------------------------------------------------------------------------- /src/0072.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int minDistance(string word1, string word2) { 4 | int m = word1.size(); 5 | int n = word2.size(); 6 | vector> dp(m + 1, vector(n + 1)); 7 | for (int i = 1; i <= m; ++i) { 8 | dp[i][0] = i; 9 | } 10 | for (int i = 1; i <= n; ++i) { 11 | dp[0][i] = i; 12 | } 13 | for (int i = 1; i <= m; ++i) { 14 | for (int j = 1; j <= n; ++j) { 15 | int r = (word1[i - 1] == word2[j - 1]) ? dp[i - 1][j - 1] 16 | : dp[i - 1][j - 1] + 1; 17 | int d = dp[i - 1][j] + 1; 18 | int u = dp[i][j - 1] + 1; 19 | dp[i][j] = min({d, r, u}); 20 | } 21 | } 22 | return dp[m][n]; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /docs/0102.md: -------------------------------------------------------------------------------- 1 | * 将节点存储到队列中,每次循环弹出一层,同时把下一层添加到队列中,队列为空则层次遍历结束 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector> levelOrder(TreeNode* root) { 7 | vector> res; 8 | if (!root) { 9 | return res; 10 | } 11 | queue q; 12 | q.emplace(root); 13 | while (!q.empty()) { 14 | vector line; 15 | int n = q.size(); 16 | while (n--) { 17 | TreeNode* t = q.front(); 18 | q.pop(); 19 | line.emplace_back(t->val); 20 | if (t->left) { 21 | q.emplace(t->left); 22 | } 23 | if (t->right) { 24 | q.emplace(t->right); 25 | } 26 | } 27 | res.emplace_back(line); 28 | } 29 | return res; 30 | } 31 | }; 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/0150.md: -------------------------------------------------------------------------------- 1 | * 把数依次存到栈中,遇到符号时,取出栈顶的两个元素进行计算,再将结果存到栈中。最后栈中仅剩一个元素,即为结果值 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int evalRPN(vector& tokens) { 7 | stack s; 8 | for (auto& x : tokens) { 9 | if (x == "+" || x == "-" || x == "*" || x == "/") { 10 | int b = s.top(); 11 | s.pop(); 12 | int a = s.top(); 13 | s.pop(); 14 | if (x == "+") { 15 | s.emplace(a + b); 16 | } else if (x == "-") { 17 | s.emplace(a - b); 18 | } else if (x == "*") { 19 | s.emplace(a * b); 20 | } else { 21 | s.emplace(a / b); 22 | } 23 | } else { 24 | s.emplace(stoi(x)); 25 | } 26 | } 27 | return s.top(); 28 | } 29 | }; 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/0025.md: -------------------------------------------------------------------------------- 1 | * 翻转前 k 个节点,接着递归处理后续节点 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | ListNode* reverseKGroup(ListNode* head, int k) { 7 | ListNode* next_group_node = head; 8 | int n = k; 9 | while (n--) { 10 | if (!next_group_node) { 11 | return head; 12 | } 13 | next_group_node = next_group_node->next; 14 | } // next_group_node 是下一次递归处理的头节点 15 | // 翻转前 k 个节点 16 | n = k; 17 | ListNode* pre = nullptr; 18 | ListNode* cur = head; 19 | while (--n) { 20 | ListNode* t = cur->next; 21 | cur->next = pre; 22 | pre = cur; 23 | cur = t; 24 | } 25 | cur->next = pre; 26 | // 递归处理后续节点 27 | head->next = reverseKGroup(next_group_node, k); 28 | return cur; 29 | } 30 | }; 31 | ``` 32 | -------------------------------------------------------------------------------- /src/0230.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int kthSmallest(TreeNode* root, int k) { 13 | if (!root) { 14 | return 0; 15 | } 16 | int res = 0; 17 | stack s; 18 | TreeNode* t = root; 19 | while (t || !s.empty()) { 20 | while (t) { 21 | s.emplace(t); 22 | t = t->left; 23 | } 24 | t = s.top(); 25 | s.pop(); 26 | if (k-- == 1) { 27 | res = t->val; 28 | break; 29 | } 30 | t = t->right; 31 | } 32 | return res; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/0328.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* oddEvenList(ListNode* head) { 12 | if (!head || !head->next) { 13 | return head; 14 | } 15 | ListNode* odd = head; 16 | ListNode* even = head->next; 17 | ListNode* evenStart = head->next; 18 | while (odd->next && odd->next->next) { 19 | odd->next = even->next; 20 | odd = odd->next; 21 | even->next = odd->next; 22 | even = even->next; 23 | } 24 | if (even) { 25 | even->next = nullptr; 26 | } 27 | odd->next = evenStart; 28 | return head; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/0165.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int compareVersion(string version1, string version2) { 4 | vector v1{split(version1, '.')}; 5 | vector v2{split(version2, '.')}; 6 | int sz = max(v1.size(), v2.size()); 7 | for (int i = 0; i < sz; ++i) { 8 | int a = i < v1.size() ? v1[i] : 0; 9 | int b = i < v2.size() ? v2[i] : 0; 10 | if (a > b) { 11 | return 1; 12 | } 13 | if (a < b) { 14 | return -1; 15 | } 16 | } 17 | return 0; 18 | } 19 | 20 | vector split(const string& s, char delemiter) { 21 | vector res; 22 | istringstream ss{s}; 23 | string t; 24 | while (getline(ss, t, delemiter)) { 25 | res.emplace_back(stoi(t)); 26 | } 27 | return res; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /docs/0287.md: -------------------------------------------------------------------------------- 1 | * 题目要求 `O(1)` 空间,因此不能用哈希表。将 `i` 与 `nums[i]` 视为链表的相邻节点,如果 `nums[i]` 存在重复元素,则该链表有环 2 | 3 | ``` 4 | nums[i] = 1 3 4 2 2 5 | i = 0 1 2 3 4 6 | 7 | nums[0] = 1 8 | nums[1] = 3 9 | nums[3] = 2 10 | nums[2] = 4 11 | nums[4] = 2 12 | nums[2] = 4 13 | nums[4] = 2 14 | 陷入循环 15 | ``` 16 | 17 | * 用快慢指针找环入口即可 18 | 19 | ```cpp 20 | class Solution { 21 | public: 22 | int findDuplicate(vector& nums) { 23 | int slow = 0; 24 | int fast = 0; 25 | while (true) { 26 | slow = nums[slow]; 27 | fast = nums[nums[fast]]; 28 | if (slow == fast) { 29 | break; 30 | } 31 | } 32 | fast = 0; 33 | while (slow != fast) { // 找环入口 34 | slow = nums[slow]; 35 | fast = nums[fast]; 36 | } 37 | return slow; 38 | } 39 | }; 40 | ``` 41 | -------------------------------------------------------------------------------- /src/0384.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | Solution(vector& nums) { v.assign(nums.begin(), nums.end()); } 4 | 5 | /** Resets the array to its original configuration and return it. */ 6 | vector reset() { return v; } 7 | 8 | /** Returns a random shuffling of the array. */ 9 | vector shuffle() { 10 | vector res{v}; 11 | for (int i = 0; i < res.size(); ++i) { 12 | int t = i + rand() % (res.size() - i); 13 | swap(res[i], res[t]); 14 | } 15 | return res; 16 | } 17 | 18 | private: 19 | vector v; 20 | }; 21 | 22 | /** 23 | * Your Solution object will be instantiated and called as such: 24 | * Solution* obj = new Solution(nums); 25 | * vector param_1 = obj->reset(); 26 | * vector param_2 = obj->shuffle(); 27 | */ 28 | -------------------------------------------------------------------------------- /src/0028.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int strStr(string haystack, string needle) { 4 | if (needle.empty()) { 5 | return 0; 6 | } 7 | vector pi(needle.size()); 8 | for (int i = 1, j = 0; i < pi.size(); ++i) { 9 | while (j > 0 && needle[i] != needle[j]) { 10 | j = pi[j - 1]; 11 | } 12 | if (needle[i] == needle[j]) { 13 | ++j; 14 | } 15 | pi[i] = j; 16 | } 17 | for (int i = 0, j = 0; i < haystack.size(); ++i) { 18 | while (j > 0 && haystack[i] != needle[j]) { 19 | j = pi[j - 1]; 20 | } 21 | if (haystack[i] == needle[j]) { 22 | ++j; 23 | } 24 | if (j == needle.size()) { 25 | return i - needle.size() + 1; 26 | } 27 | } 28 | return -1; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/0207.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canFinish(int numCourses, vector>& prerequisites) { 4 | unordered_map> m; 5 | vector indegree(numCourses); 6 | for (auto& x : prerequisites) { 7 | m[x[1]].emplace_back(x[0]); 8 | ++indegree[x[0]]; 9 | } 10 | queue q; 11 | for (int i = 0; i < indegree.size(); ++i) { 12 | if (!indegree[i]) { 13 | q.emplace(i); 14 | } 15 | } 16 | int cnt = 0; 17 | while (!q.empty()) { 18 | int n = q.front(); 19 | q.pop(); 20 | ++cnt; 21 | for (auto& x : m[n]) { 22 | --indegree[x]; 23 | if (!indegree[x]) { 24 | q.emplace(x); 25 | } 26 | } 27 | } 28 | return cnt == numCourses; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /docs/0071.md: -------------------------------------------------------------------------------- 1 | * 将字符串按 `/` 分割出目录名再逐个判断即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | string simplifyPath(string path) { 7 | string res; 8 | vector t{split(path, '/')}; 9 | for (auto& x : t) { 10 | res += '/'; 11 | res += x; 12 | } 13 | return res.empty() ? "/" : res; 14 | } 15 | 16 | vector split(const string& s, char delemiter) { 17 | vector res; 18 | istringstream ss{s}; 19 | string t; 20 | while (getline(ss, t, delemiter)) { 21 | if (t.empty() || t == "." || (t == ".." && res.empty())) { 22 | continue; 23 | } else if (t == ".." && !res.empty()) { 24 | res.pop_back(); 25 | } else { 26 | res.emplace_back(t); 27 | } 28 | } 29 | return res; 30 | } 31 | }; 32 | ``` 33 | -------------------------------------------------------------------------------- /src/0227.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int calculate(string s) { 4 | stack data; 5 | string operand{"+"}; 6 | char op = '+'; 7 | s += '$'; 8 | for (auto& x : s) { 9 | if (x == ' ') { 10 | continue; 11 | } 12 | if (isdigit(x)) { 13 | operand += x; 14 | } else { 15 | if (op == '*') { 16 | data.top() *= stoi(operand); 17 | } else if (op == '/') { 18 | data.top() /= stoi(operand); 19 | } else { 20 | data.emplace(stoi(operand)); 21 | } 22 | operand = x == '-' ? "-" : "+"; 23 | op = x; 24 | } 25 | } 26 | int res = 0; 27 | while (!data.empty()) { 28 | res += data.top(); 29 | data.pop(); 30 | } 31 | return res; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/0235.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | 11 | class Solution { 12 | public: 13 | TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 14 | if (!root) { 15 | return nullptr; 16 | } 17 | if (!p) { 18 | return q; 19 | } 20 | if (!q) { 21 | return p; 22 | } 23 | if (root->val > p->val && root->val > q->val) { 24 | return lowestCommonAncestor(root->left, p, q); 25 | } 26 | if (root->val < p->val && root->val < q->val) { 27 | return lowestCommonAncestor(root->right, p, q); 28 | } 29 | return root; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /docs/0162.md: -------------------------------------------------------------------------------- 1 | * 用 [std::adjacent_find](https://en.cppreference.com/w/cpp/algorithm/adjacent_find) 查找首个降序元素对,时间复杂度 `O(n)` 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int findPeakElement(vector& nums) { 7 | auto it = adjacent_find(nums.begin(), nums.end(), greater{}); 8 | return it == nums.end() ? nums.size() - 1 : it - nums.begin(); 9 | } 10 | }; 11 | ``` 12 | 13 | * 二分查找,时间复杂度 `O(log n)` 14 | 15 | ```cpp 16 | class Solution { 17 | public: 18 | int findPeakElement(vector& nums) { 19 | int l = 0; 20 | int r = nums.size(); 21 | while (l < r) { 22 | int m = l + (r - l) / 2; 23 | if (m > 0 && nums[m] < nums[m - 1]) { 24 | r = m; 25 | } else { 26 | l = m + 1; 27 | } 28 | } 29 | return l - 1; 30 | } 31 | }; 32 | ``` 33 | -------------------------------------------------------------------------------- /src/0437.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int pathSum(TreeNode* root, int sum) { 13 | if (!root) { 14 | return 0; 15 | } 16 | int res = 0; 17 | dfs(root, res, sum); 18 | res += pathSum(root->left, sum); 19 | res += pathSum(root->right, sum); 20 | return res; 21 | } 22 | 23 | void dfs(TreeNode* root, int& res, int n) { 24 | if (!root) { 25 | return; 26 | } 27 | if (root->val == n) { 28 | ++res; 29 | } 30 | dfs(root->left, res, n - root->val); 31 | dfs(root->right, res, n - root->val); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/0116.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | // Definition for a Node. 3 | class Node { 4 | public: 5 | int val; 6 | Node* left; 7 | Node* right; 8 | Node* next; 9 | 10 | Node() : val(0), left(NULL), right(NULL), next(NULL) {} 11 | 12 | Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} 13 | 14 | Node(int _val, Node* _left, Node* _right, Node* _next) 15 | : val(_val), left(_left), right(_right), next(_next) {} 16 | }; 17 | */ 18 | class Solution { 19 | public: 20 | Node* connect(Node* root) { 21 | if (!root) { 22 | return nullptr; 23 | } 24 | if (root->left) { 25 | root->left->next = root->right; 26 | if (root->next) root->right->next = root->next->left; 27 | } 28 | connect(root->left); 29 | connect(root->right); 30 | return root; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /src/0912.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector sortArray(vector &nums) { 4 | heapSort(nums); 5 | return nums; 6 | } 7 | 8 | void heapSort(vector &nums) { 9 | for (int i = nums.size() / 2 - 1; i >= 0; --i) { 10 | adjustHeap(nums, i, nums.size()); 11 | } 12 | for (int i = nums.size() - 1; i > 0; --i) { 13 | swap(nums[0], nums[i]); 14 | adjustHeap(nums, 0, i); 15 | } 16 | } 17 | 18 | void adjustHeap(vector &nums, int i, int m) { 19 | while (2 * i + 1 < m) { 20 | int l = 2 * i + 1; 21 | int r = 2 * i + 2; 22 | int mx = r < m && nums[l] < nums[r] ? r : l; 23 | if (nums[i] < nums[mx]) { 24 | swap(nums[i], nums[mx]); 25 | i = mx; 26 | } else { 27 | break; 28 | } 29 | } 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /docs/0062.md: -------------------------------------------------------------------------------- 1 | * 动态规划 2 | 3 | ``` 4 | $$$ 5 | $$b 6 | $a@ 7 | 8 | 到达 @ 之前,必然先到达 a 或 b 9 | 因此到达 @ 的路径数 = 到达 a 的路径数 + 到达 b 的路径数 10 | ``` 11 | 12 | * 对于位于边界上的位置,只可能有一条直线路径,因此可作为初始解,再用其计算其他位置 13 | 14 | ``` 15 | @@@ 111 111 111 16 | @$$ => 1$$ => 123 => 123 17 | @$$ 1$$ 1$$ 136 18 | 19 | 结果为6 20 | ``` 21 | 22 | * 解法如下 23 | 24 | ```cpp 25 | class Solution { 26 | public: 27 | int uniquePaths(int m, int n) { 28 | vector> dp(m, vector(n)); 29 | for (int i = 0; i < n; ++i) { 30 | dp[0][i] = 1; 31 | } 32 | for (int i = 0; i < m; ++i) { 33 | dp[i][0] = 1; 34 | } 35 | for (int i = 1; i < m; ++i) { 36 | for (int j = 1; j < n; ++j) { 37 | dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; 38 | } 39 | } 40 | return dp[m - 1][n - 1]; 41 | } 42 | }; 43 | ``` 44 | -------------------------------------------------------------------------------- /src/0215.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findKthLargest(vector& nums, int k) { 4 | return nth(nums, 0, nums.size() - 1, nums.size() - k); 5 | } 6 | 7 | int nth(vector& nums, int l, int r, int k) { 8 | int n = partition(nums, l, r); 9 | if (n == k) { 10 | return nums[n]; 11 | } 12 | return n > k ? nth(nums, l, n - 1, k) : nth(nums, n + 1, r, k); 13 | } 14 | 15 | int partition(vector& nums, int l, int r) { 16 | int i = l; 17 | int j = r; 18 | while (i < j) { 19 | while (i < j && nums[j] >= nums[l]) { 20 | --j; 21 | } 22 | while (i < j && nums[i] <= nums[l]) { 23 | ++i; 24 | } 25 | if (i < j) { 26 | swap(nums[i], nums[j]); 27 | } 28 | } 29 | swap(nums[i], nums[l]); 30 | return i; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /docs/0450.md: -------------------------------------------------------------------------------- 1 | ```cpp 2 | class Solution { 3 | public: 4 | TreeNode* deleteNode(TreeNode* root, int key) { 5 | if (!root) { 6 | return nullptr; 7 | } 8 | if (key > root->val) { 9 | root->right = deleteNode(root->right, key); 10 | return root; 11 | } 12 | if (key < root->val) { 13 | root->left = deleteNode(root->left, key); 14 | return root; 15 | } 16 | if (!root->left || !root->right) { 17 | TreeNode* t = root->left ? root->left : root->right; 18 | delete root; 19 | root = nullptr; 20 | return t; 21 | } 22 | TreeNode* t = root->right; 23 | while (t->left) { 24 | t = t->left; // 右子树最左节点,即值大于根节点的下一节点 25 | } 26 | swap(root->val, t->val); 27 | root->right = deleteNode(root->right, key); 28 | return root; 29 | } 30 | }; 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/0165.md: -------------------------------------------------------------------------------- 1 | * 将字符串按 `.` 分割出修订号再逐个判断即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int compareVersion(string version1, string version2) { 7 | vector v1{split(version1, '.')}; 8 | vector v2{split(version2, '.')}; 9 | int sz = max(v1.size(), v2.size()); 10 | for (int i = 0; i < sz; ++i) { 11 | int a = i < v1.size() ? v1[i] : 0; 12 | int b = i < v2.size() ? v2[i] : 0; 13 | if (a > b) { 14 | return 1; 15 | } 16 | if (a < b) { 17 | return -1; 18 | } 19 | } 20 | return 0; 21 | } 22 | 23 | vector split(const string& s, char delemiter) { 24 | vector res; 25 | istringstream ss{s}; 26 | string t; 27 | while (getline(ss, t, delemiter)) { 28 | res.emplace_back(stoi(t)); 29 | } 30 | return res; 31 | } 32 | }; 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/0371.md: -------------------------------------------------------------------------------- 1 | * 异或运算可以看成不进位的加法,与运算则可以获取要进位的位置 2 | 3 | ``` 4 | 0 ^ 0 = 0 5 | 0 ^ 1 = 1 6 | 1 ^ 0 = 1 7 | 1 ^ 1 = 0 8 | 9 | 0 & 0 = 0 10 | 0 & 1 = 0 11 | 1 & 0 = 0 12 | 1 & 1 = 1 13 | 14 | 计算 0101 + 0011 15 | 0101 ^ 0011 = 0110 => 未进位的结果 16 | 0101 & 0011 = 0001 => 为 1 的位置要进位,左移后与未进位结果相加即可 17 | 18 | 计算 0110 + 0010 19 | 0110 ^ 0010 = 0100 20 | 0110 & 0010 = 0010 21 | 22 | 计算 0100 + 0100 23 | 0100 ^ 0100 = 0000 24 | 0100 & 0100 = 0100 25 | 26 | 计算 0000 + 1000 27 | 0000 ^ 1000 = 1000 28 | 0000 & 1000 = 0000 => 无进位值,结束 29 | 30 | 结果即为 1000 31 | ``` 32 | 33 | * 解法如下 34 | 35 | ```cpp 36 | class Solution { 37 | public: 38 | int getSum(int a, int b) { 39 | int sum = a ^ b; 40 | int carry = static_cast(a & b) << 1; 41 | if (carry) { 42 | return getSum(sum, carry); 43 | } 44 | return sum; 45 | } 46 | }; 47 | ``` 48 | -------------------------------------------------------------------------------- /src/0155.cpp: -------------------------------------------------------------------------------- 1 | class MinStack { 2 | public: 3 | /** initialize your data structure here. */ 4 | MinStack() {} 5 | 6 | void push(int x) { 7 | stackAll.emplace(x); 8 | if (stackMin.empty() || x <= stackMin.top()) { 9 | stackMin.emplace(x); 10 | } 11 | } 12 | 13 | void pop() { 14 | if (stackAll.top() == stackMin.top()) { 15 | stackMin.pop(); 16 | } 17 | stackAll.pop(); 18 | } 19 | 20 | int top() { return stackAll.top(); } 21 | 22 | int getMin() { return stackMin.top(); } 23 | 24 | private: 25 | stack stackAll; 26 | stack stackMin; 27 | }; 28 | 29 | /** 30 | * Your MinStack object will be instantiated and called as such: 31 | * MinStack* obj = new MinStack(); 32 | * obj->push(x); 33 | * obj->pop(); 34 | * int param_3 = obj->top(); 35 | * int param_4 = obj->getMin(); 36 | */ 37 | -------------------------------------------------------------------------------- /src/0589.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | // Definition for a Node. 3 | class Node { 4 | public: 5 | int val; 6 | vector children; 7 | 8 | Node() {} 9 | 10 | Node(int _val) { 11 | val = _val; 12 | } 13 | 14 | Node(int _val, vector _children) { 15 | val = _val; 16 | children = _children; 17 | } 18 | }; 19 | */ 20 | class Solution { 21 | public: 22 | vector preorder(Node* root) { 23 | vector res; 24 | if (!root) { 25 | return res; 26 | } 27 | stack s; 28 | s.emplace(root); 29 | while (!s.empty()) { 30 | Node* t = s.top(); 31 | res.emplace_back(t->val); 32 | s.pop(); 33 | for (auto it = t->children.rbegin(); it != t->children.rend(); ++it) { 34 | s.emplace(*it); 35 | } 36 | } 37 | return res; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /src/0145.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector postorderTraversal(TreeNode* root) { 13 | vector res; 14 | stack s; 15 | TreeNode* t = root; 16 | TreeNode* last = root; 17 | while (t || !s.empty()) { 18 | while (t) { 19 | s.emplace(t); 20 | t = t->left; 21 | } 22 | t = s.top(); 23 | if (!t->right || t->right == last) { 24 | s.pop(); 25 | res.emplace_back(t->val); 26 | last = t; 27 | t = nullptr; 28 | } else { 29 | t = t->right; 30 | } 31 | } 32 | return res; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/0010.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isMatch(string s, string p) { 4 | vector> dp(s.size() + 1, vector(p.size() + 1)); 5 | dp[0][0] = true; 6 | for (int i = 2; i < dp[0].size(); i += 2) { 7 | if (p[i - 1] != '*') { 8 | break; 9 | } 10 | dp[0][i] = true; 11 | } 12 | for (int i = 0; i < s.size(); ++i) { 13 | for (int j = 0; j < p.size(); ++j) { 14 | if (s[i] == p[j] || p[j] == '.') { 15 | dp[i + 1][j + 1] = dp[i][j]; 16 | } else if (p[j] == '*') { 17 | dp[i + 1][j + 1] = dp[i + 1][j - 1]; 18 | if (s[i] == p[j - 1] || p[j - 1] == '.') { 19 | dp[i + 1][j + 1] = dp[i + 1][j + 1] || dp[i + 1][j] || dp[i][j + 1]; 20 | } 21 | } 22 | } 23 | } 24 | return dp[s.size()][p.size()]; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/0722.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector removeComments(vector& source) { 4 | bool in_comment = false; 5 | vector res; 6 | string s; 7 | for (auto& x : source) { 8 | for (int i = 0; i < x.size(); ++i) { 9 | string t{x.substr(i, 2)}; 10 | if (in_comment) { 11 | if (t == "*/") { 12 | in_comment = false; 13 | ++i; 14 | } 15 | continue; 16 | } 17 | if (t == "/*") { 18 | ++i; 19 | in_comment = true; 20 | continue; 21 | } 22 | if (t == "//") { 23 | break; 24 | } 25 | s += x[i]; 26 | } 27 | if (!in_comment && !s.empty()) { 28 | res.emplace_back(s); 29 | s.clear(); 30 | } 31 | } 32 | return res; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /docs/0234.md: -------------------------------------------------------------------------------- 1 | * 从中点拆分为两个链表,翻转一个再与另一个对比即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool isPalindrome(ListNode* head) { 7 | if (!head || !head->next) { 8 | return true; 9 | } 10 | ListNode* slow = head; 11 | ListNode* fast = head; 12 | while (fast && fast->next) { 13 | slow = slow->next; 14 | fast = fast->next->next; 15 | } // slow现在为中点,拆分出以slow为头节点的链表 16 | ListNode* pre = nullptr; 17 | while (slow) { // 翻转拆分出的链表 18 | ListNode* t = slow->next; 19 | slow->next = pre; 20 | pre = slow; 21 | slow = t; 22 | } // pre为翻转后的链表头节点 23 | ListNode* cur = head; 24 | while (pre) { // 对比两个链表 25 | if (cur->val != pre->val) { 26 | return false; 27 | } 28 | cur = cur->next; 29 | pre = pre->next; 30 | } 31 | return true; 32 | } 33 | }; 34 | ``` 35 | -------------------------------------------------------------------------------- /src/0590.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | // Definition for a Node. 3 | class Node { 4 | public: 5 | int val; 6 | vector children; 7 | 8 | Node() {} 9 | 10 | Node(int _val) { 11 | val = _val; 12 | } 13 | 14 | Node(int _val, vector _children) { 15 | val = _val; 16 | children = _children; 17 | } 18 | }; 19 | */ 20 | class Solution { 21 | public: 22 | vector postorder(Node* root) { 23 | vector res; 24 | if (!root) { 25 | return res; 26 | } 27 | stack> s; 28 | s.emplace(root, 0); 29 | while (!s.empty()) { 30 | auto& [t, i] = s.top(); 31 | if (i == t->children.size()) { 32 | res.emplace_back(t->val); 33 | s.pop(); 34 | } else { 35 | s.emplace(t->children[i++], 0); 36 | } 37 | } 38 | return res; 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /src/0650.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int minSteps(int n) { 4 | vector t{primers(n)}; 5 | int res = 0; 6 | while (n > 1) { 7 | for (auto& x : t) { 8 | if (n % x == 0) { 9 | n /= x; 10 | res += x; 11 | break; 12 | } 13 | } 14 | } 15 | return res; 16 | } 17 | 18 | vector primers(int n) { 19 | vector res; 20 | if (n < 2) { 21 | return res; 22 | } 23 | vector dp(n + 1, true); 24 | for (int i = 2; i < dp.size(); ++i) { 25 | if (dp[i]) { 26 | res.emplace_back(i); 27 | } 28 | for (int j = 0; j < res.size() && i * res[j] < dp.size(); ++j) { 29 | dp[i * res[j]] = false; 30 | if (i % res[j] == 0) { 31 | break; 32 | } 33 | } 34 | } 35 | return res; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /src/0047.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> permuteUnique(vector& nums) { 4 | sort(nums.begin(), nums.end()); 5 | vector> res; 6 | do { 7 | res.emplace_back(nums); 8 | nextPermutation(nums); 9 | } while (!is_sorted(nums.begin(), nums.end())); 10 | return res; 11 | } 12 | 13 | void nextPermutation(vector& nums) { 14 | if (nums.size() <= 1) { 15 | return; 16 | } 17 | for (int i = nums.size() - 1; i > 0; --i) { 18 | if (nums[i - 1] < nums[i]) { 19 | sort(nums.begin() + i, nums.end()); 20 | for (int j = i; j < nums.size(); ++j) { 21 | if (nums[j] > nums[i - 1]) { 22 | swap(nums[i - 1], nums[j]); 23 | return; 24 | } 25 | } 26 | } 27 | } 28 | reverse(nums.begin(), nums.end()); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/0174.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int calculateMinimumHP(vector>& dungeon) { 4 | if (dungeon.empty() || dungeon[0].empty()) { 5 | return 1; 6 | } 7 | int m = dungeon.size(); 8 | int n = dungeon[0].size(); 9 | vector> dp(m, vector(n)); 10 | dp.back().back() = max(1, 1 - dungeon.back().back()); 11 | for (int i = m - 2; i >= 0; --i) { 12 | dp[i].back() = max(1, dp[i + 1].back() - dungeon[i].back()); 13 | } 14 | for (int i = n - 2; i >= 0; --i) { 15 | dp.back()[i] = max(1, dp.back()[i + 1] - dungeon.back()[i]); 16 | } 17 | for (int i = m - 2; i >= 0; --i) { 18 | for (int j = n - 2; j >= 0; --j) { 19 | int tmp = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]; 20 | dp[i][j] = max(1, tmp); 21 | } 22 | } 23 | return dp[0][0]; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /docs/0007.md: -------------------------------------------------------------------------------- 1 | * 简单的防溢出的做法是使用 long 类型作为返回值,只需要在最后判断溢出 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int reverse(int x) { 7 | long res = 0; 8 | while (x) { 9 | res = res * 10 + x % 10; 10 | x /= 10; 11 | } 12 | if (res > INT_MAX || res < INT_MIN) { 13 | return 0; 14 | } 15 | return res; 16 | } 17 | }; 18 | ``` 19 | 20 | * 使用 int 则每次都需要判断下一次是否溢出 21 | 22 | ```cpp 23 | class Solution { 24 | public: 25 | int reverse(int x) { 26 | int res = 0; 27 | while (x) { 28 | int t = x % 10; 29 | if (res > INT_MAX / 10 || (res == INT_MAX / 10 && t > (INT_MAX % 10))) { 30 | return 0; 31 | } 32 | if (res < INT_MIN / 10 || (res == INT_MIN / 10 && t < (INT_MIN % 10))) { 33 | return 0; 34 | } 35 | res = res * 10 + t; 36 | x /= 10; 37 | } 38 | return res; 39 | } 40 | }; 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/0088.md: -------------------------------------------------------------------------------- 1 | * 从后往前添加 2 | 3 | ``` 4 | *添加6 5 | [1,2,3,0,0,0] 6 | | 7 | [2,5,6] 8 | 9 | *添加5 10 | [1,2,3,0,0,6] 11 | | 12 | [2,5,6] 13 | 14 | *添加3 15 | [1,2,3,0,5,6] 16 | | 17 | [2,5,6] 18 | 19 | *添加2 20 | [1,2,3,3,5,6] 21 | | 22 | [2,5,6] 23 | 24 | *nums2 访问结束,此时的 nums1 即为结果 25 | [1,2,2,3,5,6] 26 | | 27 | [2,5,6] 28 | ``` 29 | 30 | * 实现如下 31 | 32 | ```cpp 33 | class Solution { 34 | public: 35 | void merge(vector& nums1, int m, vector& nums2, int n) { 36 | while (m && n) { 37 | if (nums1[m - 1] > nums2[n - 1]) { 38 | nums1[m + n - 1] = nums1[m - 1]; 39 | --m; 40 | } else { 41 | nums1[m + n - 1] = nums2[n - 1]; 42 | --n; 43 | } 44 | } 45 | while (n--) { // nums2 仍有剩余元素 46 | nums1[n] = nums2[n]; 47 | } 48 | } 49 | }; 50 | ``` 51 | -------------------------------------------------------------------------------- /src/0210.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector findOrder(int numCourses, vector>& prerequisites) { 4 | unordered_map> m; 5 | vector indegree(numCourses); 6 | for (auto& x : prerequisites) { 7 | m[x[1]].emplace_back(x[0]); 8 | ++indegree[x[0]]; 9 | } 10 | queue q; 11 | for (int i = 0; i < indegree.size(); ++i) { 12 | if (!indegree[i]) { 13 | q.emplace(i); 14 | } 15 | } 16 | vector res; 17 | while (!q.empty()) { 18 | int n = q.front(); 19 | q.pop(); 20 | res.emplace_back(n); 21 | for (auto& x : m[n]) { 22 | --indegree[x]; 23 | if (!indegree[x]) { 24 | q.emplace(x); 25 | } 26 | } 27 | } 28 | if (res.size() < numCourses) { 29 | return {}; 30 | } 31 | return res; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /docs/0283.md: -------------------------------------------------------------------------------- 1 | * [std::remove](https://en.cppreference.com/w/cpp/io/c/remove) 的功能就是把所有不为目标值的元素,覆盖到容器开头,最后返回覆盖结束后一位置的迭代器 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | void moveZeroes(vector& nums) { 7 | for_each(remove(nums.begin(), nums.end(), 0), nums.end(), 8 | [](int& x) { x = 0; }); 9 | } 10 | }; 11 | ``` 12 | 13 | * 过程如下 14 | 15 | ``` 16 | 01034 => 将 134 覆盖到开头 => 13434 => 返回第二个 3 的位置 17 | 对返回位置及其之后位置置零 => 13400 18 | ``` 19 | 20 | * 解法如下 21 | 22 | ```cpp 23 | class Solution { 24 | public: 25 | void moveZeroes(vector& nums) { 26 | int l = 0; 27 | int cur = 0; 28 | while (cur < nums.size()) { 29 | if (nums[cur] == 0) { 30 | ++cur; 31 | } else { 32 | nums[l++] = nums[cur++]; 33 | } 34 | } 35 | for (int i = l; i < nums.size(); ++i) { 36 | nums[i] = 0; 37 | } 38 | } 39 | }; 40 | ``` 41 | -------------------------------------------------------------------------------- /src/0114.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | void flatten(TreeNode* root) { 13 | while (root) { 14 | if (root->left) { 15 | TreeNode* t = getLeftMostRight(root); 16 | if (t) { 17 | t->right = root->right; 18 | root->right = root->left; 19 | root->left = nullptr; 20 | } 21 | } 22 | root = root->right; 23 | } 24 | } 25 | 26 | TreeNode* getLeftMostRight(TreeNode* root) { 27 | if (!root || !root->left) { 28 | return nullptr; 29 | } 30 | TreeNode* t = root->left; 31 | while (t->right) { 32 | t = t->right; 33 | } 34 | return t; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /src/0131.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> partition(string s) { 4 | vector> res; 5 | if (s.empty()) { 6 | return res; 7 | } 8 | vector t; 9 | dfs(res, t, s, 0); 10 | return res; 11 | } 12 | 13 | void dfs(vector>& res, vector& t, string_view s, 14 | int n) { 15 | if (n == s.size()) { 16 | res.emplace_back(t); 17 | return; 18 | } 19 | for (int i = n; i < s.size(); ++i) { 20 | if (isValid(s, n, i)) { 21 | t.emplace_back(s.substr(n, i - n + 1)); 22 | dfs(res, t, s, i + 1); 23 | t.pop_back(); 24 | } 25 | } 26 | } 27 | 28 | bool isValid(string_view s, int l, int r) { 29 | while (l < r) { 30 | if (s[l++] != s[r--]) { 31 | return false; 32 | } 33 | } 34 | return true; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /src/0008.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int myAtoi(string s) { 4 | if (s.empty()) { 5 | return 0; 6 | } 7 | long res = 0; 8 | int cur = 0; 9 | bool postive = true; 10 | while (cur < s.size() && s[cur] == ' ') { 11 | ++cur; 12 | } 13 | if (cur >= s.size()) { 14 | return 0; 15 | } 16 | if (s[cur] == '+') { 17 | ++cur; 18 | } else if (s[cur] == '-') { 19 | postive = false; 20 | ++cur; 21 | } 22 | while (cur < s.size() && isdigit(s[cur])) { 23 | if (res > INT_MAX) { 24 | break; 25 | } 26 | res = res * 10 + (s[cur] - '0'); 27 | ++cur; 28 | } 29 | if (!postive) { 30 | res = -res; 31 | } 32 | if (res >= INT_MAX) { 33 | return INT_MAX; 34 | } 35 | if (res <= INT_MIN) { 36 | return INT_MIN; 37 | } 38 | return res; 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /docs/0722.md: -------------------------------------------------------------------------------- 1 | * 依次遍历每一行即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector removeComments(vector& source) { 7 | bool in_comment = false; 8 | vector res; 9 | string s; 10 | for (auto& x : source) { 11 | for (int i = 0; i < x.size(); ++i) { 12 | string t{x.substr(i, 2)}; 13 | if (in_comment) { 14 | if (t == "*/") { 15 | in_comment = false; 16 | ++i; 17 | } 18 | continue; 19 | } 20 | if (t == "/*") { 21 | ++i; 22 | in_comment = true; 23 | continue; 24 | } 25 | if (t == "//") { 26 | break; 27 | } 28 | s += x[i]; 29 | } 30 | if (!in_comment && !s.empty()) { 31 | res.emplace_back(s); 32 | s.clear(); 33 | } 34 | } 35 | return res; 36 | } 37 | }; 38 | ``` 39 | -------------------------------------------------------------------------------- /src/0213.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int rob(vector& nums) { 4 | if (nums.empty()) { 5 | return 0; 6 | } 7 | int sz = nums.size(); 8 | if (sz == 1) { 9 | return nums[0]; 10 | } 11 | if (sz == 2) { 12 | return max(nums[0], nums[1]); 13 | } 14 | vector dp_no_first(sz); 15 | vector dp_no_last(sz - 1); 16 | dp_no_first[1] = nums[1]; 17 | dp_no_first[2] = max(nums[1], nums[2]); 18 | dp_no_last[0] = nums[0]; 19 | dp_no_last[1] = max(nums[0], nums[1]); 20 | for (int i = 3; i < dp_no_first.size(); ++i) { 21 | dp_no_first[i] = max(dp_no_first[i - 1], dp_no_first[i - 2] + nums[i]); 22 | } 23 | for (int i = 2; i < dp_no_last.size(); ++i) { 24 | dp_no_last[i] = max(dp_no_last[i - 1], dp_no_last[i - 2] + nums[i]); 25 | } 26 | return max(dp_no_first.back(), dp_no_last.back()); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /docs/0053.md: -------------------------------------------------------------------------------- 1 | * 遍历每个数,计算以当前数为子数组尾元素时的最大和。当上次的和为负数时,则从当前数开始重新计算和 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int maxSubArray(vector& nums) { 7 | int res = INT_MIN; 8 | int sum = 0; 9 | for (auto& x : nums) { 10 | if (sum >= 0) { 11 | sum += x; 12 | } else { 13 | sum = x; 14 | } 15 | res = max(res, sum); 16 | } 17 | return res; 18 | } 19 | }; 20 | ``` 21 | 22 | * 动态规划,`dp[i]` 表示以 `nums[i]` 为子数组尾元素时的最大和 23 | 24 | ```cpp 25 | class Solution { 26 | public: 27 | int maxSubArray(vector& nums) { 28 | if (nums.empty()) { 29 | return 0; 30 | } 31 | vector dp(nums.size()); 32 | dp[0] = nums[0]; 33 | int res = dp[0]; 34 | for (int i = 1; i < dp.size(); ++i) { 35 | dp[i] = max(nums[i], dp[i - 1] + nums[i]); 36 | res = max(res, dp[i]); 37 | } 38 | return res; 39 | } 40 | }; 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/0312.md: -------------------------------------------------------------------------------- 1 | * 动态规划,`dp[i][j]` 表示 `i` 到 `j` 的区间(不戳破 `i` 和 `j`)能获得最大收益,`k` 为该区间内最后一个戳破的气球,状态转移方程为 2 | 3 | ``` 4 | dp[i][j] = max(dp[i][j], dp[i][k] + dp[k][j] + nums[i] * nums[k] * nums[j]); 5 | 6 | k 为最后戳破,所以最后 ijk 相邻 7 | 依次令 k = i + 1、i + 2、...、j - 1 8 | 其中得到的最大值即为 dp[i][j] 9 | ``` 10 | 11 | * 解法如下 12 | 13 | ```cpp 14 | class Solution { 15 | public: 16 | int maxCoins(vector& nums) { 17 | nums.emplace(nums.begin(), 1); 18 | nums.emplace_back(1); 19 | int sz = nums.size(); 20 | vector> dp(sz, vector(sz)); 21 | for (int n = 2; n < sz; ++n) { 22 | for (int i = 0; i + n < sz; ++i) { 23 | for (int j = i + 1; j < i + n; ++j) { 24 | int t = dp[i][j] + dp[j][i + n] + nums[i] * nums[j] * nums[i + n]; 25 | dp[i][i + n] = max(dp[i][i + n], t); 26 | } 27 | } 28 | } 29 | return dp[0][sz - 1]; 30 | } 31 | }; 32 | ``` 33 | -------------------------------------------------------------------------------- /src/0034.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector searchRange(vector& nums, int target) { 4 | int a = lowerBound(nums, 0, nums.size(), target); 5 | int b = upperBound(nums, 0, nums.size(), target); 6 | return {a, b}; 7 | } 8 | 9 | int lowerBound(vector& nums, int l, int r, int target) { 10 | while (l != r) { 11 | int m = l + (r - l) / 2; 12 | if (nums[m] >= target) { 13 | r = m; 14 | } else { 15 | l = m + 1; 16 | } 17 | } 18 | return l < nums.size() && nums[l] == target ? l : -1; 19 | } 20 | 21 | int upperBound(vector& nums, int l, int r, int target) { 22 | while (l != r) { 23 | int m = l + (r - l) / 2; 24 | if (nums[m] > target) { 25 | r = m; 26 | } else { 27 | l = m + 1; 28 | } 29 | } 30 | return l > 0 && nums[l - 1] == target ? l - 1 : -1; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /docs/0131.md: -------------------------------------------------------------------------------- 1 | * 回溯法 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector> partition(string s) { 7 | vector> res; 8 | if (s.empty()) { 9 | return res; 10 | } 11 | vector t; 12 | dfs(res, t, s, 0); 13 | return res; 14 | } 15 | 16 | void dfs(vector>& res, vector& t, string_view s, 17 | int n) { 18 | if (n == s.size()) { 19 | res.emplace_back(t); 20 | return; 21 | } 22 | for (int i = n; i < s.size(); ++i) { 23 | if (isValid(s, n, i)) { 24 | t.emplace_back(s.substr(n, i - n + 1)); 25 | dfs(res, t, s, i + 1); 26 | t.pop_back(); 27 | } 28 | } 29 | } 30 | 31 | bool isValid(string_view s, int l, int r) { 32 | while (l < r) { 33 | if (s[l++] != s[r--]) { 34 | return false; 35 | } 36 | } 37 | return true; 38 | } 39 | }; 40 | ``` 41 | -------------------------------------------------------------------------------- /src/0102.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector> levelOrder(TreeNode* root) { 13 | vector> res; 14 | if (!root) { 15 | return res; 16 | } 17 | queue q; 18 | q.emplace(root); 19 | while (!q.empty()) { 20 | vector line; 21 | int n = q.size(); 22 | while (n--) { 23 | TreeNode* t = q.front(); 24 | q.pop(); 25 | line.emplace_back(t->val); 26 | if (t->left) { 27 | q.emplace(t->left); 28 | } 29 | if (t->right) { 30 | q.emplace(t->right); 31 | } 32 | } 33 | res.emplace_back(line); 34 | } 35 | return res; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /src/0234.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | bool isPalindrome(ListNode* head) { 12 | if (!head || !head->next) { 13 | return true; 14 | } 15 | ListNode* slow = head; 16 | ListNode* fast = head; 17 | while (fast && fast->next) { 18 | slow = slow->next; 19 | fast = fast->next->next; 20 | } 21 | ListNode* pre = nullptr; 22 | while (slow) { 23 | ListNode* t = slow->next; 24 | slow->next = pre; 25 | pre = slow; 26 | slow = t; 27 | } 28 | ListNode* cur = head; 29 | while (pre) { 30 | if (cur->val != pre->val) { 31 | return false; 32 | } 33 | cur = cur->next; 34 | pre = pre->next; 35 | } 36 | return true; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /src/0166.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string fractionToDecimal(int numerator, int denominator) { 4 | if (numerator == 0) { 5 | return "0"; 6 | } 7 | string res; 8 | if ((numerator ^ denominator) < 0) { 9 | res += '-'; 10 | } 11 | long a = labs(numerator); 12 | long b = labs(denominator); 13 | 14 | if (a < b) { 15 | res += "0."; 16 | } else { 17 | res += to_string(a / b); 18 | if (a % b == 0) return res; 19 | res += '.'; 20 | a = a % b; 21 | } 22 | unordered_map m; 23 | int cnt = 0; 24 | while (a % b) { 25 | a *= 10; 26 | res += to_string(a / b); 27 | a %= b; 28 | if (m.count(a)) { 29 | int dot_pos = res.find('.') + 1 + m[a]; 30 | res.insert(dot_pos, "("); 31 | res += ')'; 32 | break; 33 | } 34 | m[a] = ++cnt; 35 | } 36 | return res; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /src/0085.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maximalRectangle(vector>& matrix) { 4 | if (matrix.empty()) return 0; 5 | int res = 0; 6 | vector dp(matrix[0].size() + 1); 7 | for (auto& x : matrix) { 8 | for (int i = 0; i < x.size(); ++i) { 9 | if (x[i] == '1') { 10 | ++dp[i]; 11 | } else { 12 | dp[i] = 0; 13 | } 14 | } 15 | res = max(res, largestRectangleArea(dp)); 16 | } 17 | return res; 18 | } 19 | 20 | int largestRectangleArea(const vector& heights) { 21 | stack s; 22 | int res = 0; 23 | for (int i = 0; i < heights.size(); ++i) { 24 | while (!s.empty() && heights[i] < heights[s.top()]) { 25 | int t = s.top(); 26 | s.pop(); 27 | res = max(res, heights[t] * (s.empty() ? i : (i - s.top() - 1))); 28 | } 29 | s.emplace(i); 30 | } 31 | return res; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/1115.cpp: -------------------------------------------------------------------------------- 1 | class FooBar { 2 | public: 3 | FooBar(int n) { this->n = n; } 4 | 5 | void foo(function printFoo) { 6 | for (int i = 0; i < n; i++) { 7 | unique_lock l{m}; 8 | cv1.wait(l, [this] { return b1; }); 9 | // printFoo() outputs "foo". Do not change or remove this line. 10 | printFoo(); 11 | b1 = false; 12 | b2 = true; 13 | cv2.notify_one(); 14 | } 15 | } 16 | 17 | void bar(function printBar) { 18 | for (int i = 0; i < n; i++) { 19 | unique_lock l{m}; 20 | cv2.wait(l, [this] { return b2; }); 21 | // printBar() outputs "bar". Do not change or remove this line. 22 | printBar(); 23 | b1 = true; 24 | b2 = false; 25 | cv1.notify_one(); 26 | } 27 | } 28 | 29 | private: 30 | int n; 31 | mutex m; 32 | condition_variable cv1; 33 | condition_variable cv2; 34 | bool b1 = true; 35 | bool b2 = false; 36 | }; 37 | -------------------------------------------------------------------------------- /src/0004.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | double findMedianSortedArrays(vector& nums1, vector& nums2) { 4 | int n = nums1.size() + nums2.size(); 5 | int x = (n + 1) / 2; 6 | int y = (n + 2) / 2; 7 | return (findK(nums1, nums2, 0, 0, x) + findK(nums1, nums2, 0, 0, y)) / 2.0; 8 | } 9 | 10 | double findK(vector& nums1, vector& nums2, int a, int b, int k) { 11 | if (a >= nums1.size()) { 12 | return nums2[b + k - 1]; 13 | } 14 | if (b >= nums2.size()) { 15 | return nums1[a + k - 1]; 16 | } 17 | if (k == 1) { 18 | return min(nums1[a], nums2[b]); 19 | } 20 | int x = a + k / 2 - 1; 21 | int y = b + k / 2 - 1; 22 | int m1 = x < nums1.size() ? nums1[x] : INT_MAX; 23 | int m2 = y < nums2.size() ? nums2[y] : INT_MAX; 24 | return m1 < m2 ? findK(nums1, nums2, x + 1, b, k - k / 2) 25 | : findK(nums1, nums2, a, y + 1, k - k / 2); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/0025.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode() : val(0), next(nullptr) {} 7 | * ListNode(int x) : val(x), next(nullptr) {} 8 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 | * }; 10 | */ 11 | class Solution { 12 | public: 13 | ListNode* reverseKGroup(ListNode* head, int k) { 14 | ListNode* next_group_node = head; 15 | int n = k; 16 | while (n--) { 17 | if (!next_group_node) { 18 | return head; 19 | } 20 | next_group_node = next_group_node->next; 21 | } 22 | n = k; 23 | ListNode* pre = nullptr; 24 | ListNode* cur = head; 25 | while (--n) { 26 | ListNode* t = cur->next; 27 | cur->next = pre; 28 | pre = cur; 29 | cur = t; 30 | } 31 | cur->next = pre; 32 | head->next = reverseKGroup(next_group_node, k); 33 | return cur; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /src/0221.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maximalSquare(vector>& matrix) { 4 | if (matrix.empty() || matrix[0].empty()) { 5 | return 0; 6 | } 7 | int res = 0; 8 | int m = matrix.size(); 9 | int n = matrix[0].size(); 10 | vector> dp(m, vector(n)); 11 | for (int i = 0; i < m; ++i) { 12 | if (matrix[i][0] == '1') { 13 | dp[i][0] = 1; 14 | res = max(res, dp[i][0]); 15 | } 16 | } 17 | for (int i = 0; i < n; ++i) { 18 | if (matrix[0][i] == '1') { 19 | dp[0][i] = 1; 20 | res = max(res, dp[0][i]); 21 | } 22 | } 23 | for (int i = 1; i < m; ++i) { 24 | for (int j = 1; j < n; ++j) { 25 | if (matrix[i][j] == '1') { 26 | dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1; 27 | res = max(res, dp[i][j]); 28 | } 29 | } 30 | } 31 | return res * res; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /docs/0589.md: -------------------------------------------------------------------------------- 1 | * 递归解法 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector preorder(Node* root) { 7 | vector res; 8 | dfs(root, res); 9 | return res; 10 | } 11 | 12 | void dfs(Node* root, vector& res) { 13 | if (!root) { 14 | return; 15 | } 16 | res.emplace_back(root->val); 17 | for (auto& x : root->children) { 18 | dfs(x, res); 19 | } 20 | } 21 | }; 22 | ``` 23 | 24 | * 非递归解法 25 | 26 | ```cpp 27 | class Solution { 28 | public: 29 | vector preorder(Node* root) { 30 | vector res; 31 | if (!root) { 32 | return res; 33 | } 34 | stack s; 35 | s.emplace(root); 36 | while (!s.empty()) { 37 | Node* t = s.top(); 38 | res.emplace_back(t->val); 39 | s.pop(); 40 | for (auto it = t->children.rbegin(); it != t->children.rend(); ++it) { 41 | s.emplace(*it); 42 | } 43 | } 44 | return res; 45 | } 46 | }; 47 | ``` 48 | -------------------------------------------------------------------------------- /src/0005.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string longestPalindrome(string s) { 4 | if (s.size() <= 1) { 5 | return s; 6 | } 7 | string str{"#"}; 8 | for (auto& x : s) { 9 | str += x; 10 | str += '#'; 11 | } 12 | int sz = str.size(); 13 | vector p(sz); 14 | int start = 0; 15 | int maxLen = 0; 16 | 17 | int id = 0; 18 | int mx = 0; 19 | 20 | for (int i = 0; i < sz; ++i) { 21 | if (i < mx) { 22 | p[i] = min(p[2 * id - i], mx - i); 23 | } else if (i == mx) { 24 | p[i] = 1; 25 | } 26 | while (i >= p[i] && str[i - p[i]] == str[i + p[i]]) { 27 | ++p[i]; 28 | } 29 | if (mx < i + p[i]) { 30 | id = i; 31 | mx = i + p[i]; 32 | } 33 | if (p[i] - 1 > maxLen) { 34 | start = i; 35 | maxLen = p[i] - 1; 36 | } 37 | } 38 | return s.substr((start - p[start] + 1) / 2, maxLen); 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /src/1114.cpp: -------------------------------------------------------------------------------- 1 | class Foo { 2 | public: 3 | Foo() {} 4 | 5 | void first(function printFirst) { 6 | unique_lock l{m}; 7 | // printFirst() outputs "first". Do not change or remove this line. 8 | printFirst(); 9 | b1 = true; 10 | cv1.notify_one(); 11 | } 12 | 13 | void second(function printSecond) { 14 | unique_lock l{m}; 15 | cv1.wait(l, [this] { return b1; }); 16 | // printSecond() outputs "second". Do not change or remove this line. 17 | printSecond(); 18 | b2 = true; 19 | cv2.notify_one(); 20 | } 21 | 22 | void third(function printThird) { 23 | unique_lock l{m}; 24 | cv2.wait(l, [this] { return b2; }); 25 | // printThird() outputs "third". Do not change or remove this line. 26 | printThird(); 27 | } 28 | 29 | private: 30 | mutex m; 31 | condition_variable cv1; 32 | condition_variable cv2; 33 | bool b1 = false; 34 | bool b2 = false; 35 | }; 36 | -------------------------------------------------------------------------------- /src/0513.cpp: -------------------------------------------------------------------------------- 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), 10 | * right(right) {} 11 | * }; 12 | */ 13 | class Solution { 14 | public: 15 | int findBottomLeftValue(TreeNode* root) { 16 | queue q; 17 | q.emplace(root); 18 | int res; 19 | while (!q.empty()) { 20 | int n = q.size(); 21 | res = q.front()->val; 22 | for (int i = 0; i < n; ++i) { 23 | TreeNode* t = q.front(); 24 | q.pop(); 25 | if (t->left) { 26 | q.emplace(t->left); 27 | } 28 | if (t->right) { 29 | q.emplace(t->right); 30 | } 31 | } 32 | } 33 | return res; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /docs/0050.md: -------------------------------------------------------------------------------- 1 | * 快速幂 2 | 3 | ``` 4 | 3 ^ 10 = 3 ^ 5 * 3 ^ 5 5 | 3 ^ 5 = 3 ^ 2 * 3 ^ 2 * 3 6 | 3 ^ 2 = 3 ^ 1 * 3 ^ 1 7 | 3 ^ 1 = 3 ^ 0 * 3 ^ 0 * 3 8 | ``` 9 | 10 | * 实现如下 11 | 12 | ```cpp 13 | double myPow(double x, int n) { 14 | if (!n) { 15 | return 1.0; 16 | } 17 | double t = myPow(x, n / 2); 18 | return n % 2 & 1 ? t * t * x : t * t; 19 | } 20 | ``` 21 | 22 | * 此外要考虑指数为负数的情况,对此把底数转为倒数,再把指数转为正数即可。这里要考虑一个边界情况,即 `INT_MIN`(32 位为 `-2 ^ 32`)的相反数比 `INT_MAX`(32 位为 `2 ^ 32 - 1`)大,直接取反将溢出。对于负数,先加 1,再取反即可防溢出,最后需要多乘一次底数 23 | 24 | ```cpp 25 | class Solution { 26 | public: 27 | double myPow(double x, int n) { 28 | double t = 1; 29 | if (n < 0) { 30 | x = 1 / x; 31 | t = x; 32 | n = -(n + 1); 33 | } 34 | return t * helper(x, n); 35 | } 36 | 37 | double helper(double x, int n) { 38 | if (!n) { 39 | return 1.0; 40 | } 41 | double t = helper(x, n / 2); 42 | return n % 2 & 1 ? t * t * x : t * t; 43 | } 44 | }; 45 | ``` 46 | -------------------------------------------------------------------------------- /src/0429.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | // Definition for a Node. 3 | class Node { 4 | public: 5 | int val; 6 | vector children; 7 | 8 | Node() {} 9 | 10 | Node(int _val) { 11 | val = _val; 12 | } 13 | 14 | Node(int _val, vector _children) { 15 | val = _val; 16 | children = _children; 17 | } 18 | }; 19 | */ 20 | class Solution { 21 | public: 22 | vector> levelOrder(Node* root) { 23 | vector> res; 24 | if (!root) { 25 | return res; 26 | } 27 | queue q; 28 | q.emplace(root); 29 | while (!q.empty()) { 30 | vector line; 31 | int n = q.size(); 32 | for (int i = 0; i < n; ++i) { 33 | Node* t = q.front(); 34 | q.pop(); 35 | line.emplace_back(t->val); 36 | for (auto& x : t->children) { 37 | q.emplace(x); 38 | } 39 | } 40 | res.emplace_back(line); 41 | } 42 | return res; 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /docs/0213.md: -------------------------------------------------------------------------------- 1 | * 分别对不偷第一间和不偷最后一间两种情况进行动态规划,复用 #198 解法即可,两种情况较大收益者即为结果 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int rob(vector& nums) { 7 | if (nums.empty()) { 8 | return 0; 9 | } 10 | int sz = nums.size(); 11 | if (sz == 1) { 12 | return nums[0]; 13 | } 14 | if (sz == 2) { 15 | return max(nums[0], nums[1]); 16 | } 17 | vector dp_no_first(sz); 18 | vector dp_no_last(sz - 1); 19 | dp_no_first[1] = nums[1]; 20 | dp_no_first[2] = max(nums[1], nums[2]); 21 | dp_no_last[0] = nums[0]; 22 | dp_no_last[1] = max(nums[0], nums[1]); 23 | for (int i = 3; i < dp_no_first.size(); ++i) { 24 | dp_no_first[i] = max(dp_no_first[i - 1], dp_no_first[i - 2] + nums[i]); 25 | } 26 | for (int i = 2; i < dp_no_last.size(); ++i) { 27 | dp_no_last[i] = max(dp_no_last[i - 1], dp_no_last[i - 2] + nums[i]); 28 | } 29 | return max(dp_no_first.back(), dp_no_last.back()); 30 | } 31 | }; 32 | ``` 33 | -------------------------------------------------------------------------------- /src/0547.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findCircleNum(vector>& M) { 4 | if (M.empty() || M[0].empty()) { 5 | return 0; 6 | } 7 | vector p{MakeSet(M.size())}; 8 | for (int i = 0; i < M.size(); ++i) { 9 | for (int j = 0; j < M[0].size(); ++j) { 10 | if (M[i][j] == 1) { 11 | Union(p, i, j); 12 | } 13 | } 14 | } 15 | int res = 0; 16 | for (int i = 0; i < p.size(); ++i) { 17 | if (p[i] == i) { 18 | ++res; 19 | } 20 | } 21 | return res; 22 | } 23 | 24 | private: 25 | vector MakeSet(int n) { 26 | vector res(n); 27 | iota(res.begin(), res.end(), 0); 28 | return res; 29 | } 30 | 31 | int FindSet(vector& p, int i) { 32 | while (p[i] != i) { 33 | i = p[i]; 34 | } 35 | return i; 36 | } 37 | 38 | void Union(vector& p, int parent, int child) { 39 | p[FindSet(p, child)] = p[FindSet(p, parent)]; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /docs/0008.md: -------------------------------------------------------------------------------- 1 | ```cpp 2 | class Solution { 3 | public: 4 | int myAtoi(string s) { 5 | if (s.empty()) { 6 | return 0; 7 | } 8 | long res = 0; 9 | int cur = 0; 10 | bool postive = true; 11 | // 去掉开头所有空字符 12 | while (cur < s.size() && s[cur] == ' ') { 13 | ++cur; 14 | } 15 | if (cur >= s.size()) { 16 | return 0; 17 | } 18 | // 检查有无正负号 19 | if (s[cur] == '+') { 20 | ++cur; 21 | } else if (s[cur] == '-') { 22 | postive = false; 23 | ++cur; 24 | } 25 | // 检查每个字符都是数字,并计算结果 26 | while (cur < s.size() && isdigit(s[cur])) { 27 | if (res > INT_MAX) { // 溢出时退出 28 | break; 29 | } 30 | res = res * 10 + (s[cur] - '0'); 31 | ++cur; 32 | } 33 | if (!postive) { 34 | res = -res; 35 | } 36 | if (res >= INT_MAX) { 37 | return INT_MAX; 38 | } 39 | if (res <= INT_MIN) { 40 | return INT_MIN; 41 | } 42 | return res; 43 | } 44 | }; 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/0590.md: -------------------------------------------------------------------------------- 1 | * 递归解法 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector postorder(Node* root) { 7 | vector res; 8 | dfs(root, res); 9 | return res; 10 | } 11 | 12 | void dfs(Node* root, vector& res) { 13 | if (!root) { 14 | return; 15 | } 16 | for (auto& x : root->children) { 17 | dfs(x, res); 18 | } 19 | res.emplace_back(root->val); 20 | } 21 | }; 22 | ``` 23 | 24 | * 非递归解法 25 | 26 | ```cpp 27 | class Solution { 28 | public: 29 | vector postorder(Node* root) { 30 | vector res; 31 | if (!root) { 32 | return res; 33 | } 34 | stack> s; // 记录已添加的子节点数 35 | s.emplace(root, 0); 36 | while (!s.empty()) { 37 | auto& [t, i] = s.top(); 38 | if (i == t->children.size()) { 39 | res.emplace_back(t->val); 40 | s.pop(); 41 | } else { 42 | s.emplace(t->children[i++], 0); 43 | } 44 | } 45 | return res; 46 | } 47 | }; 48 | ``` 49 | -------------------------------------------------------------------------------- /src/0015.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> threeSum(vector& nums) { 4 | vector> res; 5 | int sz = nums.size(); 6 | if (sz < 3) return res; 7 | sort(nums.begin(), nums.end()); 8 | for (int i = 0; i < sz - 2; ++i) { 9 | if (i > 0 && nums[i] == nums[i - 1]) { 10 | continue; 11 | } 12 | int l = i + 1; 13 | int r = sz - 1; 14 | int target = -nums[i]; 15 | while (l < r) { 16 | if (nums[l] + nums[r] == target) { 17 | while (l < r && nums[l] == nums[l + 1]) { 18 | ++l; 19 | } 20 | while (l < r && nums[r] == nums[r - 1]) { 21 | --r; 22 | } 23 | res.emplace_back(vector{nums[i], nums[l], nums[r]}); 24 | ++l; 25 | --r; 26 | } else if (nums[l] + nums[r] > target) { 27 | --r; 28 | } else { 29 | ++l; 30 | } 31 | } 32 | } 33 | return res; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /docs/0278.md: -------------------------------------------------------------------------------- 1 | * 二分查找 2 | 3 | ```cpp 4 | // Forward declaration of isBadVersion API. 5 | bool isBadVersion(int version); 6 | 7 | class Solution { 8 | public: 9 | int firstBadVersion(int n) { 10 | int l = 1; 11 | int r = n + 1; 12 | while (l < r) { 13 | int m = l + (r - l) / 2; 14 | if (isBadVersion(m)) { 15 | r = m; 16 | } else { 17 | l = m + 1; 18 | } 19 | } 20 | return l; 21 | } 22 | }; 23 | ``` 24 | 25 | * 但上述方法取 `n + 1` 为右边界时,若 `n` 为 `INT_MAX` 将导致越界,因此要做一些特殊处理 26 | 27 | ```cpp 28 | // Forward declaration of isBadVersion API. 29 | bool isBadVersion(int version); 30 | 31 | class Solution { 32 | public: 33 | int firstBadVersion(int n) { 34 | int l = 1; 35 | int r = n; 36 | while (l <= r) { // 与第一种做法边界检查等价但不会溢出 37 | int m = l + (r - l) / 2; 38 | if (isBadVersion(m)) { 39 | r = m - 1; // r 是右边界前一个位置,要少 1 40 | } else { 41 | l = m + 1; 42 | } 43 | } 44 | return l; 45 | } 46 | }; 47 | ``` 48 | -------------------------------------------------------------------------------- /src/0054.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector spiralOrder(vector>& matrix) { 4 | vector res; 5 | if (matrix.empty() || matrix[0].empty()) { 6 | return res; 7 | } 8 | int u = 0; 9 | int d = matrix.size() - 1; 10 | int l = 0; 11 | int r = matrix[0].size() - 1; 12 | while (true) { 13 | for (int i = l; i <= r; ++i) { 14 | res.emplace_back(matrix[u][i]); 15 | } 16 | if (++u > d) { 17 | break; 18 | } 19 | for (int i = u; i <= d; ++i) { 20 | res.emplace_back(matrix[i][r]); 21 | } 22 | if (--r < l) { 23 | break; 24 | } 25 | for (int i = r; i >= l; --i) { 26 | res.emplace_back(matrix[d][i]); 27 | } 28 | if (--d < u) { 29 | break; 30 | } 31 | for (int i = d; i >= u; --i) { 32 | res.emplace_back(matrix[i][l]); 33 | } 34 | if (++l > r) { 35 | break; 36 | } 37 | } 38 | return res; 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /docs/0295.md: -------------------------------------------------------------------------------- 1 | * 用大顶堆保存左半边元素,用小顶堆各保存右半边元素,中位数即为二者堆顶值之一或平均数 2 | 3 | ```cpp 4 | class MedianFinder { 5 | public: 6 | /** initialize your data structure here. */ 7 | MedianFinder() {} 8 | 9 | void addNum(int num) { 10 | if (q1.empty()) { 11 | q1.emplace(num); 12 | return; 13 | } 14 | if (num <= q1.top()) { 15 | q1.emplace(num); 16 | if (q1.size() == q2.size() + 2) { 17 | q2.emplace(q1.top()); 18 | q1.pop(); 19 | } 20 | } else { 21 | q2.emplace(num); 22 | if (q1.size() == q2.size() - 2) { 23 | q1.emplace(q2.top()); 24 | q2.pop(); 25 | } 26 | } 27 | } 28 | 29 | double findMedian() { 30 | if (q1.size() > q2.size()) { 31 | return q1.top(); 32 | } 33 | if (q1.size() < q2.size()) { 34 | return q2.top(); 35 | } 36 | return (q1.top() + q2.top()) / 2.0; 37 | } 38 | 39 | private: 40 | priority_queue q1; // 大顶堆 41 | priority_queue, greater> q2; 42 | }; 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/0650.md: -------------------------------------------------------------------------------- 1 | * 对于粘贴操作,之前必须进行一次复制,若要粘贴到文本长度为现在的 `n` 倍,则需要 1 次复制和 `n - 1` 次粘贴,共 `n` 次操作。为了减少操作次数,应该尽可能多的复制,而当前长度必须是复制前长度的整数倍,因此分解质因数,所有质因数的和即为结果 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int minSteps(int n) { 7 | vector t{primers(n)}; 8 | int res = 0; 9 | while (n > 1) { 10 | for (auto& x : t) { 11 | if (n % x == 0) { 12 | n /= x; 13 | res += x; 14 | break; 15 | } 16 | } 17 | } 18 | return res; 19 | } 20 | 21 | vector primers(int n) { 22 | vector res; 23 | if (n < 2) { 24 | return res; 25 | } 26 | vector dp(n + 1, true); 27 | for (int i = 2; i < dp.size(); ++i) { 28 | if (dp[i]) { 29 | res.emplace_back(i); 30 | } 31 | for (int j = 0; j < res.size() && i * res[j] < dp.size(); ++j) { 32 | dp[i * res[j]] = false; 33 | if (i % res[j] == 0) { 34 | break; 35 | } 36 | } 37 | } 38 | return res; 39 | } 40 | }; 41 | ``` 42 | -------------------------------------------------------------------------------- /src/0105.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* buildTree(vector& preorder, vector& inorder) { 13 | return buildTree(preorder, 0, preorder.size(), inorder, 0, inorder.size()); 14 | } 15 | 16 | TreeNode* buildTree(vector& preorder, int l1, int r1, 17 | vector& inorder, int l2, int r2) { 18 | if (l1 >= r1 || l2 >= r2) { 19 | return nullptr; 20 | } 21 | TreeNode* t = new TreeNode(preorder[l1]); 22 | int pos = find(inorder.begin() + l2, inorder.begin() + r2, preorder[l1]) - 23 | inorder.begin(); 24 | t->left = buildTree(preorder, l1 + 1, l1 + 1 + pos - l2, inorder, l2, pos); 25 | t->right = buildTree(preorder, l1 + 1 + pos - l2, r1, inorder, pos + 1, r2); 26 | return t; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /docs/0380.md: -------------------------------------------------------------------------------- 1 | * 用数组保存值,用哈希表保存值的索引 2 | 3 | ```cpp 4 | class RandomizedSet { 5 | public: 6 | /** Initialize your data structure here. */ 7 | RandomizedSet() {} 8 | 9 | /** Inserts a value to the set. Returns true if the set did not already 10 | * contain the specified element. */ 11 | bool insert(int val) { 12 | if (m.count(val)) { 13 | return false; 14 | } 15 | v.emplace_back(val); 16 | m.emplace(val, v.size() - 1); 17 | return true; 18 | } 19 | 20 | /** Removes a value from the set. Returns true if the set contained the 21 | * specified element. */ 22 | bool remove(int val) { 23 | if (!m.count(val)) { 24 | return false; 25 | } 26 | v[m[val]] = v.back(); 27 | m[v.back()] = m[val]; 28 | v.pop_back(); 29 | m.erase(val); 30 | return true; 31 | } 32 | 33 | /** Get a random element from the set. */ 34 | int getRandom() { return v[rand() % v.size()]; } 35 | 36 | private: 37 | unordered_map m; 38 | vector v; 39 | }; 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/0041.md: -------------------------------------------------------------------------------- 1 | * 对于一个数 `n`,放在数组的第 `n` 个位置,这样数和其所在位置对应。当所有数都这样放好后,从头开始遍历数组,找到第一个不对应的数 `nums[i]`,`i + 1` 就是结果,如果每个数都对应,结果就是最后一个数(或数组长度)加 1 2 | 3 | ``` 4 | 1 2 0 => 1 2 0 => 0 所在位置不对应 => 返回 3 5 | 3 4 -1 1 => 1 -1 3 4 => -1 所在位置不对应 => 返回 2 6 | 7 8 9 11 12 => 7 8 9 11 12 => 7 所在位置不对应 => 返回 1 7 | 1 2 3 => 均对应,返回 4 8 | ``` 9 | 10 | * 解法如下 11 | 12 | ```cpp 13 | class Solution { 14 | public: 15 | int firstMissingPositive(vector& nums) { 16 | if (nums.empty()) { 17 | return 1; 18 | } 19 | int sz = nums.size(); 20 | for (int i = 0; i < sz; ++i) { 21 | // 防止调整到越界位置 22 | while (nums[i] != i + 1 && nums[i] - 1 >= 0 && nums[i] - 1 < sz) { 23 | if (nums[i] == nums[nums[i] - 1]) { 24 | break; // 避免一直交换相等元素导致的死循环 25 | } 26 | swap(nums[i], nums[nums[i] - 1]); // 调整元素位置直到不能调整 27 | } 28 | } 29 | for (int i = 0; i < sz; ++i) { 30 | if (nums[i] != i + 1) { 31 | return i + 1; 32 | } 33 | } 34 | return sz + 1; 35 | } 36 | }; 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/0238.md: -------------------------------------------------------------------------------- 1 | * 把当前数左边所有数的乘积和右边所有数的乘积保存到两个数组中,同时遍历两个数组,得到的乘积即为其他元素的乘积 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector productExceptSelf(vector& nums) { 7 | int n = nums.size(); 8 | vector l(n, 1); 9 | vector r(n, 1); 10 | for (int i = 1; i < n; ++i) { 11 | l[i] = l[i - 1] * nums[i - 1]; 12 | } 13 | for (int i = n - 2; i >= 0; --i) { 14 | r[i] = r[i + 1] * nums[i + 1]; 15 | } 16 | for (int i = 0; i < n; ++i) { 17 | l[i] *= r[i]; 18 | } 19 | return l; 20 | } 21 | }; 22 | ``` 23 | 24 | * 可以只使用一个数组 25 | 26 | ```cpp 27 | class Solution { 28 | public: 29 | vector productExceptSelf(vector& nums) { 30 | int sz = nums.size(); 31 | vector res(sz, 1); 32 | for (int i = 1; i < sz; ++i) { 33 | res[i] = res[i - 1] * nums[i - 1]; 34 | } 35 | int t = 1; 36 | for (int i = sz - 2; i >= 0; --i) { 37 | t = t * nums[i + 1]; 38 | res[i] *= t; 39 | } 40 | return res; 41 | } 42 | }; 43 | ``` 44 | -------------------------------------------------------------------------------- /src/0450.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* deleteNode(TreeNode* root, int key) { 13 | if (!root) { 14 | return nullptr; 15 | } 16 | if (key > root->val) { 17 | root->right = deleteNode(root->right, key); 18 | return root; 19 | } 20 | if (key < root->val) { 21 | root->left = deleteNode(root->left, key); 22 | return root; 23 | } 24 | if (!root->left || !root->right) { 25 | TreeNode* t = root->left ? root->left : root->right; 26 | delete root; 27 | root = nullptr; 28 | return t; 29 | } 30 | TreeNode* t = root->right; 31 | while (t->left) { 32 | t = t->left; 33 | } 34 | swap(root->val, t->val); 35 | root->right = deleteNode(root->right, key); 36 | return root; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /docs/0055.md: -------------------------------------------------------------------------------- 1 | * 记录每个位置可以到达的最大右边界,如果当前位置超出最大右边界,则无法跳到当前位置,也就无法到达终点(如果能到达终点,则终点前的每个位置都应该可到达) 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | bool canJump(vector& nums) { 7 | int mx = 0; 8 | for (int i = 0; i < nums.size(); ++i) { 9 | if (i > mx) { 10 | return false; 11 | } 12 | mx = max(mx, i + nums[i]); 13 | } 14 | return true; 15 | } 16 | }; 17 | ``` 18 | 19 | * 动态规划,`dp[i]` 表示到达 `i` 位置时还能跳的最大距离 20 | 21 | ```cpp 22 | class Solution { 23 | public: 24 | bool canJump(vector& nums) { 25 | if (nums.empty()) { 26 | return false; 27 | } 28 | if (nums.size() == 1 && nums[0] >= 0) { 29 | return true; 30 | } 31 | vector dp(nums.size()); 32 | dp[0] = nums[0]; 33 | if (dp[0] == 0) { 34 | return false; 35 | } 36 | for (int i = 1; i < dp.size(); ++i) { 37 | dp[i] = max(dp[i - 1] - 1, nums[i - 1]); 38 | if (dp[i] == 0) { 39 | return false; 40 | } 41 | } 42 | return true; 43 | } 44 | }; 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/0547.md: -------------------------------------------------------------------------------- 1 | * 并査集,参考 #200 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int findCircleNum(vector>& M) { 7 | if (M.empty() || M[0].empty()) { 8 | return 0; 9 | } 10 | vector p{MakeSet(M.size())}; 11 | for (int i = 0; i < M.size(); ++i) { 12 | for (int j = 0; j < M[0].size(); ++j) { 13 | if (M[i][j] == 1) { 14 | Union(p, i, j); 15 | } 16 | } 17 | } 18 | int res = 0; 19 | for (int i = 0; i < p.size(); ++i) { 20 | if (p[i] == i) { 21 | ++res; 22 | } 23 | } 24 | return res; 25 | } 26 | 27 | private: 28 | vector MakeSet(int n) { 29 | vector res(n); 30 | iota(res.begin(), res.end(), 0); 31 | return res; 32 | } 33 | 34 | int FindSet(vector& p, int i) { 35 | while (p[i] != i) { 36 | i = p[i]; 37 | } 38 | return i; 39 | } 40 | 41 | void Union(vector& p, int parent, int child) { 42 | p[FindSet(p, child)] = p[FindSet(p, parent)]; 43 | } 44 | }; 45 | ``` 46 | -------------------------------------------------------------------------------- /src/0146.cpp: -------------------------------------------------------------------------------- 1 | class LRUCache { 2 | public: 3 | explicit LRUCache(int capacity) : n(capacity) {} 4 | 5 | int get(int key) { 6 | if (n == 0 || !m.count(key)) { 7 | return -1; 8 | } 9 | q.splice(q.begin(), q, m[key]); 10 | return q.front().second; 11 | } 12 | 13 | void put(int key, int value) { 14 | if (n == 0) { 15 | return; 16 | } 17 | if (m.count(key)) { // 已存在该key 18 | q.splice(q.begin(), q, m[key]); 19 | q.front().second = value; 20 | return; 21 | } 22 | if (m.size() == n) { 23 | m.erase(q.back().first); 24 | q.pop_back(); 25 | } 26 | q.emplace_front(key, value); 27 | m.emplace(key, q.begin()); 28 | } 29 | 30 | private: 31 | int n; 32 | list> q; 33 | unordered_map>::iterator> m; 34 | }; 35 | 36 | /** 37 | * Your LRUCache object will be instantiated and called as such: 38 | * LRUCache* obj = new LRUCache(capacity); 39 | * int param_1 = obj->get(key); 40 | * obj->put(key,value); 41 | */ 42 | -------------------------------------------------------------------------------- /src/0149.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxPoints(vector>& points) { 4 | int sz = points.size(); 5 | if (sz < 3) { 6 | return sz; 7 | } 8 | int res = 0; 9 | for (int i = 0; i < sz; ++i) { 10 | int cnt = 0; 11 | int mx = 0; 12 | unordered_map m; 13 | for (int j = i + 1; j < sz; ++j) { 14 | int dx = points[j][0] - points[i][0]; 15 | int dy = points[j][1] - points[i][1]; 16 | if (dx == 0 && dy == 0) { 17 | ++cnt; 18 | } else { 19 | string k = getK(dx, dy); 20 | ++m[k]; 21 | mx = max(mx, m[k]); 22 | } 23 | } 24 | res = max(res, mx + cnt + 1); 25 | } 26 | return res; 27 | } 28 | 29 | private: 30 | string getK(int x, int y) { 31 | int a = x; 32 | int b = y; 33 | while (b) { 34 | int t = a % b; 35 | a = b; 36 | b = t; 37 | } 38 | x /= a; 39 | y /= a; 40 | return to_string(x) + "#" + to_string(y); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /docs/0221.md: -------------------------------------------------------------------------------- 1 | * 动态规划,`dp[i][j]` 表示以 `matrix[i][j]` 为右下角的最大正方形边长 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int maximalSquare(vector>& matrix) { 7 | if (matrix.empty() || matrix[0].empty()) { 8 | return 0; 9 | } 10 | int res = 0; 11 | int m = matrix.size(); 12 | int n = matrix[0].size(); 13 | vector> dp(m, vector(n)); 14 | for (int i = 0; i < m; ++i) { 15 | if (matrix[i][0] == '1') { 16 | dp[i][0] = 1; 17 | res = max(res, dp[i][0]); 18 | } 19 | } 20 | for (int i = 0; i < n; ++i) { 21 | if (matrix[0][i] == '1') { 22 | dp[0][i] = 1; 23 | res = max(res, dp[0][i]); 24 | } 25 | } 26 | for (int i = 1; i < m; ++i) { 27 | for (int j = 1; j < n; ++j) { 28 | if (matrix[i][j] == '1') { 29 | dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1; 30 | res = max(res, dp[i][j]); 31 | } 32 | } 33 | } 34 | return res * res; 35 | } 36 | }; 37 | ``` 38 | -------------------------------------------------------------------------------- /src/0002.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { 12 | if (!l1) { 13 | return l2; 14 | } 15 | if (!l2) { 16 | return l1; 17 | } 18 | ListNode* p = l1; 19 | ListNode* q = l2; 20 | ListNode* dummy = new ListNode(-1); 21 | ListNode* cur = dummy; 22 | int carry = 0; 23 | while (p || q) { 24 | int a = p ? p->val : 0; 25 | int b = q ? q->val : 0; 26 | int sum = a + b + carry; 27 | carry = sum / 10; 28 | sum = sum % 10; 29 | cur->next = new ListNode(sum); 30 | cur = cur->next; 31 | if (p) { 32 | p = p->next; 33 | } 34 | if (q) { 35 | q = q->next; 36 | } 37 | } 38 | if (carry == 1) { 39 | cur->next = new ListNode(1); 40 | } 41 | return dummy->next; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /src/0138.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | // Definition for a Node. 3 | class Node { 4 | public: 5 | int val; 6 | Node* next; 7 | Node* random; 8 | 9 | Node(int _val) { 10 | val = _val; 11 | next = NULL; 12 | random = NULL; 13 | } 14 | }; 15 | */ 16 | class Solution { 17 | public: 18 | Node* copyRandomList(Node* head) { 19 | if (!head) { 20 | return nullptr; 21 | } 22 | Node* cur = head; 23 | while (cur) { 24 | Node* t = new Node(cur->val); 25 | t->next = cur->next; 26 | cur->next = t; 27 | cur = t->next; 28 | } 29 | 30 | cur = head; 31 | while (cur) { 32 | if (cur->random) { 33 | cur->next->random = cur->random->next; 34 | } 35 | cur = cur->next->next; 36 | } 37 | 38 | cur = head; 39 | Node* dummy = new Node(-1); 40 | Node* t = dummy; 41 | while (cur) { 42 | t->next = cur->next; 43 | t = t->next; 44 | cur->next = cur->next->next; 45 | cur = cur->next; 46 | } 47 | return dummy->next; 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /docs/0021.md: -------------------------------------------------------------------------------- 1 | * 如果一个链表为空,直接返回另一个即可。如果两个链表都不为空,比较两个头节点大小,小的作为合并后的头节点。合并剩余元素,将合并结果链接到合并的头节点之后 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 7 | if (!l1) { 8 | return l2; 9 | } 10 | if (!l2) { 11 | return l1; 12 | } 13 | if (l1->val < l2->val) { 14 | l1->next = mergeTwoLists(l1->next, l2); 15 | return l1; 16 | } 17 | l2->next = mergeTwoLists(l2->next, l1); 18 | return l2; 19 | } 20 | }; 21 | ``` 22 | 23 | * 以 124 和 134 两个链表为例 24 | 25 | ``` 26 | l1 = 1->2->4 27 | l2 = 1->3->4 28 | 29 | res = 1 30 | l1 = 1->2->4 31 | l2 = 3->4 32 | 33 | res = 1->1 34 | l1 = 2->4 35 | l2 = 3->4 36 | 37 | res = 1->1->2 38 | l1 = 4 39 | l2 = 3->4 40 | 41 | res = 1->1->2->3 42 | l1 = 4 43 | l2 = 4 44 | 45 | res = 1->1->2->3->4 46 | l1 = 4 47 | l2 = null 48 | 49 | res = 1->1->2->3->4->4 50 | l1 = null 51 | l2 = null 52 | 53 | 实际执行过程为: 54 | res = 4 55 | res = 4->4 56 | res = 3->4->4 57 | res = 2->3->4->4 58 | res = 1->2->3->4->4 59 | res = 1->1->2->3->4->4 60 | ``` 61 | -------------------------------------------------------------------------------- /src/0654.cpp: -------------------------------------------------------------------------------- 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), 10 | * right(right) {} 11 | * }; 12 | */ 13 | class Solution { 14 | public: 15 | TreeNode* constructMaximumBinaryTree(vector& nums) { 16 | return constructMaximumBinaryTree(nums, 0, nums.size()); 17 | } 18 | 19 | TreeNode* constructMaximumBinaryTree(vector& nums, int l, int r) { 20 | if (l == r) { 21 | return nullptr; 22 | } 23 | int max_index = 24 | max_element(nums.begin() + l, nums.begin() + r) - nums.begin(); 25 | TreeNode* root = new TreeNode(nums[max_index]); 26 | root->left = constructMaximumBinaryTree(nums, l, max_index); 27 | root->right = constructMaximumBinaryTree(nums, max_index + 1, r); 28 | return root; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /docs/0033.md: -------------------------------------------------------------------------------- 1 | * 要求 `O(log n)` 时间复杂度,数组有序,因此应当使用二分搜索 2 | * 对于旋转过的数组,中间值的左右侧,必然有一侧是升序排列的 3 | 4 | ``` 5 | $$$@@@ // $$$ 和 @@@ 为旋转后有序的两部分 6 | 7 | $$$ 中的任何元素,其左侧都位于 $$$ 中,必然有序 8 | @@@ 中的任何元素,其右侧都位于 @@@ 中,必然有序 9 | ``` 10 | 11 | * 检查目标值是否位于升序排列的一侧,以此来缩小范围 12 | 13 | ```cpp 14 | class Solution { 15 | public: 16 | int search(vector& nums, int target) { 17 | if (nums.empty()) { 18 | return -1; 19 | } 20 | int l = 0; 21 | int r = nums.size(); 22 | while (l != r) { 23 | int m = l + (r - l) / 2; 24 | if (target == nums[m]) { 25 | return m; 26 | } 27 | if (nums[m] >= nums[l]) { // 左侧升序 28 | if (target < nums[m] && target >= nums[l]) { // 位于左侧 29 | r = m; 30 | } else { 31 | l = m + 1; 32 | } 33 | } else { // 左侧不为升序则右侧一定为升序 34 | if (target > nums[m] && target <= nums[r - 1]) { // 位于右侧 35 | l = m + 1; 36 | } else { 37 | r = m; 38 | } 39 | } 40 | } 41 | return -1; 42 | } 43 | }; 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/0017.md: -------------------------------------------------------------------------------- 1 | * 回溯法,通常写法如下 2 | 3 | ```cpp 4 | void dfs(..., int n) { // 定义一个不断增长的参数 5 | if (n 满足某个条件,到达终点) { 6 | 进行一些操作; 7 | return; 8 | } 9 | // 否则执行一些操作再进入下一步,结束后撤销操作 10 | 操作 1; 11 | dfs(..., n + 1); // 进入下一步 12 | 撤销操作 1; 13 | } 14 | ``` 15 | 16 | * 解法如下 17 | 18 | ```cpp 19 | class Solution { 20 | public: 21 | vector letterCombinations(string digits) { 22 | vector res; 23 | if (digits.empty()) { 24 | return res; 25 | } 26 | dfs(digits, res, 0, ""); 27 | return res; 28 | } 29 | 30 | void dfs(string digits, vector& res, int n, string s) { 31 | if (n == digits.size()) { // 遍历结束 32 | res.emplace_back(s); // 记录结果 33 | return; 34 | } 35 | for (auto& x : key[digits[n] - '2']) { 36 | s += x; // 操作 1 37 | dfs(digits, res, n + 1, s); 38 | s.pop_back(); // 撤销操作 1,回溯到操作 1 之前的状态 39 | } 40 | } 41 | 42 | private: 43 | const vector key{"abc", "def", "ghi", "jkl", 44 | "mno", "pqrs", "tuv", "wxyz"}; 45 | }; 46 | ``` 47 | -------------------------------------------------------------------------------- /src/0106.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* buildTree(vector& inorder, vector& postorder) { 13 | return buildTree(postorder, 0, postorder.size(), inorder, 0, 14 | inorder.size()); 15 | } 16 | 17 | TreeNode* buildTree(vector& postorder, int l1, int r1, 18 | vector& inorder, int l2, int r2) { 19 | if (l1 >= r1 || l2 >= r2) { 20 | return nullptr; 21 | } 22 | TreeNode* t = new TreeNode(postorder[r1 - 1]); 23 | int pos = 24 | find(inorder.begin() + l2, inorder.begin() + r2, postorder[r1 - 1]) - 25 | inorder.begin(); 26 | t->left = buildTree(postorder, l1, l1 + pos - l2, inorder, l2, pos); 27 | t->right = 28 | buildTree(postorder, l1 + pos - l2, r1 - 1, inorder, pos + 1, r2); 29 | return t; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /docs/0026.md: -------------------------------------------------------------------------------- 1 | * 这就是 [std::unique](https://en.cppreference.com/w/cpp/algorithm/unique) 的功能 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int removeDuplicates(vector& nums) { 7 | return unique(nums.begin(), nums.end()) - nums.begin(); 8 | } 9 | }; 10 | ``` 11 | 12 | * 原理如下 13 | 14 | ``` 15 | [0,0,1,1,1,2,2,3,3,4] 16 | [0,1,1,1,1,2,2,3,3,4] // 找到 0 之后第一个不与 0 重复的元素 1,复制 0 之后 17 | [0,1,2,1,1,2,2,3,3,4] // 找到 1 之后第一个不与 1 重复的元素 2,复制 1 之后 18 | [0,1,2,3,1,2,2,3,3,4] // 找到 2 之后第一个不与 2 重复的元素 3,复制 2 之后 19 | [0,1,2,3,4,2,2,3,3,4] // 找到 3 之后第一个不与 3 重复的元素 4,复制 3 之后 20 | // 返回最后一个不重复元素(即 4)的后一位置(4 之后第一个 2)的迭代器 21 | ``` 22 | 23 | * 不使用 STL 的解法如下 24 | 25 | ```cpp 26 | class Solution { 27 | public: 28 | int removeDuplicates(vector& nums) { 29 | if (nums.empty()) { 30 | return 0; 31 | } 32 | int l = 0; 33 | for (int r = 1; r < nums.size(); ++r) { 34 | if (nums[l] != nums[r]) { 35 | ++l; 36 | if (l < r) { 37 | nums[l] = nums[r]; 38 | } 39 | } 40 | } 41 | return l + 1; 42 | } 43 | }; 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/0128.md: -------------------------------------------------------------------------------- 1 | * 排序去重后动态规划,时间复杂度 `O(n log n)` 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | int longestConsecutive(vector& nums) { 7 | if (nums.empty()) { 8 | return 0; 9 | } 10 | sort(nums.begin(), nums.end()); 11 | nums.erase(unique(nums.begin(), nums.end()), nums.end()); 12 | int res = 1; 13 | vector dp(nums.size(), 1); 14 | for (int i = 1; i < nums.size(); ++i) { 15 | if (nums[i] == nums[i - 1] + 1) { 16 | dp[i] = dp[i - 1] + 1; 17 | } 18 | res = max(res, dp[i]); 19 | } 20 | return res; 21 | } 22 | }; 23 | ``` 24 | 25 | * 使用哈希表,时间复杂度`O(n)` 26 | 27 | ```cpp 28 | class Solution { 29 | public: 30 | int longestConsecutive(vector& nums) { 31 | unordered_set s(nums.begin(), nums.end()); 32 | int res = 0; 33 | for (auto& x : nums) { 34 | if (!s.count(x - 1)) { 35 | int cnt = 1; 36 | while (s.count(x + cnt)) { 37 | ++cnt; 38 | } 39 | res = max(res, cnt); 40 | } 41 | } 42 | return res; 43 | } 44 | }; 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/0075.md: -------------------------------------------------------------------------------- 1 | * 设置左右边界,从左向右遍历,遇到 0 放到左边界并将左边界右移,遇到 2 放到右边界并将右边界左移,遇到 1 不用操作,继续访问下一个数。遍历完成后 0 全在左侧,2 全在右侧,中间就是 1 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | void sortColors(vector& nums) { 7 | int cur = 0; 8 | int l = 0; 9 | int r = nums.size(); 10 | while (cur < r) { 11 | if (nums[cur] == 0 && nums[l] == 0) { 12 | ++cur; 13 | ++l; 14 | } else if (nums[cur] == 0) { 15 | swap(nums[cur], nums[l++]); 16 | } else if (nums[cur] == 2) { 17 | swap(nums[cur], nums[--r]); 18 | } else { 19 | ++cur; 20 | } 21 | } 22 | } 23 | }; 24 | ``` 25 | 26 | * 上述逻辑可合并如下 27 | 28 | ```cpp 29 | class Solution { 30 | public: 31 | void sortColors(vector& nums) { 32 | int cur = 0; 33 | int l = 0; 34 | int r = nums.size(); 35 | while (cur < r) { 36 | if (nums[cur] == 0) { 37 | swap(nums[cur++], nums[l++]); 38 | } else if (nums[cur] == 2) { 39 | swap(nums[cur], nums[--r]); 40 | } else { 41 | ++cur; 42 | } 43 | } 44 | } 45 | }; 46 | ``` 47 | -------------------------------------------------------------------------------- /src/0173.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class BSTIterator { 11 | public: 12 | BSTIterator(TreeNode* root) { 13 | TreeNode* t = root; 14 | while (t) { 15 | s.emplace(t); 16 | t = t->left; 17 | } 18 | } 19 | 20 | /** @return the next smallest number */ 21 | int next() { 22 | TreeNode* t = s.top(); 23 | int res = t->val; 24 | s.pop(); 25 | t = t->right; 26 | while (t) { 27 | s.emplace(t); 28 | t = t->left; 29 | } 30 | return res; 31 | } 32 | 33 | /** @return whether we have a next smallest number */ 34 | bool hasNext() { return !s.empty(); } 35 | 36 | private: 37 | stack s; 38 | }; 39 | 40 | /** 41 | * Your BSTIterator object will be instantiated and called as such: 42 | * BSTIterator* obj = new BSTIterator(root); 43 | * int param_1 = obj->next(); 44 | * bool param_2 = obj->hasNext(); 45 | */ 46 | -------------------------------------------------------------------------------- /docs/0056.md: -------------------------------------------------------------------------------- 1 | * 先按照区间左边界值升序排序 2 | * 对于两个区间,如果第一个区间的右边界与第二个区间的左边界不重合,则第一个区间是一个不重叠的区间,添加到结果中 3 | 4 | ``` 5 | [1, 3] [4, 5] => [1, 3] 是不重叠的区间,添加到结果中 6 | ``` 7 | 8 | * 如果两者重叠,合并两个区间的方法是,左边界取较小值,右边界取较大值,合并结果存储到右区间,继续与下一个区间比较 9 | 10 | ``` 11 | [1, 3] [2, 6] => [1, 6] 12 | [1, 7] [2, 6] => [1, 7] 13 | ``` 14 | 15 | * 从左到右依次两两处理。最后一个区间不会执行上述操作,直接添加到结果中即可 16 | 17 | ```cpp 18 | class Solution { 19 | public: 20 | vector> merge(vector>& intervals) { 21 | vector> res; 22 | if (intervals.empty()) { 23 | return res; 24 | } 25 | sort(intervals.begin(), intervals.end(), 26 | [](auto& x, auto& y) { return x[0] < y[0]; }); 27 | for (int i = 0; i < intervals.size() - 1; ++i) { 28 | if (intervals[i][1] < intervals[i + 1][0]) { 29 | res.emplace_back(intervals[i]); 30 | } else { 31 | intervals[i + 1][0] = intervals[i][0]; 32 | intervals[i + 1][1] = max(intervals[i][1], intervals[i + 1][1]); 33 | } 34 | } 35 | res.emplace_back(intervals.back()); 36 | return res; 37 | } 38 | }; 39 | ``` 40 | -------------------------------------------------------------------------------- /src/0148.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* sortList(ListNode* head) { 12 | if (!head || !head->next) { 13 | return head; 14 | } 15 | ListNode* slow = head; 16 | ListNode* fast = head; 17 | ListNode* pre = slow; 18 | while (fast && fast->next) { 19 | pre = slow; 20 | slow = slow->next; 21 | fast = fast->next->next; 22 | } 23 | pre->next = nullptr; 24 | ListNode* l1 = sortList(head); 25 | ListNode* l2 = sortList(slow); 26 | return mergeTwoLists(l1, l2); 27 | } 28 | 29 | ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 30 | if (!l1) { 31 | return l2; 32 | } 33 | if (!l2) { 34 | return l1; 35 | } 36 | if (l1->val < l2->val) { 37 | l1->next = mergeTwoLists(l1->next, l2); 38 | return l1; 39 | } 40 | l2->next = mergeTwoLists(l2->next, l1); 41 | return l2; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /docs/0066.md: -------------------------------------------------------------------------------- 1 | * 对各种情况依次处理 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | vector plusOne(vector& digits) { 7 | int n = digits.size() - 1; 8 | if (digits[n] != 9) { // 末位不为 9,直接加 1 返回即可 9 | ++digits[n]; 10 | return digits; 11 | } 12 | while (digits[n] == 9) { // 末尾有多个 9,均改为 0 13 | digits[n] = 0; 14 | if (--n < 0) { // 如果全是 9,首位改为 1,末位加一个 0 15 | digits[0] = 1; 16 | digits.emplace_back(0); 17 | return digits; 18 | } 19 | } 20 | ++digits[n]; // 多个 9 但不全是 9,最后一个 9 的下一位加 1 21 | return digits; 22 | } 23 | }; 24 | ``` 25 | 26 | * 或者直接视为一个数从低位到高位依次计算 27 | 28 | ```cpp 29 | class Solution { 30 | public: 31 | vector plusOne(vector& digits) { 32 | int carry = 1; 33 | for (auto it = digits.rbegin(); it != digits.rend(); ++it) { 34 | if (!carry) { 35 | break; 36 | } 37 | *it += carry; 38 | carry = *it / 10; 39 | *it %= 10; 40 | } 41 | if (carry) { 42 | digits.emplace(digits.begin(), carry); 43 | } 44 | return digits; 45 | } 46 | }; 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/0166.md: -------------------------------------------------------------------------------- 1 | * 按要求一步步计算即可 2 | 3 | ```cpp 4 | class Solution { 5 | public: 6 | string fractionToDecimal(int numerator, int denominator) { 7 | if (numerator == 0) { 8 | return "0"; 9 | } 10 | string res; 11 | if ((numerator ^ denominator) < 0) { // 异号 12 | res += '-'; 13 | } 14 | long a = labs(numerator); 15 | long b = labs(denominator); 16 | // 计算小数点之前的数 17 | if (a < b) { 18 | res += "0."; 19 | } else { 20 | res += to_string(a / b); 21 | if (a % b == 0) return res; 22 | res += '.'; 23 | a = a % b; 24 | } 25 | // 计算小数点之后的数 26 | unordered_map m; // 每次做除法得到的余数,及其对应的小数位 27 | int cnt = 0; 28 | while (a % b) { 29 | a *= 10; 30 | res += to_string(a / b); 31 | a %= b; 32 | if (m.count(a)) { // 出现相同余数则说明是无限循环小数 33 | // 在小数点位置后添加左括号,并在结果字符串最后添加右括号 34 | int dot_pos = res.find('.') + 1 + m[a]; 35 | res.insert(dot_pos, "("); 36 | res += ')'; 37 | break; 38 | } 39 | m[a] = ++cnt; 40 | } 41 | return res; 42 | } 43 | }; 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/0324.md: -------------------------------------------------------------------------------- 1 | * 将中位数放到中间,左侧放更小的元素,右侧放更大的元素,接着把右侧元素依次插入到左侧即可 2 | * 题目要求 `O(1)` 空间,不能使用额外数组。用宏给数组定义一个映射,映射数组的左侧对应奇数位置的数,这样只要映射数组的左侧都是比右侧大的数,则原数组就会变成摆动排序 3 | 4 | ``` 5 | a(0) = nums[1] 6 | a(1) = nums[3] 7 | a(2) = nums[5] 8 | a(3) = nums[0] 9 | a(4) = nums[2] 10 | a(5) = nums[4] 11 | 12 | nums = 111465 13 | a(i) = 145116 14 | i = 012345 15 | 16 | 目标情况: 17 | nums = 161514 18 | a(i) = 654111 19 | i = 012345 20 | ``` 21 | 22 | * 实现如下 23 | 24 | ```cpp 25 | class Solution { 26 | public: 27 | void wiggleSort(vector& nums) { 28 | if (nums.empty()) { 29 | return; 30 | } 31 | int sz = nums.size(); 32 | nth_element(nums.begin(), nums.begin() + sz / 2, nums.end()); 33 | int m = nums[sz / 2]; 34 | #define a(i) nums[(2 * (i) + 1) % (sz | 1)] 35 | int i = 0; 36 | int j = 0; 37 | int k = sz - 1; 38 | while (j <= k) { 39 | if (a(j) > m) { 40 | swap(a(i), a(j)); 41 | ++i; 42 | ++j; 43 | } else if (a(j) < m) { 44 | swap(a(j), a(k)); 45 | --k; 46 | } else { 47 | ++j; 48 | } 49 | } 50 | } 51 | }; 52 | ``` 53 | --------------------------------------------------------------------------------