贪心算法专题练习

1. K次取反后最大化的数组和

这个题目的贪心就体现在最小的负数取反之后对整个数组和的贡献是最大的,直接上思路:

直接上代码:

cpp 复制代码
class Solution {
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        int m = 0;
        int n = nums.size();
        int minNum = INT_MAX;
        int ret = 0;
        for(auto& e : nums)
        {
            if(e < 0) m++;
            minNum = min(minNum, abs(e)); // 求绝对值最小元素
        }
        // 分类讨论
        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 != 0) // 判断是否处理最⼩的正数
            {
                ret -= minNum * 2;
            }
        }
        return ret;  
    }
};

2. 按身高排序

这个题目比较简单,按照贪心的思想我们只需要按照身高的最大值排序即可,但是仍有一些细节问题,我们不能直接按照i位置对应的heights来排序,因为排序过程是会移动元素的,但是names内的元素是不会移动的。由题意可知,names 数组和heights数组的下标是一一对应的, 因此我们可以重新创建出来一个下标数组,将这个下标数组按照heights[i]的大小排序。那么,当下标数组排完序之后,里面的顺序就相当于heights这个数组排完序之后的下标。之后通过排序后的下标,依次找到原来的name,完成对名字的排序。

直接上代码:

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

3.优势洗牌(田忌赛马)

此时我们有了这个概念,我们就来模拟一遍流程

直接上代码:

cpp 复制代码
class Solution {
public:
    vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {
        vector<int> index(nums1.size());
        // 1.排序
        for(int i = 0; i < nums1.size(); i++)
            index[i] = i;
        sort(nums1.begin(), nums1.end());
        sort(index.begin(), index.end(), [&](int x, int y)
        {
            return nums2[x] < nums2[y];
        });

        // 田忌赛马
        int left = 0;
        int right = nums1.size() - 1;
        vector<int> ret(nums1.size());
        for(auto e : nums1)
        {
            // index[left] 代表最小值的下标
            // nums2[index[left]] 代表nums2中的最小值
            if(e > nums2[index[left]]) ret[index[left++]] = e;
            // index[right] 代表最大值的下标
            // ret[index[right]] 代表nums2中的最大值
            else ret[index[right--]] = e;
        }
        return ret;
    }
};

4.最长回文串

这个题目比较简单,根据回文串的特点,我们只需要统计字符出现的次数,再判断奇数和偶数的情况即可,直接上思路:

直接上代码:

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

5. 增减字符串匹配

贪心策略算法思路:

  • a. 当遇到 "I" 的时候,为了让下⼀个上升的数可选择的「范围更多」,当前选择「最小」的那 个数;
  • b. 当遇到 "D" 的时候,为了让下⼀个下降的数可选择的「范围更多」,选择当前「最大」的那 个数。

直接上代码:

cpp 复制代码
class Solution
{
public:
	vector<int> diStringMatch(string s)
	{
		int left = 0, right = s.size(); // 用left,right标记最小值和最⼤值
		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;
	}
};
相关推荐
聚客AI13 小时前
🙋‍♀️Transformer训练与推理全流程:从输入处理到输出生成
人工智能·算法·llm
大怪v16 小时前
前端:人工智能?我也会啊!来个花活,😎😎😎“自动驾驶”整起!
前端·javascript·算法
惯导马工18 小时前
【论文导读】ORB-SLAM3:An Accurate Open-Source Library for Visual, Visual-Inertial and
深度学习·算法
骑自行车的码农19 小时前
【React用到的一些算法】游标和栈
算法·react.js
博笙困了20 小时前
AcWing学习——双指针算法
c++·算法
moonlifesudo20 小时前
322:零钱兑换(三种方法)
算法
NAGNIP2 天前
大模型框架性能优化策略:延迟、吞吐量与成本权衡
算法
美团技术团队2 天前
LongCat-Flash:如何使用 SGLang 部署美团 Agentic 模型
人工智能·算法
Fanxt_Ja2 天前
【LeetCode】算法详解#15 ---环形链表II
数据结构·算法·leetcode·链表
侃侃_天下2 天前
最终的信号类
开发语言·c++·算法