贪心算法精选30道编程题 (附有图解和源码)
贪心算法精选30道编程题
文章目录
- 贪心算法精选30道编程题
- 贪心算法简介
- 1. 柠檬⽔找零(easy)
- 2. 将数组和减半的最少操作次数(medium)
- 3. 最⼤数(medium)
- 4. 摆动序列(medium)
- 5. 最⻓递增⼦序列(medium)
- 6. 递增的三元⼦序列(medium)
- 7. 最⻓连续递增序列(easy)
- 8. 买卖股票的最佳时机(easy)
- 9. 买卖股票的最佳时机 Ⅱ(medium)
- 10. K 次取反后最⼤化的数组和(easy)
- 11. 按⾝⾼排序(easy)
- 12. 优势洗牌(⽥忌赛⻢)(medium)
- 13. 最⻓回⽂串(easy)
- 14. 增减字符串匹配(easy)
- 15. 分发饼⼲(easy)
- 16. 最优除法(medium)
- 17. 跳跃游戏 Ⅱ(medium)
- 18. 跳跃游戏(medium)
- 19. 加油站(medium)
- 20. 单调递增的数字(medium)
- 21. 坏了的计算器(medium)
- 22. 合并区间(medium)
- 23. ⽆重叠区间(medium)
- 24. ⽤最少数量的箭引爆⽓球(medium)
- 25. 整数替换(medium)
- 26. 俄罗斯套娃信封问题(hard)
- 27. 可被三整除的最⼤和(medium)
- 28. 距离相等的条形码(medium)
- 29. 重构字符串(medium)
- 整体源代码总结
贪心算法简介
1. 柠檬⽔找零(easy)
Leedcode链接
代码如下(示例):
class Solution {
public:bool lemonadeChange(vector<int>& bills){int five = 0, ten = 0;for (auto x : bills){if (x == 5) five++;else if (x == 10){if (five > 0) five--, ten++;else return false;}else if (x == 20){if (five && ten) five--, ten--;else if (five >= 3) five -= 3;else return false;}}return true;}
};
2. 将数组和减半的最少操作次数(medium)
Leedcode链接
代码如下(示例):
class Solution {
public:int halveArray(vector<int>& nums){priority_queue<double> heap;double sum = 0.0;for (auto x : nums){heap.push(x);sum += x;}sum /= 2.0;int count = 0;while (sum > 0){double ret = heap.top() / 2.0;sum -= ret;heap.pop();count++;heap.push(ret);}return count;}
};
3. 最⼤数(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:string largestNumber(vector<int>& nums){// 优化:把所有的数转化成字符串vector<string> strs;for (int x : nums) strs.push_back(to_string(x));// 排序sort(strs.begin(), strs.end(), [](const string& s1, const string& s2){return s1 + s2 > s2 + s1;});// 提取结果string ret;for (auto& s : strs) ret += s;if (ret[0] == '0') return "0";return ret;}
};
4. 摆动序列(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:int wiggleMaxLength(vector<int>& nums){int n = nums.size();if (n < 2) return n;int ret = 0, left = 0;for (int i = 0; i < n - 1; i++){int right = nums[i + 1] - nums[i]; // 计算接下来的趋势if (right == 0) continue; // 如果⽔平,直接跳过if (right * left <= 0) ret++; // 累加波峰或者波⾕left = right;}return ret + 1;}
};
5. 最⻓递增⼦序列(medium)
Leedcode链接
代码如下(示例):
class Solution {
public:int lengthOfLIS(vector<int>& nums){int n = nums.size();vector<int> ret;ret.push_back(nums[0]);for (int i = 1; i < n; i++){if (nums[i] > ret.back()) // 如果能接在最后⼀个元素后⾯,直接放{ret.push_back(nums[i]);}else{// ⼆分插⼊位置int left = 0, right = ret.size() - 1;while (left < right){int mid = (left + right) >> 1;if (ret[mid] < nums[i]) left = mid + 1;else right = mid;}ret[left] = nums[i]; // 放在 left 位置上}}return ret.size();}
};
6. 递增的三元⼦序列(medium)
Leedcode链接
代码如下(示例):
class Solution {
public:bool increasingTriplet(vector<int>& nums){int n = nums.size();int a = nums[0], b = INT_MAX;for (int i = 1; i < n; i++){if (nums[i] > b) return true;else if (nums[i] > a) b = nums[i];else a = nums[i];}return false;}
};
7. 最⻓连续递增序列(easy)
Leedcode链接
解题思路:贪心+双指针
代码如下(示例):
class Solution {
public:int findLengthOfLCIS(vector<int>& nums){int ret = 0, n = nums.size();for (int i = 0; i < n; ){int j = i + 1;while (j < n && nums[j] > nums[j - 1]) j++;ret = max(ret, j - i);i = j;}return ret;}
};
8. 买卖股票的最佳时机(easy)
Leedcode链接
代码如下(示例):
class Solution {
public:int maxProfit(vector<int>& prices){int ret = 0;for (int i = 0, priceMin = INT_MAX; i < prices.size(); i++){ret = max(ret, prices[i] - priceMin);priceMin = min(priceMin, prices[i]);}return ret;}
};
9. 买卖股票的最佳时机 Ⅱ(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:int maxProfit(vector<int>& p){// 实现⽅式⼀:双指针int ret = 0, n = p.size();for (int i = 0; i < n; i++){int j = i;while (j + 1 < n && p[j + 1] > p[j]) j++; // 找上升的末端ret += p[j] - p[i];i = j;}return ret;}
};
class Solution
{
public:int maxProfit(vector<int>& prices){// 实现⽅式⼆:拆分成⼀天⼀天int ret = 0;for (int i = 1; i < prices.size(); i++){if (prices[i] > prices[i - 1])ret += prices[i] - prices[i - 1];}return ret;}
};
10. K 次取反后最⼤化的数组和(easy)
Leedcode链接
代码如下(示例):
class Solution
{
public:int largestSumAfterKNegations(vector<int>& nums, int k){int m = 0, minElem = INT_MAX, n = nums.size();for (auto x : nums){if (x < 0) m++;minElem = min(minElem, abs(x)); // 求绝对值最⼩的那个数}// 分类讨论int ret = 0;if (m > k){sort(nums.begin(), nums.end());for (int i = 0; i < k; i++) // 前 k ⼩个负数,变成正数{ret += -nums[i];}for (int i = k; i < n; i++) // 后⾯的数不变{ret += nums[i];}}else{// 把所有的负数变成正数for (auto x : nums) ret += abs(x);if ((k - m) % 2) // 判断是否处理最⼩的正数{ret -= minElem * 2;}}return ret;}
};
11. 按⾝⾼排序(easy)
Leedcode链接
代码如下(示例):
class Solution
{
public:vector<string> sortPeople(vector<string>& names, vector<int>& heights){// 1. 创建⼀个下标数组int n = names.size();vector<int> index(n);for (int i = 0; i < n; i++) index[i] = i;// 2. 对下标进⾏排序sort(index.begin(), index.end(), [&](int i, int j){return heights[i] > heights[j];});// 3. 提取结果vector<string> ret;for (int i : index){ret.push_back(names[i]);}return ret;}
};
12. 优势洗牌(⽥忌赛⻢)(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2){int n = nums1.size();// 1. 排序sort(nums1.begin(), nums1.end());vector<int> index2(n);for (int i = 0; i < n; i++) index2[i] = i;sort(index2.begin(), index2.end(), [&](int i, int j){return nums2[i] < nums2[j];});// 2. ⽥忌赛⻢vector<int> ret(n);int left = 0, right = n - 1;for (auto x : nums1){if (x > nums2[index2[left]]) ret[index2[left++]] = x;else ret[index2[right--]] = x;}return ret;}
};
13. 最⻓回⽂串(easy)
Leedcode链接
代码如下(示例):
class Solution
{
public:int longestPalindrome(string s){// 1. 计数 - ⽤数组模拟哈希表int hash[127] = { 0 };for (char ch : s) hash[ch]++;// 2. 统计结果int ret = 0;for (int x : hash){ret += x / 2 * 2;}return ret < s.size() ? ret + 1 : ret;}
};
14. 增减字符串匹配(easy)
Leedcode链接
代码如下(示例):
class Solution {
public:vector<int> diStringMatch(string s){int left = 0, right = s.size();vector<int> ret;for (auto ch : s){if (ch == 'I') ret.push_back(left++);else ret.push_back(right--);}ret.push_back(left);return ret;}
};
15. 分发饼⼲(easy)
Leedcode链接
代码如下(示例):
class Solution {
public:int findContentChildren(vector<int>& g, vector<int>& s){// 先排序sort(g.begin(), g.end());sort(s.begin(), s.end());// 利⽤双指针找答案int ret = 0, n = s.size();for (int i = 0, j = 0; i < g.size() && j < n; i++, j++){while (j < n && s[j] < g[i]) j++; // 找饼⼲if (j < n) ret++;}return ret;}
};
16. 最优除法(medium)
Leedcode链接
A一定在分子上,B一定在分母上!把后面所有的数都放在分子上即可~
代码如下(示例):
class Solution
{
public:string optimalDivision(vector<int>& nums){int n = nums.size();// 先处理两个边界情况if (n == 1){return to_string(nums[0]);}if (n == 2){return to_string(nums[0]) + "/" + to_string(nums[1]);}string ret = to_string(nums[0]) + "/(" + to_string(nums[1]);for (int i = 2; i < n; i++){ret += "/" + to_string(nums[i]);}ret += ")";return ret;}
};
17. 跳跃游戏 Ⅱ(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:int jump(vector<int>& nums){int left = 0, right = 0, maxPos = 0, ret = 0, n = nums.size();while (left <= right) // 保险的写法,以防跳不到 n - 1 的位置{if (maxPos >= n - 1) // 先判断⼀下是否已经能跳到最后⼀个位置{return ret;}// 遍历当成层,更新下⼀层的最右端点for (int i = left; i <= right; i++){maxPos = max(maxPos, nums[i] + i);}left = right + 1;right = maxPos;ret++;}return -1; // 跳不到的情况}
};
18. 跳跃游戏(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:bool canJump(vector<int>& nums){int left = 0, right = 0, maxPos = 0, n = nums.size();while (left <= right){if (maxPos >= n - 1){return true;}for (int i = left; i <= right; i++){maxPos = max(maxPos, nums[i] + i);}left = right + 1;right = maxPos;}return false;}
};
19. 加油站(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost){int n = gas.size();for (int i = 0; i < n; i++) // 依次枚举所有的起点{int rest = 0; // 标记⼀下净收益int step = 0;for (; step < n; step++) // 枚举向后⾛的步数{int index = (i + step) % n; // 求出⾛ step 步之后的下标rest = rest + gas[index] - cost[index];if (rest < 0) break;}if (rest >= 0) return i;i = i + step; // 优化}return -1;}
};
20. 单调递增的数字(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:int monotoneIncreasingDigits(int n){string s = to_string(n); // 把数字转化成字符串int i = 0, m = s.size();// 找第⼀个递减的位置while (i + 1 < m && s[i] <= s[i + 1]) i++;if (i + 1 == m) return n; // 判断⼀下特殊情况// 回推while (i - 1 >= 0 && s[i] == s[i - 1]) i--;s[i]--;for (int j = i + 1; j < m; j++) s[j] = '9';return stoi(s);}
};
21. 坏了的计算器(medium)
Leedcode链接
代码如下(示例):
class Solution {
public:int brokenCalc(int startValue, int target){int ret = 0;while (startValue < target){if (target % 2 == 0) target /= 2;else target += 1;ret++;}return ret + startValue - target;}
};
22. 合并区间(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:vector<vector<int>> merge(vector<vector<int>>& intervals){// 1. 先按照左端点排序sort(intervals.begin(), intervals.end());// 2. 合并区间int left = intervals[0][0], right = intervals[0][1];vector<vector<int>> ret;for (int i = 1; i < intervals.size(); i++){int a = intervals[i][0], b = intervals[i][1];if (a <= right) // 有重叠部分{// 合并 - 求并集right = max(right, b);}else // 没有重叠部分{ret.push_back({ left, right }); // 加⼊到结果中left = a;right = b;}}// 别忘了最后⼀个区间ret.push_back({ left, right });return ret;}
};
23. ⽆重叠区间(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:int eraseOverlapIntervals(vector<vector<int>>& intervals){// 1. 按照左端点排序sort(intervals.begin(), intervals.end());// 2. 移除区间int ret = 0;int left = intervals[0][0], right = intervals[0][1];for (int i = 1; i < intervals.size(); i++){int a = intervals[i][0], b = intervals[i][1];if (a < right) // 有重叠部分{ret++; // 删掉⼀个区间right = min(right, b);}else // 没有重叠部分{right = b;}}return ret;}
};
24. ⽤最少数量的箭引爆⽓球(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:int findMinArrowShots(vector<vector<int>>& points){// 1. 按照左端点排序sort(points.begin(), points.end());// 2. 求互相重叠区间的数量int right = points[0][1];int ret = 1;for (int i = 1; i < points.size(); i++){int a = points[i][0], b = points[i][1];if (a <= right) // 有重叠部分{right = min(right, b);}else // ⽆重叠部分{ret++;right = b;}}return ret;}
};
25. 整数替换(medium)
Leedcode链接
代码如下(示例):
// 解法一:
class Solution {
public:long long integerReplacement(long long n){return dfs(n);}long long dfs(long long n){if (n == 1) return 0;if (n % 2 == 0) return 1 + dfs(n / 2);else return 1 + min(dfs(n + 1), dfs(n - 1));}
};// 解法二:
class Solution {
public:int integerReplacement(int n) {int ret = 0;while (n > 1){// 分类讨论if (n % 2 == 0){ret++;n /= 2;}else{if (n == 3){ret += 2;n = 1;}else if (n % 4 == 1){ret += 2;n /= 2;}else{ret += 2;n = n / 2 + 1;}}}return ret;}
};
26. 俄罗斯套娃信封问题(hard)
Leedcode链接
代码如下(示例):
class Solution
{
public:int maxEnvelopes(vector<vector<int>>& e){// 解法⼀:动态规划// 预处理sort(e.begin(), e.end());int n = e.size();vector<int> dp(n, 1);int ret = 1;for (int i = 1; i < n; i++){for (int j = 0; j < i; j++){if (e[i][0] > e[j][0] && e[i][1] > e[j][1]){dp[i] = max(dp[i], dp[j] + 1);}}ret = max(ret, dp[i]);}return ret;}
};class Solution
{
public:int maxEnvelopes(vector<vector<int>>& e){// 解法⼆:重写排序 + 贪⼼ + ⼆分sort(e.begin(), e.end(), [&](const vector<int>& v1, const vector<int>&v2){return v1[0] != v2[0] ? v1[0] < v2[0] : v1[1] > v2[1];});// 贪⼼ + ⼆分vector<int> ret;ret.push_back(e[0][1]);for (int i = 1; i < e.size(); i++){int b = e[i][1];if (b > ret.back()){ret.push_back(b);}else{int left = 0, right = ret.size() - 1;while (left < right){int mid = (left + right) / 2;if (ret[mid] >= b) right = mid;else left = mid + 1;}ret[left] = b;}}return ret.size();}
};
27. 可被三整除的最⼤和(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:int maxSumDivThree(vector<int>& nums){const int INF = 0x3f3f3f3f;int sum = 0, x1 = INF, x2 = INF, y1 = INF, y2 = INF;for (auto x : nums){sum += x;if (x % 3 == 1){if (x < x1) x2 = x1, x1 = x;else if (x < x2) x2 = x;}else if (x % 3 == 2){if (x < y1) y2 = y1, y1 = x;else if (x < y2) y2 = x;}}// 分类讨论if (sum % 3 == 0) return sum;else if (sum % 3 == 1) return max(sum - x1, sum - y1 - y2);else return max(sum - y1, sum - x1 - x2);}
};
28. 距离相等的条形码(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:vector<int> rearrangeBarcodes(vector<int>& b){unordered_map<int, int> hash; // 统计每个数出现的频次int maxVal = 0, maxCount = 0;for (auto x : b){if (maxCount < ++hash[x]){maxCount = hash[x];maxVal = x;}}int n = b.size();vector<int> ret(n);int index = 0;// 先处理出现次数最多的那个数for (int i = 0; i < maxCount; i++){ret[index] = maxVal;index += 2;}// 处理剩下的数hash.erase(maxVal);for (auto& [x, y] : hash){for (int i = 0; i < y; i++){if (index >= n) index = 1;ret[index] = x;index += 2;}}return ret;}
};
29. 重构字符串(medium)
Leedcode链接
代码如下(示例):
class Solution
{
public:string reorganizeString(string s) {int hash[26] = { 0 };char maxChar = ' ';int maxCount = 0;for(auto ch : s){if(maxCount < ++hash[ch - 'a']){maxChar = ch;maxCount = hash[ch - 'a'];}}// 先判断⼀下int n = s.size();if(maxCount > (n + 1) / 2) return "";string ret(n, ' ');int index = 0;// 先处理出现次数最多的那个字符for(int i = 0; i < maxCount; i++){ret[index] = maxChar;index += 2;}hash[maxChar - 'a'] = 0;for(int i = 0; i < 26; i++){for(int j = 0; j < hash[i]; j++){if(index >= n) index = 1;ret[index] = 'a' + i;index += 2;}}return ret;}
};
整体源代码总结
代码如下(示例):
#include<iostream>
using namespace std;
#include<string>
#include<vector>//class Solution {
//public:
// bool lemonadeChange(vector<int>& bills)
// {
// int five = 0, ten = 0;
// for (auto x : bills)
// {
// if (x == 5) five++;
// else if (x == 10)
// {
// if (five > 0) five--, ten++;
// else return false;
// }
// else if (x == 20)
// {
// if (five && ten) five--, ten--;
// else if (five >= 3) five -= 3;
// else return false;
// }
// }
// return true;
// }
//};#include<queue>//class Solution {
//public:
// int halveArray(vector<int>& nums)
// {
// priority_queue<double> heap;
// double sum = 0.0;
// for (auto x : nums)
// {
// heap.push(x);
// sum += x;
// }
// sum /= 2.0;
// int count = 0;
// while (sum > 0)
// {
// double ret = heap.top() / 2.0;
// sum -= ret;
// heap.pop();
// count++;
// heap.push(ret);
// }
// return count;
// }
//};//class Solution
//{
//public:
// string largestNumber(vector<int>& nums)
// {
// // 优化:把所有的数转化成字符串
// vector<string> strs;
// for (int x : nums) strs.push_back(to_string(x));
// // 排序
// sort(strs.begin(), strs.end(), [](const string& s1, const string& s2)
// {
// return s1 + s2 > s2 + s1;
// });
// // 提取结果
// string ret;
// for (auto& s : strs) ret += s;
// if (ret[0] == '0') return "0";
// return ret;
// }
//};//class Solution
//{
//public:
// int wiggleMaxLength(vector<int>& nums)
// {
// int n = nums.size();
// if (n < 2) return n;
// int ret = 0, left = 0;
// for (int i = 0; i < n - 1; i++)
// {
// int right = nums[i + 1] - nums[i]; // 计算接下来的趋势
// if (right == 0) continue; // 如果⽔平,直接跳过
// if (right * left <= 0) ret++; // 累加波峰或者波⾕
// left = right;
// }
// return ret + 1;
// }
//};//class Solution {
//public:
// int lengthOfLIS(vector<int>& nums)
// {
// int n = nums.size();
// vector<int> ret;
// ret.push_back(nums[0]);
// for (int i = 1; i < n; i++)
// {
// if (nums[i] > ret.back()) // 如果能接在最后⼀个元素后⾯,直接放
// {
// ret.push_back(nums[i]);
// }
// else
// {
// // ⼆分插⼊位置
// int left = 0, right = ret.size() - 1;
// while (left < right)
// {
// int mid = (left + right) >> 1;
// if (ret[mid] < nums[i]) left = mid + 1;
// else right = mid;
// }
// ret[left] = nums[i]; // 放在 left 位置上
// }
// }
// return ret.size();
// }
//};//class Solution {
//public:
// bool increasingTriplet(vector<int>& nums)
// {
// int n = nums.size();
// int a = nums[0], b = INT_MAX;
// for (int i = 1; i < n; i++)
// {
// if (nums[i] > b) return true;
// else if (nums[i] > a) b = nums[i];
// else a = nums[i];
// }
// return false;
// }
//};//class Solution {
//public:
// int findLengthOfLCIS(vector<int>& nums)
// {
// int ret = 0, n = nums.size();
// for (int i = 0; i < n; )
// {
// int j = i + 1;
// while (j < n && nums[j] > nums[j - 1]) j++;
// ret = max(ret, j - i);
// i = j;
// }
// return ret;
// }
//};//class Solution {
//public:
// int maxProfit(vector<int>& prices)
// {
// int ret = 0;
// for (int i = 0, priceMin = INT_MAX; i < prices.size(); i++)
// {
// ret = max(ret, prices[i] - priceMin);
// priceMin = min(priceMin, prices[i]);
// }
// return ret;
// }
//};//class Solution
//{
//public:
// int maxProfit(vector<int>& p)
// {
// // 实现⽅式⼀:双指针
// int ret = 0, n = p.size();
// for (int i = 0; i < n; i++)
// {
// int j = i;
// while (j + 1 < n && p[j + 1] > p[j]) j++; // 找上升的末端
// ret += p[j] - p[i];
// i = j;
// }
// return ret;
// }
//};
//class Solution
//{
//public:
// int maxProfit(vector<int>& prices)
// {
// // 实现⽅式⼆:拆分成⼀天⼀天
// int ret = 0;
// for (int i = 1; i < prices.size(); i++)
// {
// if (prices[i] > prices[i - 1])
// ret += prices[i] - prices[i - 1];
// }
// return ret;
// }
//};//class Solution
//{
//public:
// int largestSumAfterKNegations(vector<int>& nums, int k)
// {
// int m = 0, minElem = INT_MAX, n = nums.size();
// for (auto x : nums)
// {
// if (x < 0) m++;
// minElem = min(minElem, abs(x)); // 求绝对值最⼩的那个数
// }
// // 分类讨论
// int ret = 0;
// if (m > k)
// {
// sort(nums.begin(), nums.end());
// for (int i = 0; i < k; i++) // 前 k ⼩个负数,变成正数
// {
// ret += -nums[i];
// }
// for (int i = k; i < n; i++) // 后⾯的数不变
// {
// ret += nums[i];
// }
// }
// else
// {
// // 把所有的负数变成正数
// for (auto x : nums) ret += abs(x);
// if ((k - m) % 2) // 判断是否处理最⼩的正数
// {
// ret -= minElem * 2;
// }
// }
// return ret;
// }
//};//class Solution
//{
//public:
// vector<string> sortPeople(vector<string>& names, vector<int>& heights)
// {
// // 1. 创建⼀个下标数组
// int n = names.size();
// vector<int> index(n);
// for (int i = 0; i < n; i++) index[i] = i;
// // 2. 对下标进⾏排序
// sort(index.begin(), index.end(), [&](int i, int j)
// {
// return heights[i] > heights[j];
// });
// // 3. 提取结果
// vector<string> ret;
// for (int i : index)
// {
// ret.push_back(names[i]);
// }
// return ret;
// }
//};//class Solution
//{
//public:
// vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2)
// {
// int n = nums1.size();
// // 1. 排序
// sort(nums1.begin(), nums1.end());
// vector<int> index2(n);
// for (int i = 0; i < n; i++) index2[i] = i;
// sort(index2.begin(), index2.end(), [&](int i, int j)
// {
// return nums2[i] < nums2[j];
// });
// // 2. ⽥忌赛⻢
// vector<int> ret(n);
// int left = 0, right = n - 1;
// for (auto x : nums1)
// {
// if (x > nums2[index2[left]]) ret[index2[left++]] = x;
// else ret[index2[right--]] = x;
// }
// return ret;
// }
//};// LINUX
//struct shmid_ds {
// struct ipc_perm shm_perm; /* operation perms */
// int shm_segsz; /* size of segment
// (bytes) */
// __kernel_time_t shm_atime; /* last attach time
// */
// __kernel_time_t shm_dtime; /* last detach time
// */
// __kernel_time_t shm_ctime; /* last change time
// */
// __kernel_ipc_pid_t shm_cpid; /* pid of creator */
// __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
// unsigned short shm_nattch; /* no. of current
// attaches */
// unsigned short shm_unused; /* compatibility */
// void shm_unused2; / ditto - used by
// DIPC * /
// void shm_unused3; / unused * /
//};//class Solution
//{
//public:
// int longestPalindrome(string s)
// {
// // 1. 计数 - ⽤数组模拟哈希表
// int hash[127] = { 0 };
// for (char ch : s) hash[ch]++;
// // 2. 统计结果
// int ret = 0;
// for (int x : hash)
// {
// ret += x / 2 * 2;
// }
// return ret < s.size() ? ret + 1 : ret;
// }
//};//class Solution {
//public:
// vector<int> diStringMatch(string s)
// {
// int left = 0, right = s.size();
// vector<int> ret;
// for (auto ch : s)
// {
// if (ch == 'I') ret.push_back(left++);
// else ret.push_back(right--);
// }
// ret.push_back(left);
// return ret;
// }
//};//class Solution {
//public:
// int findContentChildren(vector<int>& g, vector<int>& s)
// {
// // 先排序
// sort(g.begin(), g.end());
// sort(s.begin(), s.end());
// // 利⽤双指针找答案
// int ret = 0, n = s.size();
// for (int i = 0, j = 0; i < g.size() && j < n; i++, j++)
// {
// while (j < n && s[j] < g[i]) j++; // 找饼⼲
// if (j < n) ret++;
// }
// return ret;
// }
//};//class Solution
//{
//public:
// string optimalDivision(vector<int>& nums)
// {
// int n = nums.size();
// // 先处理两个边界情况
// if (n == 1)
// {
// return to_string(nums[0]);
// }
// if (n == 2)
// {
// return to_string(nums[0]) + "/" + to_string(nums[1]);
// }
// string ret = to_string(nums[0]) + "/(" + to_string(nums[1]);
// for (int i = 2; i < n; i++)
// {
// ret += "/" + to_string(nums[i]);
// }
// ret += ")";
// return ret;
// }
//};//class Solution
//{
//public:
// int jump(vector<int>& nums)
// {
// int left = 0, right = 0, maxPos = 0, ret = 0, n = nums.size();
// while (left <= right) // 保险的写法,以防跳不到 n - 1 的位置
// {
// if (maxPos >= n - 1) // 先判断⼀下是否已经能跳到最后⼀个位置
// {
// return ret;
// }
// // 遍历当成层,更新下⼀层的最右端点
// for (int i = left; i <= right; i++)
// {
// maxPos = max(maxPos, nums[i] + i);
// }
// left = right + 1;
// right = maxPos;
// ret++;
// }
// return -1; // 跳不到的情况
// }
//};//class Solution
//{
//public:
// bool canJump(vector<int>& nums)
// {
// int left = 0, right = 0, maxPos = 0, n = nums.size();
// while (left <= right)
// {
// if (maxPos >= n - 1)
// {
// return true;
// }
// for (int i = left; i <= right; i++)
// {
// maxPos = max(maxPos, nums[i] + i);
// }
// left = right + 1;
// right = maxPos;
// }
// return false;
// }
//};//class Solution
//{
//public:
// int canCompleteCircuit(vector<int>& gas, vector<int>& cost)
// {
// int n = gas.size();
// for (int i = 0; i < n; i++) // 依次枚举所有的起点
// {
// int rest = 0; // 标记⼀下净收益
// int step = 0;
// for (; step < n; step++) // 枚举向后⾛的步数
// {
// int index = (i + step) % n; // 求出⾛ step 步之后的下标
// rest = rest + gas[index] - cost[index];
// if (rest < 0) break;
// }
// if (rest >= 0) return i;
// i = i + step; // 优化
// }
// return -1;
// }
//};//class Solution
//{
//public:
// int monotoneIncreasingDigits(int n)
// {
// string s = to_string(n); // 把数字转化成字符串
// int i = 0, m = s.size();
// // 找第⼀个递减的位置
// while (i + 1 < m && s[i] <= s[i + 1]) i++;
// if (i + 1 == m) return n; // 判断⼀下特殊情况
// // 回推
// while (i - 1 >= 0 && s[i] == s[i - 1]) i--;
// s[i]--;
// for (int j = i + 1; j < m; j++) s[j] = '9';
// return stoi(s);
// }
//};//class Solution {
//public:
// int brokenCalc(int startValue, int target)
// {
// int ret = 0;
// while (startValue < target)
// {
// if (target % 2 == 0) target /= 2;
// else target += 1;
// ret++;
// }
// return ret + startValue - target;
// }
//};//class Solution
//{
//public:
// vector<vector<int>> merge(vector<vector<int>>& intervals)
// {
// // 1. 先按照左端点排序
// sort(intervals.begin(), intervals.end());
// // 2. 合并区间
// int left = intervals[0][0], right = intervals[0][1];
// vector<vector<int>> ret;
// for (int i = 1; i < intervals.size(); i++)
// {
// int a = intervals[i][0], b = intervals[i][1];
// if (a <= right) // 有重叠部分
// {
// // 合并 - 求并集
// right = max(right, b);
// }
// else // 没有重叠部分
// {
// ret.push_back({ left, right }); // 加⼊到结果中
// left = a;
// right = b;
// }
// }
// // 别忘了最后⼀个区间
// ret.push_back({ left, right });
// return ret;
// }
//};//class Solution
//{
//public:
// int eraseOverlapIntervals(vector<vector<int>>& intervals)
// {
// // 1. 按照左端点排序
// sort(intervals.begin(), intervals.end());
// // 2. 移除区间
// int ret = 0;
// int left = intervals[0][0], right = intervals[0][1];
// for (int i = 1; i < intervals.size(); i++)
// {
// int a = intervals[i][0], b = intervals[i][1];
// if (a < right) // 有重叠部分
// {
// ret++; // 删掉⼀个区间
// right = min(right, b);
// }
// else // 没有重叠部分
// {
// right = b;
// }
// }
// return ret;
// }
//};//class Solution
//{
//public:
// int findMinArrowShots(vector<vector<int>>& points)
// {
// // 1. 按照左端点排序
// sort(points.begin(), points.end());
// // 2. 求互相重叠区间的数量
// int right = points[0][1];
// int ret = 1;
// for (int i = 1; i < points.size(); i++)
// {
// int a = points[i][0], b = points[i][1];
// if (a <= right) // 有重叠部分
// {
// right = min(right, b);
// }
// else // ⽆重叠部分
// {
// ret++;
// right = b;
// }
// }
// return ret;
// }
//};//class Solution {
//public:
// int integerReplacement(int n) {
//
// int ret = 0;
// while (n > 1)
// {
// // 分类讨论
// if (n % 2 == 0)
// {
// ret++;
// n /= 2;
// }
// else
// {
// if (n == 3)
// {
// ret += 2;
// n = 1;
// }
// else if (n % 4 == 1)
// {
// ret += 2;
// n /= 2;
// }
// else
// {
// ret += 2;
// n = n / 2 + 1;
// }
// }
// }
// return ret;
// }
//};//// 解法一:
//class Solution {
//public:
// long long integerReplacement(long long n)
// {
// return dfs(n);
// }
// long long dfs(long long n)
// {
// if (n == 1) return 0;
// if (n % 2 == 0) return 1 + dfs(n / 2);
// else return 1 + min(dfs(n + 1), dfs(n - 1));
// }
//};//class Solution
//{
//public:
// int maxEnvelopes(vector<vector<int>>& e)
// {
// // 解法⼀:动态规划
// // 预处理
// sort(e.begin(), e.end());
// int n = e.size();
// vector<int> dp(n, 1);
// int ret = 1;
// for (int i = 1; i < n; i++)
// {
// for (int j = 0; j < i; j++)
// {
// if (e[i][0] > e[j][0] && e[i][1] > e[j][1])
// {
// dp[i] = max(dp[i], dp[j] + 1);
// }
// }
// ret = max(ret, dp[i]);
// }
// return ret;
// }
//};
//
//
//class Solution
//{
//public:
// int maxEnvelopes(vector<vector<int>>& e)
// {
// // 解法⼆:重写排序 + 贪⼼ + ⼆分
// sort(e.begin(), e.end(), [&](const vector<int>& v1, const vector<int>&
// v2)
// {
// return v1[0] != v2[0] ? v1[0] < v2[0] : v1[1] > v2[1];
// });
// // 贪⼼ + ⼆分
// vector<int> ret;
// ret.push_back(e[0][1]);
// for (int i = 1; i < e.size(); i++)
// {
// int b = e[i][1];
// if (b > ret.back())
// {
// ret.push_back(b);
// }
// else
// {
// int left = 0, right = ret.size() - 1;
// while (left < right)
// {
// int mid = (left + right) / 2;
// if (ret[mid] >= b) right = mid;
// else left = mid + 1;
// }
// ret[left] = b;
// }
// }
// return ret.size();
// }
//};//class Solution
//{
//public:
// int maxSumDivThree(vector<int>& nums)
// {
// const int INF = 0x3f3f3f3f;
// int sum = 0, x1 = INF, x2 = INF, y1 = INF, y2 = INF;
// for (auto x : nums)
// {
// sum += x;
// if (x % 3 == 1)
// {
// if (x < x1) x2 = x1, x1 = x;
// else if (x < x2) x2 = x;
// }
// else if (x % 3 == 2)
// {
// if (x < y1) y2 = y1, y1 = x;
// else if (x < y2) y2 = x;
// }
// }
// // 分类讨论
// if (sum % 3 == 0) return sum;
// else if (sum % 3 == 1) return max(sum - x1, sum - y1 - y2);
// else return max(sum - y1, sum - x1 - x2);
// }
//};//class Solution
//{
//public:
// vector<int> rearrangeBarcodes(vector<int>& b)
// {
// unordered_map<int, int> hash; // 统计每个数出现的频次
// int maxVal = 0, maxCount = 0;
// for (auto x : b)
// {
// if (maxCount < ++hash[x])
// {
// maxCount = hash[x];
// maxVal = x;
// }
// }
// int n = b.size();
// vector<int> ret(n);
// int index = 0;
// // 先处理出现次数最多的那个数
// for (int i = 0; i < maxCount; i++)
// {
// ret[index] = maxVal;
// index += 2;
// }
// // 处理剩下的数
// hash.erase(maxVal);
// for (auto& [x, y] : hash)
// {
// for (int i = 0; i < y; i++)
// {
// if (index >= n) index = 1;
// ret[index] = x;
// index += 2;
// }
// }
// return ret;
// }
//};//class Solution
//{
//public:
// string reorganizeString(string s)
// {
// int hash[26] = { 0 };
// char maxChar = ' ';
// int maxCount = 0;
// for (auto ch : s)
// {
// if (maxCount < ++hash[ch - 'a'])
// {
// maxChar = ch;
// maxCount = hash[ch - 'a'];
// }
// }
// // 先判断⼀下
// int n = s.size();
// if (maxCount > (n + 1) / 2) return "";
// string ret(n, ' ');
// int index = 0;
// // 先处理出现次数最多的那个字符
// for (int i = 0; i < maxCount; i++)
// {
// ret[index] = maxChar;
// index += 2;
// }
// hash[maxChar - 'a'] = 0;
// for (int i = 0; i < 26; i++)
// {
// for (int j = 0; j < hash[i]; j++)
// {
// if (index >= n) index = 1;
// ret[index] = 'a' + i;
// index += 2;
// }
// }
// return ret;
// }
//};