思维题专题

贪心子专题-五、思维题

参考:分享丨【题单】贪心算法(基本贪心策略/反悔/区间/字典序/数学/思维/构造)- 讨论 - 力扣(LeetCode)

一、 从特殊到一般

Leetcode 781. 森林中的兔子

思考:“从特殊到一般”找规律

        特殊:

        一般:

(上取整转变为下取整的方法参见“数学专题”)

Code:

class Solution {
public:
    int numRabbits(vector<int>& answers) {
        unordered_map<int, int> cnt;
        for (int x: answers)    cnt[x] ++;
        int res = 0;
        for (auto& [x, c]: cnt) 
            res += (c + x) / (x + 1) * (x + 1);
        return res;
    }
};

二、从一般到特殊

Leetcode 1007. 行相等的最少多米诺旋转

思考:转化/分类讨论/增加setting

        目标是让第一排或者第二排的所有数都相同,这个「所有」必然包含第一个骨牌中的数。所以要么都变成 tops[0],要么都变成 bottoms[0]。计算这两种情况,取最小值。

minRot起到了增加一个条件,更好的解决问题的作用。

Code

class Solution {
public:
    int minDominoRotations(vector<int>& tops, vector<int>& bottoms) {
        auto min_rot = [&](int target) -> int {
            int to_top = 0, to_bottom = 0;
            for (int i = 0; i < tops.size(); i ++) {
                int x = tops[i], y = bottoms[i];
                if (x != target && y != target) return INT_MAX;
                if (x != target)    to_top ++;  // 把y旋转到上半
                else if(y != target) to_bottom ++;  // x旋转到下半
            }  
            return min(to_top, to_bottom);
        };
        int res = min(min_rot(tops[0]), min_rot(bottoms[0]));
        return res == INT_MAX ? -1: res;
    }
};

        感觉这种类似二分的setting,会将一个变量控制不变(增加一个条件),再去解决问题时,会更方便的解决。

 Leetcode 2860. 让所有学生保持开心的分组方法数

 暴力解法:dfs搜索,超时。。。

贪心:(比大小---->sort)遇事不决先排序

由于排序后,选中的人数就是i + 1,所以判断条件就变成了nums[i] < i + 1 < nums[i + 1] 

最关键的点:①前缀优先选择

②选择中的人数转化为i+1,然后需要满足题目的两个条件(第i位同学满足选中的条件,第i+1位同学需要满足不选中的条件,即可推到全体范围都满足条件)。

class Solution {
public:
    int countWays(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int res = 0;
        // 特判都不来   
        res = (0 < nums[0]);
        // 一般情况
        for(int i = 0; i < nums.size() - 1; i ++){  // 减去1后,全来的情况直接特判即可。
            if((i + 1) > nums[i] && (i + 1) < nums[i + 1])  
                res ++;
        }
        // 特判都来(由于数据范围,总人数是必定>nums[i]的,所以res++)
        res = res + 1;
        return res;
    }
};

其他

Leetcode 最长相邻不相等子序列 I

思路:题意:选一个 words 的子序列,要求相邻字符串对应的 groups[i] 不同。

class Solution {
public:
    vector<string> getLongestSubsequence(vector<string>& words, vector<int>& groups) {
        int n = words.size();
        vector<string> res;
        for (int i = 0; i < n; i ++)    
            if (i == n - 1 || groups[i] != groups[i + 1])
                res.push_back(words[i]);
        return res;
    }
};

Leetcode 75. 颜色分类 

思路:技巧:O(1) 插入元素

        简单来说:遍历的时候记录下当前位置的值,之后当前位置无脑变2,p1和p0两个指针跟着擦屁股。p1,p0是nums要变为1或者变为0的位置,最终遍历完成后p0为最后一个0的位置,p1是最后一个1的位置。

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int p0 = 0, p1 = 0;
        for (int i = 0; i < nums.size(); i ++) {
            int x = nums[i];
            nums[i] = 2;
            if (x <= 1)     nums[p1 ++] = 1;
            if (x == 0)     nums[p0 ++] = 0;
        }
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Ocean__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值