# 刷题总结——算法思想

## LeetCode——双指针

T167. 两数之和 II - 输入有序数组

class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int left = 0;
int right = numbers.size()-1;
while(left < right){
int num = numbers[left] + numbers[right];
if(num == target)  return {left+1, right+1};
else if(num < target) left++;
else right--;
}
return {};
}
};


T633. 平方数之和

class Solution {
public:
bool judgeSquareSum(int c) {
long l = 0;
long r = sqrt(c);
while(l <= r){
int num = l * l + r * r;
if(num == c)
return true;
else if(num < c)
l++;
else
r--;
}
return false;
}
};


T345. 反转字符串中的元音字母

class Solution {
public:
string reverseVowels(string s) {
int l = 0;
int r = s.size()-1;
while(l < r){
if(isOrigin(s[l]) && isOrigin(s[r])){
char tmp = s[l];
s[l] = s[r];
s[r] = tmp;
l++;
r--;
}
else if(isOrigin(s[l]))
r--;
else
l++;
}
return s;
}

bool isOrigin(char c){
if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U')
return true;
else
return false;
}
};


T680. 验证回文字符串 Ⅱ

class Solution {
public:
bool validPalindrome(string s) {
int i = 0;
int j = s.size()-1;
while(i < j){
if(s[i] != s[j]){
return isValid(s, i+1, j) || isValid(s, i, j-1);
}
else{
++i;
--j;
}
}
return true;

}
bool isValid(string s, int i, int j){
while(i < j){
if(s[i] !=  s[j]) return false;
else{
++i;
--j;
}
}
return true;
}
};


T88. 合并两个有序数组

class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int k = m + n - 1;
int i = m - 1;
int j = n - 1;
while(i>=0 && j>=0){
if(nums1[i] >= nums2[j]){
nums1[k] = nums1[i];
k--;
i--;
}
else{
nums1[k] = nums2[j];
k--;
j--;
}
}
while(j >= 0){
nums1[k] = nums2[j];
k--;
j--;
}
}
};


T141. 环形链表

/**
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
while(fast != NULL && fast->next != NULL){
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
return true;
}
return false;
}
};


T524. 通过删除字母匹配到字典里最长单词

class Solution {
public:
string findLongestWord(string s, vector<string>& d) {
string res="";
for(string str : d){
int i = 0;
for(char c : s){
if(i<str.size() && c==str[i]){
++i;
}
if(i==str.size() && str.size() >= res.size()){
if(str.size() > res.size() || str < res){
res = str;
}
}
}
}
return res;

}
};


## LeetCode——排序

T215. 数组中的第K个最大元素

class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int left = 0;
int right = nums.size() - 1;
//注意while里面的循环条件
while (true) {
int pos = partition(nums, left, right);
if (pos == k - 1) return nums[pos];
else if (pos > k - 1) right = pos - 1;
else left = pos + 1;
}
}

int partition(vector<int>& nums, int left, int right) {
int pivot = nums[left];
int l = left + 1;
int r = right;
while (l <= r) {
//注意大小比较条件
if (nums[l] < pivot && nums[r] > pivot) {
swap(nums[l++], nums[r--]);
}
else if(nums[l] < pivot) r--;
else l++;
}
swap(nums[left], nums[r]);
return r;
}
};


T347. 前 K 个高频元素

class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> m;
vector<vector<int>> bucket(nums.size() + 1);
vector<int> res;
for(auto a : nums) ++m[a];
for(auto it : m)
bucket[it.second].push_back(it.first);
for(int i = nums.size(); i>=0; --i){
for(int j=0; j<bucket[i].size(); ++j){
res.push_back(bucket[i][j]);
if(res.size()==k) return res;
}
}
return res;

}
};


T451. 根据字符出现频率排序

class Solution {
public:
string frequencySort(string s) {
string res="";
priority_queue<pair<int, char>> q;
unordered_map<char, int> m;
for(char c : s) ++m[c];
for(auto a : m)
q.push({a.second, a.first});
while(!q.empty()){
auto t = q.top();
q.pop();
res.append(t.first, t.second);
}
return res;
}
};


T75. 颜色分类

class Solution {
public:
void sortColors(vector<int>& nums) {
vector<int> colours(3);
for(int num : nums)  ++colours[num];
for(int i=0,cur=0; i<3; ++i){
for(int j=0; j<colours[i]; ++j){
nums[cur++] = i;
}
}
}
};

class Solution {
public:
void sortColors(vector<int>& nums) {
int red = 0, blue = nums.size() - 1;
for (int i = 0; i <= blue; ++i) {
if (nums[i] == 0) {
swap(nums[i], nums[red++]);
} else if (nums[i] == 2) {
swap(nums[i--], nums[blue--]);
}
}
}
};


## LeetCode——贪心思想

T455. 分发饼干

class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
int res = 0;
int p = 0;
sort(g.begin(), g.end());
sort(s.begin(), s.end());
for (int i = 0; i < s.size(); ++i) {
if (s[i] >= g[p]) {
++res;
++p;
}
if (p >= g.size()) break;

}
return res;
}
};


T435. 无重叠区间

class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
int res=0;
int n=intervals.size();
int last=0;
sort(intervals.begin(),intervals.end());
for(int i=1; i<n; ++i){
if(intervals[i][0] < intervals[last][1]){
++res;
if(intervals[i][1] < intervals[last][1])  last=i;
}
else{
last = i;
}
}
return res;

}
};


T452. 用最少数量的箭引爆气球

class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
if (points.empty()) return 0;
sort(points.begin(), points.end());
int res = 1;
int left = points[0][1];
for (int i = 1; i < points.size(); ++i) {
if (points[i][0] <= left) {
left = min(left, points[i][1]);
} else {
++res;
left = points[i][1];
}
}
return res;
}
};


T406. 根据身高重建队列

class Solution {
public:
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
sort(people.begin(), people.end(), [](vector<int>& a, vector<int>& b) {
return a[0] > b[0] || (a[0] == b[0] && a[1] < b[1]);
});
vector<vector<int>> res;
for (auto a : people) {
res.insert(res.begin() + a[1], a);
}
return res;

}
};


T121. 买卖股票的最佳时机

class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0, buy = INT_MAX;
for (int price : prices) {
res = max(res, price - buy);
}
return res;

}
};


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

class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0, n = prices.size();
for (int i = 0; i < n - 1; ++i) {
if (prices[i] < prices[i + 1]) {
res += prices[i + 1] - prices[i];
}
}
return res;

}
};


T605. 种花问题

class Solution {
public:
bool canPlaceFlowers(vector<int>& flowerbed, int n) {
for (int i = 0; i < flowerbed.size(); ++i) {
if (n == 0) return true;
if (flowerbed[i] == 0) {
int next = (i == flowerbed.size() - 1 ? 0 : flowerbed[i + 1]);
int pre = (i == 0 ? 0 : flowerbed[i - 1]);
if (next + pre == 0) {
flowerbed[i] = 1;
--n;
}
}
}
return n <= 0;

}
};


T392. 判断子序列

class Solution {
public:
bool isSubsequence(string s, string t) {
int i = 0;
for (int j = 0; j < t.size() && i < s.size(); ++j) {
if (s[i] == t[j]) ++i;
}
return i == s.size();

}
};

class Solution {
public:
bool isSubsequence(string s, string t) {
if(s.empty() && t.empty())  return true;
int i = 0;
for(char c : t){
if(s[i] == c) ++i;
if(i >= s.size()) return true;
}
return false;

}
};


T665. 非递减数列

class Solution {
public:
bool checkPossibility(vector<int>& nums) {
int cnt = 1, n = nums.size();
for (int i = 1; i < n; ++i) {
if (nums[i] < nums[i - 1]) {
if (cnt == 0) return false;
if (i == 1 || nums[i] >= nums[i - 2]) nums[i - 1] = nums[i];
else nums[i] = nums[i - 1];
--cnt;
}
}
return true;

}
};


T53. 最大子序和

class Solution {
public:
int maxSubArray(vector<int>& nums) {
int res = INT_MIN, curSum = 0;
for (int num : nums) {
curSum = max(curSum + num, num);
res = max(res, curSum);
}
return res;
}
};

class Solution {
public:
int maxSubArray(vector<int>& nums) {
if (nums.empty()) return 0;
return helper(nums, 0, (int)nums.size() - 1);
}
int helper(vector<int>& nums, int left, int right) {
if (left >= right) return nums[left];
int mid = left + (right - left) / 2;
int lmax = helper(nums, left, mid - 1);
int rmax = helper(nums, mid + 1, right);
int mmax = nums[mid], t = mmax;
for (int i = mid - 1; i >= left; --i) {
t += nums[i];
mmax = max(mmax, t);
}
t = mmax;
for (int i = mid + 1; i <= right; ++i) {
t += nums[i];
mmax = max(mmax, t);
}
return max(mmax, max(lmax, rmax));
}
};


T763. 划分字母区间

class Solution {
public:
vector<int> partitionLabels(string S) {
vector<int> res;
int n = S.size(), start = 0, last = 0;
unordered_map<char, int> m;
for (int i = 0; i < n; ++i) m[S[i]] = i;
for (int i = 0; i < n; ++i) {
last = max(last, m[S[i]]);
if (i == last) {
res.push_back(i - start + 1);
start = i + 1;
}
}
return res;

}
};


## LeetCode——二分查找

T69. x的平方根

class Solution {
public:
int mySqrt(int x) {
if (x <= 1)  return x;
int left = 0;
int right = x;
while (left < right) {
int mid = left + (right - left) / 2;
if (x / mid >= mid) left = mid + 1;
else right = mid;
}
return right - 1;
}
};


T744. 寻找比目标字母大的最小字母

class Solution {
public:
char nextGreatestLetter(vector<char>& letters, char target) {
if (target >= letters.back()) return letters[0];
int left = 0;
int right = letters.size();
while(left < right){
int mid = left + (right - left) / 2;
if(target >= letters[mid])  left = mid + 1;
else  right = mid;
}
return letters[right];
}
};


T540. 有序数组中的单一元素

class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int lo = 0;
int hi = nums.size() - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
bool halvesAreEven = (hi - mid) % 2 == 0;
if (nums[mid + 1] == nums[mid]) {
if (halvesAreEven) {
lo = mid + 2;
} else {
hi = mid - 1;
}
} else if (nums[mid - 1] == nums[mid]) {
if (halvesAreEven) {
hi = mid - 2;
} else {
lo = mid + 1;
}
} else {
return nums[mid];
}
}
return nums[lo];
}
};


T278. 第一个错误版本

// The API isBadVersion is defined for you.

class Solution {
public:
int left = 1;
int right = n;
while (left < right) {
int mid = left + (right - left) / 2;
else left = mid + 1;
}
return left;

}
};


T153. 寻找旋转排序数组中的最小值

class Solution {
public:
int findMin(vector<int>& nums) {
int l = 0;
int r = nums.size()-1;
while(l < r)
{
int m = l + (r - l) / 2;
if(nums[m] > nums[r])  l = m + 1;
else r = m;
}
return nums[r];

}
};


T34. 在排序数组中查找元素的第一个和最后一个位置

class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int idx = search(nums, 0, nums.size() - 1, target);
if (idx == -1) return {-1, -1};
int left = idx, right = idx;
while (left > 0 && nums[left - 1] == nums[idx]) --left;
while (right < nums.size() - 1 && nums[right + 1] == nums[idx]) ++right;
return {left, right};
}
int search(vector<int>& nums, int left, int right, int target) {
if (left > right) return -1;
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
if (nums[mid] < target) return search(nums, mid + 1, right, target);
else return search(nums, left, mid - 1, target);

}
};


## LeetCode——分治

T241. 为运算表达式设计优先级

class Solution {
public:
vector<int> diffWaysToCompute(string input) {
vector<int> res;
for (int i = 0; i < input.size(); ++i) {
if (input[i] == '+' || input[i] == '-' || input[i] == '*') {
vector<int> left = diffWaysToCompute(input.substr(0, i));
vector<int> right = diffWaysToCompute(input.substr(i + 1));
for (int j = 0; j < left.size(); ++j) {
for (int k = 0; k < right.size(); ++k) {
if (input[i] == '+') res.push_back(left[j] + right[k]);
else if (input[i] == '-') res.push_back(left[j] - right[k]);
else res.push_back(left[j] * right[k]);
}
}
}
}
if (res.empty()) res.push_back(stoi(input));
return res;

}
};


T95. 不同的二叉搜索树 II

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode() : val(0), left(nullptr), right(nullptr) {}
*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<TreeNode*> generateTrees(int n) {
if (n == 0) return {};
return helper(1, n);
}
vector<TreeNode*> helper(int start, int end) {
if (start > end) return {nullptr};
vector<TreeNode*> res;
for (int i = start; i <= end; ++i) {
auto left = helper(start, i - 1);
auto right = helper(i + 1, end);
for (auto a : left) {
for (auto b : right) {
TreeNode *node = new TreeNode(i);
node->left = a;
node->right = b;
res.push_back(node);
}
}
}
return res;

}
};


## LeetCode——数学

T204. 计数质数

class Solution {
public:
int countPrimes(int n) {
int res = 0;
vector<bool> prime(n, true);
for (int i = 2; i < n; ++i) {
if (!prime[i]) continue;
++res;
for (int j = 2; i * j < n; ++j) {
prime[i * j] = false;
}
}
return res;
}
};


T504. 七进制数

class Solution {
public:
string convertToBase7(int num) {
if(num == 0){
return "0";
}
bool flag = true; //是否为正数
if(num < 0){
flag = false;
num = -num;
}
string ans;
while(num != 0){
ans.push_back(char(num % 7 + '0'));
num /= 7;
}
if(!flag){  //为负数
ans.push_back('-');
}
reverse(ans.begin(), ans.end());    //反转字符串才为结果
return ans;
}
};


T405. 数字转换为十六进制数

class Solution {
public:
string toHex(int num) {
string res = "";
for (int i = 0; num && i < 8; ++i) {
int t = num & 0xf;//取出最右边四位
if (t >= 10) res = char('a' + t - 10) + res;
else res = char('0' + t) + res;
num >>= 4;//num向右移四位
}
return res.empty() ? "0" : res;

}
};


T168. Excel表列名称

class Solution {
public:
string convertToTitle(int n) {
string res = "";
while (n) {
if (n % 26 == 0) {
res += 'Z';
n -= 26;
} else {
res += n % 26 - 1 + 'A';
n -= n % 26;
}
n /= 26;
}
reverse(res.begin(), res.end());
return res;

}
};


T172. 阶乘后的零

class Solution {
public:
int trailingZeroes(int n) {
int res = 0;
while (n) {
res += n / 5;
n /= 5;
}
return res;

}
};


T67. 二进制求和

class Solution {
public:
string addBinary(string a, string b) {
string res = "";
int m = a.size() - 1, n = b.size() - 1, carry = 0;
while (m >= 0 || n >= 0) {
int p = m >= 0 ? a[m--] - '0' : 0;
int q = n >= 0 ? b[n--] - '0' : 0;
int sum = p + q + carry;
res = to_string(sum % 2) + res;
carry = sum / 2;
}
return carry == 1 ? "1" + res : res;

}
};


T415. 字符串相加

class Solution {
public:
string addStrings(string num1, string num2) {
string res = "";
int m = num1.size(), n = num2.size(), i = m - 1, j = n - 1, carry = 0;
while (i >= 0 || j >= 0) {
int a = i >= 0 ? num1[i--] - '0' : 0;
int b = j >= 0 ? num2[j--] - '0' : 0;
int sum = a + b + carry;
res.insert(res.begin(), sum % 10 + '0');
carry = sum / 10;
}
return carry ? "1" + res : res;

}
};


T462. 最少移动次数使数组元素相等 II

class Solution {
public:
int minMoves2(vector<int>& nums) {
int res = 0, i = 0, j = (int)nums.size() - 1;
sort(nums.begin(), nums.end());
while (i < j) {
res += nums[j--] - nums[i++];
}
return res;

}
};


T169. 多数元素

class Solution {
public:
int majorityElement(vector<int>& nums) {
int res = 0, cnt = 0;
for (int num : nums) {
if (cnt == 0) {
res = num;
++cnt;
}
else (num == res) ? ++cnt : --cnt;
}
return res;

}
};


T367. 有效的完全平方数

class Solution {
public:
bool isPerfectSquare(int num) {
int i = 1;
while (num > 0) {
num -= i;
i += 2;
}
return num == 0;

}
};


T326. 3的幂

class Solution {
public:
bool isPowerOfThree(int n) {
return (n > 0 && int(log10(n) / log10(3)) - log10(n) / log10(3) == 0);
//在c++中判断数字a是否为整数，我们可以用 a - int(a) == 0 来判断

}
};

class Solution {
public:
bool isPowerOfThree(int n) {
while (n && n % 3 == 0) {
n /= 3;
}
return n == 1;
}
};


T238. 除自身以外数组的乘积

class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n = nums.size();
vector<int> fwd(n, 1), bwd(n, 1), res(n);
for (int i = 0; i < n - 1; ++i) {
fwd[i + 1] = fwd[i] * nums[i];
}
for (int i = n - 1; i > 0; --i) {
bwd[i - 1] = bwd[i] * nums[i];
}
for (int i = 0; i < n; ++i) {
res[i] = fwd[i] * bwd[i];
}
return res;

}
};


T628. 三个数的最大乘积

class Solution {
public:
int maximumProduct(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
int p = nums[0] * nums[1] * nums[n - 1];
return max(p, nums[n - 1] * nums[n - 2] * nums[n - 3]);

}
};


## LeetCode——动态规划

T70. 爬楼梯

class Solution {
public:
int climbStairs(int n) {
if (n <= 1) return 1;
vector<int> dp(n);
dp[0] = 1; dp[1] = 2;
for (int i = 2; i < n; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp.back();
}
};


T198. 打家劫舍

class Solution {
public:
int rob(vector<int>& nums) {
if(nums.empty())  return 0;
if(nums.size() == 1)  return nums[0];
vector<int> dp(nums.size());
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
for (int i = 2; i < nums.size(); ++i) {
dp[i] = max(dp[i-1], dp[i-2]+nums[i]);
}
return dp.back();

}
};


T213. 打家劫舍 II

class Solution {
public:
int rob(vector<int>& nums) {
if(nums.empty()) return 0;
if(nums.size() == 1) return nums[0];
return max(rob(nums, 0, nums.size() - 1), rob(nums, 1, nums.size()));
}
int rob(vector<int> &nums, int left, int right) {
if (right - left <= 1) return nums[left];
vector<int> dp(right);
dp[left] = nums[left];
dp[left + 1] = max(nums[left], nums[left + 1]);
for (int i = left + 2; i < right; ++i) {
dp[i] = max(nums[i] + dp[i - 2], dp[i - 1]);
}
return dp.back();

}
};


T64. 最小路径和

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

}
};


T62. 不同路径

class Solution {
public:
// 状态定义：dp[i][j]是到达i，j的路径数。
// 递推方程：dp[i][j] = dp[i-1][j] + dp[i][j-1]。向右走一步或者向下走一步就可以到达i，j的方案数之和
int uniquePaths(int m, int n) {
vector<vector<int> > dp(m, vector<int>(n));
for(int i = 0; i < m; ++i) {
for(int j = 0; j < n; ++j) {
if(i == 0 || j == 0) dp[i][j] = 1;
else  dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
}
};


class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> dp(n, 1);
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
dp[j] += dp[j - 1];
}
}
return dp[n - 1];
}
};


T303. 区域和检索 - 数组不可变

class NumArray {
public:
NumArray(vector<int> &nums) {
dp = nums;
for (int i = 1; i < nums.size(); ++i) {
dp[i] += dp[i - 1];
}
}
int sumRange(int i, int j) {
return i == 0? dp[j] : dp[j] - dp[i - 1];
}
private:
vector<int> dp;
};


T413. 等差数列划分

class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
int res = 0, len = 2, n = A.size();
for (int i = 2; i < n; ++i) {
if (A[i] - A[i - 1] == A[i - 1] - A[i - 2]) {
++len;
} else {
if (len > 2) res += (len - 1) * (len - 2) * 0.5;
len = 2;
}
}
if (len > 2) res += (len - 1) * (len - 2) * 0.5;
return res;

}
};

class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
int res = 0, n = A.size();
vector<int> dp(n, 0);
for (int i = 2; i < n; ++i) {
if (A[i] - A[i - 1] == A[i - 1] - A[i - 2]) {
dp[i] = dp[i - 1] + 1;
}
res += dp[i];
}
return res;
}
};


T343. 整数拆分

class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n + 1, 1);
for (int i = 3; i <= n; ++i) {
for (int j = 1; j < i; ++j) {
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]));
}
}
return dp[n];

}
};


T91. 解码方法

class Solution {
public:
int numDecodings(string s) {
if (s.empty() || s[0] == '0') return 0;
vector<int> dp(s.size() + 1, 0);
dp[0] = 1;
for (int i = 1; i < dp.size(); ++i) {
dp[i] = (s[i - 1] == '0') ? 0 : dp[i - 1];
if (i > 1 && (s[i - 2] == '1' || (s[i - 2] == '2' && s[i - 1] <= '6'))) {
dp[i] += dp[i - 2];
}
}
return dp.back();

}
};


T300. 最长上升子序列

class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> dp(nums.size(), 1);
int res = 0;
for (int i = 0; i < nums.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (nums[i] > nums[j]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
res = max(res, dp[i]);
}
return res;

}
};


T646. 最长数对链

class Solution {
public:
int findLongestChain(vector<vector<int>>& pairs) {
sort(pairs.begin(), pairs.end());
int last = pairs[0][1];
int res = 1;
for(int i = 1; i < pairs.size(); i++){
if(pairs[i][0] > last){
last = pairs[i][1];
res++;
}
else{
last = min(pairs[i][1], last);
}
}
return res;

}
};


T376. 摆动序列

class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if (nums.empty()) return 0;
vector<int> p(nums.size(), 1);
vector<int> q(nums.size(), 1);
for (int i = 1; i < nums.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (nums[i] > nums[j]) p[i] = max(p[i], q[j] + 1);
else if (nums[i] < nums[j]) q[i] = max(q[i], p[j] + 1);
}
}
return max(p.back(), q.back());

}
};


T1143. 最长公共子序列

class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m = text1.size();
int n = text2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
if(text1[i-1] == text2[j-1]) dp[i][j] = dp[i-1][j-1]+1;
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
return dp[m][n];

}
};


0-1背包
T416. 分割等和子集

class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
for(auto ele:nums)  sum += ele;
if(sum%2)   return false;//数组和为奇数，则无法划分成两个和相等的集合

sum /= 2;//数组和的一半
int size = nums.size();

//dp[i][j] = x 表示
//对于前 i 个数，当前背包的容量为 j 时（i从1-size）
//若 x 为 true，则说明可以挑选一些数恰好将背包装满
//若 x 为 false，则说明不能挑选出一些数恰好将背包装满
vector<vector<bool>> dp(size+1,vector<bool>(sum+1,false));

for(int i=0;i<size+1;i++)
dp[i][0] = true;//背包容量为0，不管从哪些元素中挑，只要不挑选就能满足将背包装满

for(int i=1;i<size+1;i++)
{
for(int j=1;j<=sum;j++)
{
if(j - nums[i-1] < 0)//背包容量放不下第i个数
dp[i][j] = dp[i-1][j];//不将第i个数放入背包
else
dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i-1]];//逻辑与 前面表示第i个数不放入背包，后面表示放入背包
}
}

return dp[size][sum];//表示 对于数组前size个数，当前背包容量为sum时，有没有办法选择一些数让背包装满
}
};



T494. 目标和

class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
return dfs(nums, S, 0);
}

int dfs(vector<int> &nums, uint target, int left) {
if (target == 0 && left == nums.size()) return 1;
if (left >= nums.size()) return 0;
int ans = 0;
ans += dfs(nums, target - nums[left], left + 1);
ans += dfs(nums, target + nums[left], left + 1);
return ans;
}
};



T494. 目标和

class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int sum = 0;
for(int i : nums) sum += i;
if(sum < S || (sum + S) % 2 == 1){
return 0;
}
return subSets(nums, (sum + S) / 2);
}

// 满足要求的子集数
int subSets(vector<int>& nums, int sum){
int n = nums.size();
vector<vector<int>> dp(n + 1, vector<int>(sum + 1, 0));
for(auto& v : dp) v[0] = 1;

for(int i = 1; i < n + 1; ++i)
{
int val = nums[i - 1];
for(int j = 0; j <= sum; ++j)
{
if(j >= val)
{
// 选择当前物品的组合数和不选择当前物品的组合数的和
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - val];
}
else{
// 只能选择不拿当前物品
dp[i][j] = dp[i - 1][j];
}
}
}

return dp[n][sum];
}
};



T474. 一和零

class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
for (string str : strs) {
int zeros = 0, ones = 0;
for (char c : str) (c == '0') ? ++zeros : ++ones;
for (int i = m; i >= zeros; --i) {
for (int j = n; j >= ones; --j) {
dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1);
}
}
}
return dp[m][n];

}
};


T322. 零钱兑换

class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount + 1, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; ++i) {
for (int j = 0; j < coins.size(); ++j) {
if (coins[j] <= i) {
dp[i] = min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return (dp[amount] > amount) ? -1 : dp[amount];

}
};


T518. 零钱兑换 II

class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<vector<int>> dp(coins.size() + 1, vector<int>(amount + 1, 0));
dp[0][0] = 1;
for (int i = 1; i <= coins.size(); ++i) {
dp[i][0] = 1;
for (int j = 1; j <= amount; ++j) {
dp[i][j] = dp[i - 1][j] + (j >= coins[i - 1] ? dp[i][j - coins[i - 1]] : 0);
}
}
return dp[coins.size()][amount];

}
};


T139. 单词拆分

class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
vector<bool> dp(s.size() + 1);
dp[0] = true;
for (int i = 0; i < dp.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (dp[j] && wordSet.count(s.substr(j, i - j))) {
dp[i] = true;
break;
}
}
}
return dp.back();

}
};


T377. 组合总和 Ⅳ

class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<unsigned int> dp(target + 1);
dp[0] = 1;
for (int i = 1; i <= target; ++i) {
for (auto a : nums) {
if (i >= a) dp[i] += dp[i - a];
}
}
return dp.back();
}
};


## LeetCode——搜索

BFS

T1091. 二进制矩阵中的最短路径

struct Node {
int x;
int y;
};
class Solution {
public:
int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
int ans = 0;
queue<Node> myQ; // BFS一般通过队列方式解决
int M = grid.size();
int N = grid[0].size();

// 先判断边界条件，很明显，这两种情况下都是不能到达终点的。
if (grid[0][0] == 1 || grid[M - 1][N - 1] == 1) {
return -1;
}

// 备忘录，记录已经走过的节点
vector<vector<int>> mem(M, vector<int>(N, 0));

myQ.push({0, 0});
mem[0][0] = 1;

// 以下是标准BFS的写法
while (!myQ.empty()) {
int size = myQ.size();

for (int i = 0; i < size; i++) {
Node currentNode = myQ.front();
int x = currentNode.x;
int y = currentNode.y;

// 判断是否满足退出的条件
if (x == (N - 1) && y == (M - 1)) {
return (ans + 1);
}

// 下一个节点所有可能情况
vector<Node> nextNodes = {{x + 1, y}, {x - 1, y}, {x + 1, y - 1}, {x + 1, y + 1},
{x, y + 1}, {x, y - 1}, {x - 1, y - 1}, {x - 1, y + 1}};

for (auto n : nextNodes) {
// 过滤条件1： 边界检查
if (n.x < 0 || n.x >= N || n.y < 0 || n.y >= M) {
continue;
}
// 过滤条件2：备忘录检查
if (mem[n.y][n.x] == 1) {
continue;
}
// 过滤条件3：题目中的要求
if (grid[n.y][n.x] == 1) {
continue;
}

// 通过过滤筛选，加入队列！
mem[n.y][n.x] = 1;
myQ.push(n);
}

myQ.pop();
}
ans++;
}

return -1;
}
};



T279. 完全平方数

class Solution
{
public:
/*返回小于n的平方序列: 1, 4, 9...*/
vector<int> getSquares(int n)
{
vector<int> res;
for(int i = 1; i*i <= n; ++i)
{
res.push_back(i*i);
}
return res;
}
int numSquares(int n)
{
vector<int> squares = getSquares(n);
vector<bool> visited(n+1);    //记录已访问过的节点
queue<int> q;

q.push(n);
int res = 0;
visited[n] = true;
while(!q.empty())
{
int size = q.size();
res++;
while(size--)
{
int curr = q.front();
q.pop();
/*每次跨越的间隔为平方数*/
for(int num: squares)
{
int next = curr - num;
if(next < 0)
{
break;
}
if(next == 0)
{
return res;
}
if(visited[next])
{
continue;
}
visited[next] = true;
q.push(next);
}
}
}
return n;
}
};


T127. 单词接龙

class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> wordSet(wordList.begin(), wordList.end());
if (!wordSet.count(endWord)) return 0;
unordered_map<string, int> pathCnt{{{beginWord, 1}}};
queue<string> q{{beginWord}};
while (!q.empty()) {
string word = q.front(); q.pop();
for (int i = 0; i < word.size(); ++i) {
string newWord = word;
for (char ch = 'a'; ch <= 'z'; ++ch) {
newWord[i] = ch;
if (wordSet.count(newWord) && newWord == endWord) return pathCnt[word] + 1;
if (wordSet.count(newWord) && !pathCnt.count(newWord)) {
q.push(newWord);
pathCnt[newWord] = pathCnt[word] + 1;
}
}
}
}
return 0;

}
};


DFS

T695. 岛屿的最大面积

class Solution {
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
int ans = 0;
for (int i = 0; i != grid.size(); ++i)
for (int j = 0; j != grid[0].size(); ++j) {
int cur = 0;
stack<int> stacki;
stack<int> stackj;
stacki.push(i);
stackj.push(j);
while (!stacki.empty()) {
int cur_i = stacki.top(), cur_j = stackj.top();
stacki.pop();
stackj.pop();
if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i][cur_j] != 1)
continue;
++cur;
grid[cur_i][cur_j] = 0;
int di[4] = {0, 0, 1, -1};
int dj[4] = {1, -1, 0, 0};
for (int index = 0; index != 4; ++index) {
int next_i = cur_i + di[index], next_j = cur_j + dj[index];
stacki.push(next_i);
stackj.push(next_j);
}
}
ans = max(ans, cur);
}
return ans;
}
};


class Solution {
public:
vector<vector<int>> dirs{{0,-1},{-1,0},{0,1},{1,0}};
int maxAreaOfIsland(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size(), res = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] != 1) continue;
int cnt = 0;
queue<pair<int, int>> q{{{i, j}}};
grid[i][j] *= -1;
while (!q.empty()) {
auto t = q.front(); q.pop();
res = max(res, ++cnt);
for (auto dir : dirs) {
int x = t.first + dir[0], y = t.second + dir[1];
if (x < 0 || x >= m || y < 0 || y >= n || grid[x][y] <= 0) continue;
grid[x][y] *= -1;
q.push({x, y});
}
}
}
}
return res;
}
};


T200. 岛屿数量

class Solution {
private:
void dfs(vector<vector<char>>& grid, int r, int c) {
int nr = grid.size();
int nc = grid[0].size();

grid[r][c] = '0';
if (r - 1 >= 0 && grid[r-1][c] == '1') dfs(grid, r - 1, c);
if (r + 1 < nr && grid[r+1][c] == '1') dfs(grid, r + 1, c);
if (c - 1 >= 0 && grid[r][c-1] == '1') dfs(grid, r, c - 1);
if (c + 1 < nc && grid[r][c+1] == '1') dfs(grid, r, c + 1);
}

public:
int numIslands(vector<vector<char>>& grid) {
int nr = grid.size();
if (!nr) return 0;
int nc = grid[0].size();

int num_islands = 0;
for (int r = 0; r < nr; ++r) {
for (int c = 0; c < nc; ++c) {
if (grid[r][c] == '1') {
++num_islands;
dfs(grid, r, c);
}
}
}

return num_islands;
}
};



T547. 朋友圈

class Solution {
public:
int findCircleNum(vector<vector<int>>& M) {
int n = M.size();
int res = 0;
vector<bool> visited(n, false);
for (int i = 0; i < n; ++i) {
if (visited[i]) continue;
helper(M, i, visited);
++res;
}
return res;
}
void helper(vector<vector<int>>& M, int k, vector<bool>& visited) {
visited[k] = true;
for (int i = 0; i < M.size(); ++i) {
if (!M[k][i] || visited[i]) continue;
helper(M, i, visited);
}
}
};


T130. 被围绕的区域

class Solution {
public:
void solve(vector<vector<char>>& board) {
if (board.empty() || board[0].empty()) return;
int m = board.size(), n = board[0].size();
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (i == 0 || i == m - 1 || j == 0 || j == n - 1) {
if (board[i][j] == 'O') dfs(board, i , j);
}
}
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (board[i][j] == 'O') board[i][j] = 'X';
if (board[i][j] == '$') board[i][j] = 'O'; } } } void dfs(vector<vector<char>> &board, int x, int y) { int m = board.size(), n = board[0].size(); vector<vector<int>> dir{{0,-1},{-1,0},{0,1},{1,0}}; board[x][y] = '$';
for (int i = 0; i < dir.size(); ++i) {
int dx = x + dir[i][0], dy = y + dir[i][1];
if (dx >= 0 && dx < m && dy > 0 && dy < n && board[dx][dy] == 'O') {
dfs(board, dx, dy);
}
}

}
};


T417. 太平洋大西洋水流问题

class Solution {
private:
vector<vector<int>> res;
int m, n;
int dis[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };
public:
vector<vector<int>> pacificAtlantic(vector<vector<int>>& matrix) {
if (matrix.empty() || matrix[0].empty()) return {};

m = matrix.size(), n = matrix[0].size();
vector<vector<bool>> pacific(m, vector<bool>(n, false));
vector<vector<bool>> atlantic(m, vector<bool>(n, false));
for (int i = 0; i < m; ++i) {
dfs(matrix, pacific, INT_MIN, i, 0);
dfs(matrix, atlantic, INT_MIN, i, n - 1);
}
for (int i = 0; i < n; ++i) {
dfs(matrix, pacific, INT_MIN, 0, i);
dfs(matrix, atlantic, INT_MIN, m - 1, i);
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (pacific[i][j] && atlantic[i][j]) {
res.push_back({i, j});
}
}
}
return res;
}
void dfs(vector<vector<int>>& matrix, vector<vector<bool>>& visited, int pre, int i, int j) {
if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j] || matrix[i][j] < pre) return;//规定水流只能从高到低或者在同等高度上流动。
visited[i][j] = true;
for (int k = 0; k < 4; k++) {
int newx = i + dis[k][0];
int newy = j + dis[k][1];
dfs(matrix, visited, matrix[i][j], newx, newy);
}
}
};



Backtracking（回溯）属于 DFS。

T17. 电话号码的字母组合

class Solution {
public:
vector<string> letterCombinations(string digits) {
if (digits.empty()) return {};
vector<string> res;
vector<string> dict{"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
letterCombinationsDFS(digits, dict, 0, "", res);
return res;
}
void letterCombinationsDFS(string& digits, vector<string>& dict, int level, string out, vector<string>& res) {
if (level == digits.size()) {
res.push_back(out);
return;
}
string str = dict[digits[level] - '0'];
for (int i = 0; i < str.size(); ++i) {
letterCombinationsDFS(digits, dict, level + 1, out + str[i], res);
}

}
};

class Solution {
public:
vector<string> letterCombinations(string digits) {
if (digits.empty()) return {};
vector<string> res{""};
vector<string> dict{"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
for (int i = 0; i < digits.size(); ++i) {
vector<string> t;
string str = dict[digits[i] - '0'];
for (int j = 0; j < str.size(); ++j) {
for (string s : res) t.push_back(s + str[j]);
}
res = t;
}
return res;
}
};


T93. 复原IP地址

class Solution {
public:
vector<string> res;
restore(s, 4, "", res);
return res;
}
void restore(string s, int k, string out, vector<string> &res) {
if (k == 0) {
if (s.empty()) res.push_back(out);
}
else {
for (int i = 1; i <= 3; ++i) {
if (s.size() >= i && isValid(s.substr(0, i))) {
if (k == 1) restore(s.substr(i), k - 1, out + s.substr(0, i), res);
else restore(s.substr(i), k - 1, out + s.substr(0, i) + ".", res);
}
}
}
}
bool isValid(string s) {
if (s.empty() || s.size() > 3 || (s.size() > 1 && s[0] == '0')) return false;
int res = atoi(s.c_str());
return res <= 255 && res >= 0;

}
};

class Solution {
public:
vector<string> res;
for (int a = 1; a < 4; ++a)
for (int b = 1; b < 4; ++b)
for (int c = 1; c < 4; ++c)
for (int d = 1; d < 4; ++d)
if (a + b + c + d == s.size()) {
int A = stoi(s.substr(0, a));
int B = stoi(s.substr(a, b));
int C = stoi(s.substr(a + b, c));
int D = stoi(s.substr(a + b + c, d));
if (A <= 255 && B <= 255 && C <= 255 && D <= 255) {
string t = to_string(A) + "." + to_string(B) + "." + to_string(C) + "." + to_string(D);
if (t.size() == s.size() + 3) res.push_back(t);
}
}
return res;
}
};

09-05 116

12-24 53
10-21 118
02-23 126
10-07 28