贪心算法(灵神提单)

示例:
分享丨【题单】贪心算法(基本贪心策略/反悔/区间/字典序/数学/思维/构造) - 力扣(LeetCode)https://leetcode.cn/circle/discuss/g6KTKL/

一、基础区:

eg 1、3074. 重新分装苹果 - 力扣(LeetCode)

class Solution {
public:
    int minimumBoxes(vector<int>& apple, vector<int>& capacity) {
        // 每次都选最大的包裹--需要的包裹数最小
        int ans = 0, sum = 0;
        sum = reduce(apple.begin(), apple.end()); // 求和
        // for (int i : apple)
        //     sum += i;

        // 逆序排序
        // sort(capacity.rbegin(), capacity.rend());
        ranges::sort(capacity, greater());
        for (int i : capacity) {
            sum -= i;
            ans++;
            if (sum <= 0)
                break;
        }
        return ans;
    }
};

eg 2、2279. 装满石头的背包的最大数量 - 力扣(LeetCode)

class Solution {
public:
    int maximumBags(vector<int>& capacity, vector<int>& rocks, int additionalRocks) {
        // 计算每个包裹里面的剩余空间 并从小排序
        for(int i = 0; i < rocks.size(); i++)
            capacity[i] -= rocks[i];
        sort(capacity.begin(), capacity.end());
        // 开始装石头 
        int j = 0; 
        // additionalRocks >= capacity[j]--确保装满石头
        while (j < capacity.size() && additionalRocks >= capacity[j] ){
            additionalRocks -= capacity[j];
            j++;
        }
        return j;
    }
};

eg 3、1833. 雪糕的最大数量 - 力扣(LeetCode)

class Solution {
public:
    void counterSort(vector<int>& vec) {
        // 当数组为空时,直接返回
        if (vec.empty())
            return;
        // 找最大值
        int maxx = *max_element(vec.begin(), vec.end());
        // 开数组
        vector<int> counter(maxx + 1);
        // 计数
        for (int i = 0; i < vec.size(); i++)
            counter[vec[i]]++;
        // 按下标取数
        vec.clear();
        for (int i = 0; i <= maxx; i++) 
            while (counter[i] > 0) {
                vec.push_back(i);
                counter[i]--;
            }
    }

    int maxIceCream(vector<int>& costs, int coins) {
        counterSort(costs);
        int ans = 0;
        for (int i = 0; i < costs.size(); i++) {
            if (coins - costs[i] < 0)
                break;
            ans++;
            coins -= costs[i];
        }
        return ans;
    }
};

eg 4、1005. K 次取反后最大化的数组和 - 力扣(LeetCode)

class Solution {
public:

// 思路:优先把负数取反,若负数数量不足 k 个,再考虑对绝对值最小的数进行多次取反。

    int largestSumAfterKNegations(vector<int>& nums, int k) {
        // 对数组进行排序
        sort(nums.begin(), nums.end());
        int sum = 0;
        int min_abs = INT_MAX;

        // 优先将负数取反
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] < 0 && k > 0) {
                nums[i] = -nums[i];
                k--;
            }
            sum += nums[i];
            min_abs = min(min_abs, abs(nums[i]));
        }

        // 如果 k 还有剩余且为奇数,减去最小绝对值的两倍
        // 偶数就不用减了 因为每次都对同一个元素取反
        // 本来是 正数 变为 负数 就少了两份 所以要减两份
        if (k % 2 == 1) 
            sum -= 2 * min_abs;
        return sum;
    }
};

// class Solution {
// public:
//     void counter_sort(vector<int>& vec) {
//         if (vec.empty())
//             return;
//         // 找到最小值和最大值
//         int min_val = *min_element(vec.begin(), vec.end());
//         int max_val = *max_element(vec.begin(), vec.end());
//         // 计算范围
//         int range = max_val - min_val + 1;
//         vector<int> countArr(range);
//         // 计数
//         for (int num : vec) 
//             countArr[num - min_val]++;
//        
//         // 重新填充原数组
//         int index = 0;
//         for (int i = 0; i < range; i++) {
//             while (countArr[i] > 0) {
//                 vec[index++] = i + min_val;
//                 countArr[i]--;
//             }
//         }
//     }

//     int largestSumAfterKNegations(vector<int>& nums, int k) {
//         counter_sort(nums);
//         int sum = 0;
//         int min_abs = INT_MAX;

//         // 优先将负数取反
//         for (int i = 0; i < nums.size(); i++) {
//             if (nums[i] < 0 && k > 0) {
//                 nums[i] = -nums[i];
//                 k--;
//             }
//             sum += nums[i];
//             min_abs = min(min_abs, abs(nums[i]));
//         }

//         // 如果 k 还有剩余且为奇数,减去最小绝对值的两倍
//         if (k % 2 == 1) 
//             sum -= 2 * min_abs;
//         return sum;
//     }
// };

eg 5、1481. 不同整数的最少数目 - 力扣(LeetCode)

/*
    先将最少的数字去掉
*/
class Solution {
public:
    int findLeastNumOfUniqueInts(std::vector<int>& arr, int k) {
        unordered_map<int, int> count;
        for (auto x : arr)
            count[x]++;

        vector<int> a;
        for (auto& pair : count)
            a.push_back(pair.second);

        sort(a.begin(), a.end());
        for (int i = 0; i < a.size(); i++) {
            if (k - a[i] < 0)
                break;
            k -= a[i];
            a[i] = 0;
        }
        int ans = 0;
        for (int i = 0; i < a.size(); i++) 
            if (a[i] != 0) 
                ans++;
        return ans;
    }
};

eg 6、 1403. 非递增顺序的最小子序列 - 力扣(LeetCode)

class Solution {
public:
    vector<int> minSubsequence(vector<int>& nums) {
        int sum = 0;
        int n = nums.size();
        for(auto x : nums)
            sum += x;
        sort(nums.begin(), nums.end(),[](int x, int y){
            return x > y;
        });
        vector<int> ans;
        int ssum = 0;
        for(int i = 0; i < n; i++){
            ssum += nums[i];
            ans.push_back(nums[i]);
            sum -= nums[i];
            if(ssum > sum)
                break;
        }
        return ans;
    }
};

eg 7、3010. 将数组分成最小总代价的子数组 I - 力扣(LeetCode)

// 第一个数必选 再选两个最小的作为头
class Solution {
public:
    int minimumCost(vector<int> &nums) {
        sort(nums.begin() + 1, nums.end());
        return accumulate(nums.begin(), nums.begin() + 3, 0);
    }
};

eg 8、1338. 数组大小减半 - 力扣(LeetCode)

class Solution {
public:
    int minSetSize(vector<int>& arr) {
        int mmax = ranges::max(arr);
        // int mmax = *max_element(arr.begin(), arr.end());
        vector<int> frequencies(mmax + 1);
        for (int x : arr) 
            frequencies[x]++;
        // 从大到小排序
        ranges::sort(frequencies, greater());
        // sort(frequencies.begin(), frequencies.end(), greater<int>());
        int ans = 0;
        for (int i = 0; ; i++) {
            ans += frequencies[i];
            if (ans >= arr.size() / 2) 
                return i + 1;
        }
    }
};
/*
class Solution {
public:
    int minSetSize(std::vector<int>& arr) {
        unordered_map<int, int> hash;
        int sum = arr.size();
        for (auto x : arr) 
            hash[x]++;
        
        vector<int> frequencies;
        for (const auto& pair : hash) {
            frequencies.push_back(pair.second);
        }
        // 从大到小排序
        sort(frequencies.begin(), frequencies.end(), greater<int>());
        int removed = 0;
        int ans = 0;

        for (int freq : frequencies) {
            removed += freq;
            ans++;
            if (removed >= sum / 2)
                break;
        }
        return ans;
    }
};
*/

eg 9、1710. 卡车上的最大单元数 - 力扣(LeetCode)

class Solution {
public:
    int maximumUnits(vector<vector<int>>& boxes, int truckSize) {
        sort(boxes.begin(), boxes.end(),
             [](const vector<int>& a, const vector<int>& b) {
                 return a[1] > b[1];
             });
        int ans = 0;
        for (auto box : boxes) {
            int numBoxes = min(box[0], truckSize);
            ans += numBoxes * box[1];
            truckSize -= numBoxes;
            if (truckSize == 0)
                break;
        }
        return ans;
    }
};

eg 10、3075. 幸福值最大化的选择方案 - 力扣(LeetCode)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值