贪心算法精选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;
//    }
//};
相关推荐
江畔柳前堤8 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore10 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考11 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX12 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面12 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号13 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽13 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI13 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者15 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者15 小时前
【征程6】校准量化中HistogramObserver解析
算法