算法【贪心经典题目专题2】

题目一

测试链接:LCR 132. 砍竹子 II - 力扣(LeetCode)

分析:对于特殊情况2和3直接返回1和2。观察到大于等于4时,如果长度模3等于0,则答案全部是由3相乘;如果长度模3等于1,则答案最后会有两个2相乘;如果长度模3等于2,则答案最后会有一个2相乘。且长度模3等于0时,3的个数是长度除以3;长度模3等于1时,3的个数是长度除以3-1;长度模3等于2时,3的个数是长度除以3。然后相乘即可得到答案。代码如下。

class Solution {
public:
    int MOD = 1000000007;
    int power(int number, int num){
        int ans = 1;
        int temp = number;
        for(int i = 0;i < 32;++i){
            if((num & (1 << i)) != 0){
                ans = (int)(((long long)ans * temp) % MOD);
            }
            temp = (int)(((long long)temp * temp) % MOD);
        }
        return ans;
    }
    int cuttingBamboo(int bamboo_len) {
        if(bamboo_len == 2){
            return 1;
        }
        if(bamboo_len == 3){
            return 2;
        }
        int tail = bamboo_len % 3 == 0 ? 1 : (bamboo_len % 3 == 1 ? 4 : 2);
        int num = tail == 1 ? bamboo_len / 3 : (tail == 4 ? bamboo_len / 3 - 1 : bamboo_len / 3);
        return (int)(((long long)power(3, num) * tail) % MOD);
    }
};

题目二

分成k份的最大乘积

一个数字n一定要分成k份,得到的乘积尽量大是多少。数字n和k,可能非常大,到达10^12规模。结果可能更大,所以返回结果对1000000007取模。

来自真实大厂笔试,没有在线测试。

分析:乘积尽量大即k份尽可能相等,所以先将n除以k得到每一份的基础值,然后得到n模k的值即有多少基础值再加上1,相乘即可得到答案。代码如下。

class Solution {
public:
    int MOD = 1000000007;
    long long power(long long number, long long num){
        long long ans = 1;
        long long temp = number;
        for(int i = 0;i < 64;++i){
            if((num & (1 << i)) != 0){
                ans = (ans * temp) % MOD;
            }
            temp = (temp * temp) % MOD;
        }
        return ans;
    }
    int maxValue(long long n, long long k) {
        long long a = n / k;
        long long b = n % k;
        return (int)((power(a, k-b) * power(a+1, b)) % MOD);
    }
};

题目三

会议必须独占时间段的最大会议数量

给定若干会议的开始、结束时间。你参加某个会议的期间,不能参加其他会议。返回你能参加的最大会议数量。

来自真实大厂笔试,没有在线测试。

分析:以会议的结束时间从小到大进行排序,对于当前时间如果小于等于当前会议的开始时间则代表可以参加,时间更新为当前会议的结束时间,遍历所有会议即可得到答案。代码如下。

class Solution {
public:
    int maxMeetingNum(vector<vector<int>>& meeting){
        int ans = 0;
        int length = meeting.size();
        sort(meeting.begin(), meeting.end(), [](vector<int>& v1, vector<int>& v2){
            return v1[1] < v2[1];
        });
        int cur = -1;
        for(int i = 0;i < length;++i){
            if(cur <= meeting[i][0]){
                ++ans;
                cur = meeting[i][1];
            }
        }
        return ans;
    }
};

题目四

测试链接:1353. 最多可以参加的会议数目 - 力扣(LeetCode)

分析:首先按照开始时间进行排序,然后用一个小根堆维护结束时间,遍历会议的时候,对于当前时间可以解锁的会议的结束时间进入小根堆,选择可以解锁的会议中结束时间最小的会议进行参加。遍历所有天数即可得到答案。代码如下。

class Solution {
public:
    int maxEvents(vector<vector<int>>& events) {
        int length = events.size();
        sort(events.begin(), events.end(), [](vector<int>& v1, vector<int>& v2){
            return v1[0] < v2[0];
        });
        auto cmp = [](int& a, int& b){
            return a > b;
        };
        priority_queue<int, vector<int>, decltype(cmp)> p(cmp);
        int ans = 0;
        int index = 0;
        for(int day = 1;day <= 100000;++day){
            while (!p.empty() && day > p.top())
            {
                p.pop();
            }
            while (index < length && day >= events[index][0] && day <= events[index][1])
            {
                p.push(events[index][1]);
                ++index;
            }
            if(!p.empty()){
                ++ans;
                p.pop();
            }
        }
        return ans;
    }
};

题目五

测试链接:502. IPO - 力扣(LeetCode)

分析:对最小资本从小到大进行排序,用一个大根堆维护纯利润。遍历每一次选择项目的机会,对于当前资本可以解锁的项目的纯利润进入大根堆,选择当前纯利润最大的项目进行投资,将纯利润加入当前资本进行下一次的选择。遍历完即可得到答案。代码如下。

class Solution {
public:
    struct project
    {
        int profit;
        int capital;
    };
    int findMaximizedCapital(int k, int w, vector<int>& profits, vector<int>& capital) {
        int length = profits.size();
        vector<project> pro;
        pro.reserve(length);
        for(int i = 0;i < length;++i){
            project temp;
            temp.profit = profits[i];
            temp.capital = capital[i];
            pro.push_back(temp);
        }
        sort(pro.begin(), pro.end(), [](project& p1, project& p2){
            return p1.capital < p2.capital;
        });
        auto cmp = [](int& a, int& b){
            return a < b;
        };
        priority_queue<int, vector<int>, decltype(cmp)> p(cmp);
        for(int i = 0, index = 0;i < k;++i){
            while (index < length && pro[index].capital <= w)
            {
                p.push(pro[index].profit);
                ++index;
            }
            if(!p.empty()){
                w += p.top();
                p.pop();
            }
        }
        return w;
    }
};

题目六

加入差值绝对值直到长度固定

给定一个非负数组arr,计算任何两个数差值的绝对值。如果arr中没有,都要加入到arr里,但是只加一份。然后新的arr,继续计算任何两个数差值的绝对值,如果arr中没有,都要加入到arr里,但是只加一份。一直到arr大小固定,返回arr最终的长度。

来自真实大厂笔试,没有在线测试。

分析:观察可得这个数组中的所有数字是原数组除0之外所有数的最大公约数到原数组中的最大值,每一个数都是最大公约数的倍数。所以思路是求得最大公约数,得到基础个数,然后加上词频统计中个数不为1的数的剩余个数。对于是否有0的情况,如果原数组中有0,则加上原数组中0的个数;如果原数组中没0则取决于最大词频数,如果最大词频数不超过1,则没有零,超过1则加上一个0。代码如下。

class Solution {
public:
    int get_gcd(int a, int b){
        return b == 0 ? a : get_gcd(b, a % b);
    }
    int getLen(vector<int> arr){
        int gcd = 0;
        int maxValue = 0;
        int length = arr.size();
        for(int i = 0;i < length;++i){
            if(arr[i] != 0){
                gcd = arr[i];
            }
            maxValue = max(maxValue, arr[i]);
        }
        if(gcd == 0){
            return length;
        }
        map<int, int> table;
        map<int, int>::iterator pos;
        int maxCnt = 1;
        for(int i = 0;i < length;++i){
            if(arr[i] != 0){
                gcd = get_gcd(gcd, arr[i]);
            }
            pos = table.find(arr[i]);
            if(pos != table.end()){
                ++((*pos).second);
                maxCnt = max(maxCnt, (*pos).second);
            }else{
                table.insert(pair<int, int>(arr[i], 1));
            }
        }
        int ans = maxValue / gcd;
        for(int i = 0;i < length;++i){
            if(arr[i] != 0){
                pos = table.find(arr[i]);
                ans += ((*pos).second - 1);
            }
        }
        pos = table.find(0);
        ans += (pos == table.end() ? (maxCnt > 1 ? 1 : 0) : (*pos).second);
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

还有糕手

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

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

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

打赏作者

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

抵扣说明:

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

余额充值