贪心算法精选30道编程题 (附有图解和源码)

贪心算法精选30道编程题


文章目录

  • 贪心算法精选30道编程题
  • 贪心算法简介
    • [1. 柠檬⽔找零(easy)](#1. 柠檬⽔找零(easy))
    • [2. 将数组和减半的最少操作次数(medium)](#2. 将数组和减半的最少操作次数(medium))
    • [3. 最⼤数(medium)](#3. 最⼤数(medium))
    • [4. 摆动序列(medium)](#4. 摆动序列(medium))
    • [5. 最⻓递增⼦序列(medium)](#5. 最⻓递增⼦序列(medium))
    • [6. 递增的三元⼦序列(medium)](#6. 递增的三元⼦序列(medium))
    • [7. 最⻓连续递增序列(easy)](#7. 最⻓连续递增序列(easy))
    • [8. 买卖股票的最佳时机(easy)](#8. 买卖股票的最佳时机(easy))
    • [9. 买卖股票的最佳时机 Ⅱ(medium)](#9. 买卖股票的最佳时机 Ⅱ(medium))
    • [10. K 次取反后最⼤化的数组和(easy)](#10. K 次取反后最⼤化的数组和(easy))
    • [11. 按⾝⾼排序(easy)](#11. 按⾝⾼排序(easy))
    • [12. 优势洗牌(⽥忌赛⻢)(medium)](#12. 优势洗牌(⽥忌赛⻢)(medium))
    • [13. 最⻓回⽂串(easy)](#13. 最⻓回⽂串(easy))
    • [14. 增减字符串匹配(easy)](#14. 增减字符串匹配(easy))
    • [15. 分发饼⼲(easy)](#15. 分发饼⼲(easy))
    • [16. 最优除法(medium)](#16. 最优除法(medium))
    • [17. 跳跃游戏 Ⅱ(medium)](#17. 跳跃游戏 Ⅱ(medium))
    • [18. 跳跃游戏(medium)](#18. 跳跃游戏(medium))
    • [19. 加油站(medium)](#19. 加油站(medium))
    • [20. 单调递增的数字(medium)](#20. 单调递增的数字(medium))
    • [21. 坏了的计算器(medium)](#21. 坏了的计算器(medium))
    • [22. 合并区间(medium)](#22. 合并区间(medium))
    • [23. ⽆重叠区间(medium)](#23. ⽆重叠区间(medium))
    • [24. ⽤最少数量的箭引爆⽓球(medium)](#24. ⽤最少数量的箭引爆⽓球(medium))
    • [25. 整数替换(medium)](#25. 整数替换(medium))
    • [26. 俄罗斯套娃信封问题(hard)](#26. 俄罗斯套娃信封问题(hard))
    • [27. 可被三整除的最⼤和(medium)](#27. 可被三整除的最⼤和(medium))
    • [28. 距离相等的条形码(medium)](#28. 距离相等的条形码(medium))
    • [29. 重构字符串(medium)](#29. 重构字符串(medium))
  • 整体源代码总结

贪心算法简介


1. 柠檬⽔找零(easy)

Leedcode链接






代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接






代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接



解题思路:贪心+双指针



代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接






代码如下(示例):

c 复制代码
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链接





代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接





代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接





代码如下(示例):

c 复制代码
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一定在分母上!把后面所有的数都放在分子上即可~



代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接





代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
// 解法一:
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链接




代码如下(示例):

c 复制代码
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链接




代码如下(示例):

c 复制代码
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链接



代码如下(示例):

c 复制代码
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链接



代码如下(示例):

c 复制代码
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;
 }
};

整体源代码总结

代码如下(示例):

c 复制代码
#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;
//    }
//};
相关推荐
CoovallyAIHub4 小时前
顶刊新发!上海交大提出PreCM:即插即用的旋转等变卷积,显著提升分割模型鲁棒性
人工智能·算法·计算机视觉
超级大只老咪4 小时前
哈希表(算法)
java·算法·哈希算法
冷月葬花~4 小时前
day24
数据结构·算法·leetcode
仰泳的熊猫5 小时前
LeetCode:538. 把二叉搜索树转换为累加树/1038. 从二叉搜索树到更大和树
数据结构·c++·算法·leetcode
weixin_307779135 小时前
Clickhouse导出库的表、视图、用户和角色定义的SQL语句
开发语言·数据库·算法·clickhouse·自动化
piggy侠6 小时前
【GitHub每日速递 251016】23k star,Daytona:90ms内极速运行AI代码,安全弹性基础设施来袭!
算法·github
小龙报6 小时前
《算法通关指南---C++编程篇(1)》
开发语言·c++·程序人生·算法·学习方法·visual studio
Cx330❀6 小时前
《C++ 手搓list容器底层》:从结构原理深度解析到功能实现(附源码版)
开发语言·数据结构·c++·经验分享·算法·list
Swift社区6 小时前
LeetCode 399 除法求值
算法·leetcode·职场和发展