首页 > 编程语言 >「代码随想录算法训练营」第二十五天 | 贪心算法 part3

「代码随想录算法训练营」第二十五天 | 贪心算法 part3

时间:2024-08-01 20:50:41浏览次数:15  
标签:vector return people int 随想录 算法 part3 five https

134. 加油站

题目链接:https://leetcode.cn/problems/gas-station/
题目难度:中等
文章讲解:https://programmercarl.com/0134.加油站.html
视频讲解:https://www.bilibili.com/video/BV1jA411r7WX
题目状态:没有思路,学习题解

思路一:全局最优解

首先将所有路径的加油量和耗油量加一起,看是否大于0,若小于0,表示整体的加油量小于耗油量,不可能跑完全程,直接返回-1;若大于0,看其到每一站存储的油量最小值是否大于等于0,若是,则表示其在每一站都是可以跑完的,直接返回0(表示从0开始出发可以完成全程);若并不是这样的,则反向加出发点,看其什么时候的最小值不会为负数,此时就是出发点的位置。

代码一:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int curSum = 0;
        int min = INT_MAX;
        for(int i = 0; i < gas.size(); ++i) {
            int rest = gas[i] - cost[i];
            curSum += rest;
            min = std::min(min, curSum);
        }
        if(curSum < 0) return -1;
        if(min >= 0) return 0;

        for(int i = gas.size() - 1; i >= 0; --i) {
            int rest = gas[i] - cost[i];
            min += rest;
            if(min >= 0) return i;
        }
        return -1;
    }
};

思路二:贪心算法

局部最优,首先当所有路径的油差之和小于0,直接返回-1,其不可能跑完全程;再次,若从A点到B点的油差和小于0,要从B点的下一点重新记录,因为A到B之间无论从哪一点开始,都跑不完,最后返回合适的位置。

代码:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int curSum = 0;
        int totalSum = 0;
        int start = 0;
        for(int i = 0; i < cost.size(); ++i) {
            curSum += gas[i] - cost[i];
            totalSum += gas[i] - cost[i];
            if(curSum < 0) {
                start = i + 1;
                curSum = 0;
            }
        }
        if(totalSum < 0) return -1;
        return start;
    }
};

135. 分发糖果

题目链接:https://leetcode.cn/problems/candy/
题目难度:困难
文章讲解:https://programmercarl.com/0135.分发糖果.html
视频讲解:https://www.bilibili.com/video/BV1ev4y1r7wN
题目状态:好难,要长脑子了

思路:

首先创建一个数组,存储每个孩子手里的糖。

  • 首先,每个孩子手里都要有一颗糖。
  • 从左向右,判断右边孩子分数是否要大于左边孩子,若大于,就把右边孩子手里加一颗糖。
  • 从右向左,判断左边孩子的分数是否大于右边孩子,若大于,则判断左边孩子手里的糖是否已经大于右边孩子了,若不大于,则将左边孩子手里的糖加到比右边孩子大。

代码:

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<int> candyVal(ratings.size(), 1);
        for(int i = 1; i < ratings.size(); ++i) {
            if(ratings[i] > ratings[i - 1]) candyVal[i] = candyVal[i - 1] + 1;
        }
        for(int i = ratings.size() - 2; i >= 0; --i) {
            if(ratings[i] > ratings[i + 1]) candyVal[i] = max(candyVal[i], candyVal[i + 1] + 1);
        }
        int res = 0;
        for(auto &val : candyVal) res += val;
        return res;
    }
};

860. 柠檬水找零

题目链接:https://leetcode.cn/problems/lemonade-change/
题目难度:简单
文章讲解:https://programmercarl.com/0860.柠檬水找零.html
视频讲解:https://www.bilibili.com/video/BV12x4y1j7DD
题目状态:没绕过来,看完题解豁然开朗

思路:

维护五块钱和十块钱的个数five和ten

  • 当给5元时,five++;
  • 当给10元时,five--;
  • 当给20元时,要么ten--和five--,要么five-3。

代码:

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five = 0, ten = 0;
        for(int i = 0; i < bills.size(); ++i) {
            if(bills[i] == 5) five++;
            if(bills[i] == 10) {
                if(five <= 0) return false;
                five--;
                ten++;
            }
            if(bills[i] == 20) {
                if(five > 0 && ten > 0) {
                    five--;
                    ten--;
                } else if(five >= 3) {
                    five -= 3;
                } else {
                    return false;
                }
            }
        }
        return true;
    }
};

406. 根据身高重建队列

题目链接:https://leetcode.cn/problems/queue-reconstruction-by-height/
题目难度:中等
文章讲解:https://programmercarl.com/0406.根据身高重建队列.html
视频讲解:https://www.bilibili.com/video/BV1EA411675Y
题目状态:继续学习题解...

思路:

首先对整个数组进行排序,排序规则是比较身高,最高的排在前面,若身高相同,比较前方人数,人数低的排在前面。
之后开始插入返回数组,按照排序后的数组依次插入,插入的位置是自己的前方人数,下图更容易理解插入的过程。

代码实现:

class Solution {
public:
    static bool cmp(const vector<int> &a, const vector<int> &b) {
        if(a[0] == b[0]) return a[1] < b[1];
        return a[0] > b[0];
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort(people.begin(), people.end(), cmp);
        vector<vector<int>> que;
        for(int i = 0; i < people.size(); ++i) {
            int position = people[i][1];
            que.insert(que.begin() + position, people[i]);
        }
        return que;
    }
};

链表代码:(性能更好)

class Solution {
public:
    // 身高从大到小排(身高相同k小的站前面)
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        if (a[0] == b[0]) return a[1] < b[1];
        return a[0] > b[0];
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort (people.begin(), people.end(), cmp);
        list<vector<int>> que; // list底层是链表实现,插入效率比vector高的多
        for (int i = 0; i < people.size(); i++) {
            int position = people[i][1]; // 插入到下标为position的位置
            std::list<vector<int>>::iterator it = que.begin();
            while (position--) { // 寻找在插入位置
                it++;
            }
            que.insert(it, people[i]);
        }
        return vector<vector<int>>(que.begin(), que.end());
    }
};

标签:vector,return,people,int,随想录,算法,part3,five,https
From: https://www.cnblogs.com/frontpen/p/18337492

相关文章

  • 分词算法:自然语言处理中的关键技术
    分词算法:自然语言处理中的关键技术大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!分词(Tokenization)是自然语言处理(NLP)中的一项基础技术,旨在将文本拆分成有意义的单位,如单词或词组。分词在文本分析、信息检索、机器翻译等应用中发挥着重要作用。本文将介......
  • 代码随想录Day2
    209.长度最小的子数组给定一个含有n个正整数的数组和一个正整数target。找出该数组中满足其总和大于等于target的长度最小的子数组$[nums_l,nums_{l+1},...,nums_{r-1},nums_r]$,并返回其长度。如果不存在符合条件的子数组,返回0。示例1:输入:target=7,nums=......
  • JVM—垃圾收集算法和HotSpot算法实现细节
    1、分代回收策略分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。分代垃圾回收采用分治的思想,进行代的划分,把不同生命周期放在不同代上,不同代采用最适合它的垃圾回收方法进行回收。......
  • 冒泡排序的具体思想和算法实现以及改进
    冒泡排序——稳定算法从小到大排序:0~length-1对比a[0]和a[1],如果前一个大于后一个,交换位置。对比a[1]和a[2],如果前一个大于后一个,交换位置。对比a[2]和a[3],如果前一个大于后一个,交换位置。...对比a[length-2]和a[length-1],如果前一个大于后一个,交换位置。第一轮结果下......
  • 【算法】浅析线性规划算法【附完整示例】
    线性规划算法:优化资源配置,提升经济效益1.引言在现代社会,资源优化配置是提高经济效益的关键。线性规划算法作为一种优化工具,广泛应用于经济学、工程学、管理学等领域。本文将带你了解线性规划算法的原理、使用方法及其在实际应用中的意义,并通过代码示例和图示帮助大家更好......
  • 选择插入排序改进思路加算法实现
    首先默认第一个元素是已排序的,剩下元素是待排序的,从第二个元素开始遍历取出待排序区域的第一个元素element和已排序区域的最后一个元素a[j]往前开始比较大小若待排元素大于等于最后一个元素则直接跳出循环将待排元素赋值给a[j+1]若待排元素小于最后一个元素将最后一个元......
  • 折半插入排序算法思想及代码实现
    折半插入排序(BinaryInsertionSort)是插入排序算法的一种优化版本。插入排序的基本思想是将一个记录插入到已经排序好的有序表中,从而得到一个新的、记录数增加1的有序表。传统的插入排序在寻找插入位置时,采用的是顺序比较的方式,即逐个与有序表中的元素进行比较,直到找到比待插入......
  • 数据结构与算法 - 递归
    一、递归1. 概述定义:在计算机科学中,递归是一种解决计算问题的方法,其中解决方案取决于同一类问题的更小子集。比如单链表递归遍历的例子:voidf(Nodenode){if(node==null){return;}println("before:"+node.value)f(node.next);pr......
  • 数据结构与算法 - 链表
    一、链表1.概述定义:在计算机科学中,链表是数据元素的线性集合,其每个元素都指向下一个元素,元素存储上并不连续。可以分类为:单向链表,每个元素只知道其下一个元素是谁双向链表,每个元素直到其上一个元素和下一个元素循环链表,通常的链表尾节点tail指向的都是null,而循环链表......
  • OpenSSH秘钥指纹图像生成算法
    OpenSSH秘钥指纹图像生成算法使用SSH秘钥生成时产生疑惑,它的randomartimage是如何生成的?下面进行了探索和研究引入生成位数为4096位的rsa公私钥ssh-keygen-trsa-b4096Generatingpublic/privatersakeypair.Enterfileinwhichtosavethekey(/root/.s......