贪心算法专题练习

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;
	}
};
相关推荐
点云SLAM1 小时前
二叉树算法详解和C++代码示例
数据结构·c++·算法·红黑树·二叉树算法
今天背单词了吗9808 小时前
算法学习笔记:19.牛顿迭代法——从原理到实战,涵盖 LeetCode 与考研 408 例题
笔记·学习·算法·牛顿迭代法
jdlxx_dongfangxing9 小时前
进制转换算法详解及应用
算法
why技术10 小时前
也是出息了,业务代码里面也用上算法了。
java·后端·算法
2501_9228955810 小时前
字符函数和字符串函数(下)- 暴力匹配算法
算法
IT信息技术学习圈11 小时前
算法核心知识复习:排序算法对比 + 递归与递推深度解析(根据GESP四级题目总结)
算法·排序算法
愚润求学11 小时前
【动态规划】01背包问题
c++·算法·leetcode·动态规划
会唱歌的小黄李12 小时前
【算法】贪心算法入门
算法·贪心算法
轻语呢喃13 小时前
每日LeetCode : 两数相加--链表操作与进位的经典处理
javascript·算法
钢铁男儿13 小时前
C# 接口(接口可以继承接口)
java·算法·c#