代码随想录算法训练营第二十八天

news2024/11/25 4:34:05

题目:134. 加油站

暴力方法

暴力的方法很明显就是O(n^2)的,遍历每一个加油站为起点的情况,模拟一圈。

如果跑了一圈,中途没有断油,而且最后油量大于等于0,说明这个起点是ok的。

暴力的方法思路比较简单,但代码写起来也不是很容易,关键是要模拟跑一圈的过程。

for循环适合模拟从头到尾的遍历,而while循环适合模拟环形遍历,要善于使用while!

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        for (int i = 0; i < cost.size(); i++) {
            int rest = gas[i] - cost[i]; // 记录剩余油量
            int index = (i + 1) % cost.size();
            while (rest > 0 && index != i) { // 模拟以i为起点行驶一圈(如果有rest==0,那么答案就不唯一了)
                rest += gas[index] - cost[index];
                index = (index + 1) % cost.size(); // 这里的index回到起点很有技巧
            }
            // 如果以i为起点跑一圈,剩余油量>=0,返回该起始位置
            if (rest >= 0 && index == i) return i;
        }
        return -1;
    }
};

首先如果总油量减去总消耗大于等于零那么一定可以跑完一圈,说明 各个站点的加油站 剩油量rest[i]相加一定是大于等于零的。

每个加油站的剩余量rest[i]为gas[i] - cost[i]。

i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。

那么局部最优:当前累加rest[i]的和curSum一旦小于0,起始位置至少要是i+1,因为从i之前开始一定不行。全局最优:找到可以跑一圈的起始位置

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 < gas.size(); i++) {
            curSum += gas[i] - cost[i];
            totalSum += gas[i] - cost[i];
            if (curSum < 0) {   // 当前累加rest[i]和 curSum一旦小于0
                start = i + 1;  // 起始位置更新为i+1
                curSum = 0;     // curSum从0开始
            }
        }
        if (totalSum < 0) return -1; // 说明怎么走都不可能跑一圈了
        return start;
    }
};

题目:135. 分发糖果

这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼

先确定右边评分大于左边的情况(也就是从前向后遍历)

此时局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果

如果ratings[i] > ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个,所以贪心:candyVec[i] = candyVec[i - 1] + 1

代码如下:

// 从前向后
for (int i = 1; i < ratings.size(); i++) {
    if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
}

再确定左孩子大于右孩子的情况(从后向前遍历)

采用了两次贪心的策略:

  • 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
  • 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。

整体代码如下:

class Solution {
public:
    int candy(vector<int>& ratings) {
        int count = ratings.size();
        int sum = 0;
        vector<int> candys(ratings.size(), 1);
        for (int i = 1; i < ratings.size(); i++) {  
            if (ratings[i] > ratings[i - 1]) candys[i] = candys[i - 1] + 1;
        }
        for (int i = ratings.size() - 2; i >= 0; i--) {  
            if (ratings[i] > ratings[i + 1]) {
                if (candys[i] > candys[i + 1]) continue;
                candys[i] = candys[i + 1] + 1;
            }
        }
        for (int num : candys) {
            sum += num;
        }
        return sum;
    }
};

题目:860. 柠檬水找零

这道题目刚一看,可能会有点懵,这要怎么找零才能保证完成全部账单的找零呢?

但仔细一琢磨就会发现,可供我们做判断的空间非常少!

只需要维护三种金额的数量,5,10和20。

有如下三种情况:

  • 情况一:账单是5,直接收下。
  • 情况二:账单是10,消耗一个5,增加一个10
  • 情况三:账单是20,优先消耗一个10和一个5,如果不够,再消耗三个5

此时大家就发现 情况一,情况二,都是固定策略,都不用我们来做分析了,而唯一不确定的其实在情况三。

而情况三逻辑也不复杂甚至感觉纯模拟就可以了,其实情况三这里是有贪心的。

账单是20的情况,为什么要优先消耗一个10和一个5呢?

因为美元10只能给账单20找零,而美元5可以给账单10和账单20找零,美元5更万能!

所以局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。

局部最优可以推出全局最优,并找不出反例,那么就试试贪心算法!

C++代码如下:

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five = 0, ten = 0, twenty = 0;
        for (int bill : bills) {
            // 情况一
            if (bill == 5) five++;
            // 情况二
            if (bill == 10) {
                if (five <= 0) return false;
                ten++;
                five--;
            }
            // 情况三
            if (bill == 20) {
                // 优先消耗10美元,因为5美元的找零用处更大,能多留着就多留着
                if (five > 0 && ten > 0) {
                    five--;
                    ten--;
                    twenty++; // 其实这行代码可以删了,因为记录20已经没有意义了,不会用20来找零
                } else if (five >= 3) {
                    five -= 3;
                    twenty++; // 同理,这行代码也可以删了
                } else return false;
            }
        }
        return true;
    }
};

// my code
class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        vector<int> money(21,0);
        int change = 0;
        for (int i = 0; i < bills.size(); i++) {
            money[bills[i]]++;
            change = bills[i] - 5;
            if (change == 0) continue;
            if (change == 5) {
                if (money[5] != 0) money[5]--;
                else return false;
            }
            if (change == 15) {
                if (money[5] != 0 && money[10] != 0) {
                    money[5]--;
                    money[10]--;
                }
                else if (money[5] >= 3) {
                    money[5] -= 3;
                }
                else return false;
            }
            
        }
        return true;

    }
};

题目:406. 根据身高重建队列

本体有点难度可以看视频理解一下  原来看题目也没看明白要干啥

本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后再按照另一个维度重新排列。

其实如果大家认真做了135. 分发糖果 (opens new window),就会发现和此题有点点的像。

在135. 分发糖果 (opens new window)我就强调过一次,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。

如果两个维度一起考虑一定会顾此失彼

对于本题相信大家困惑的点是先确定k还是先确定h呢,也就是究竟先按h排序呢,还是先按照k排序呢?

如果按照k来从小到大排序,排完之后,会发现k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。

那么按照身高h来排序呢,身高一定是从大到小排(身高相同的话则k小的站前面),让高个子在前面。

此时我们可以确定一个维度了,就是身高,前面的节点一定都比本节点高!

那么只需要按照k为下标重新插入队列就可以了,为什么呢?

以图中{5,2} 为例:

按照身高排序之后,优先按身高高的people的k来插入,后序插入节点也不会影响前面已经插入的节点,最终按照k的规则完成了队列。

所以在按照身高从大到小排序后:

局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性

全局最优:最后都做完插入操作,整个队列满足题目队列属性

局部最优可推出全局最优,找不出反例,那就试试贪心。

整个插入过程如下:

排序完的people: [[7,0], [7,1], [6,1], [5,0], [5,2],[4,4]]

插入的过程:

  • 插入[7,0]:[[7,0]]
  • 插入[7,1]:[[7,0],[7,1]]
  • 插入[6,1]:[[7,0],[6,1],[7,1]]
  • 插入[5,0]:[[5,0],[7,0],[6,1],[7,1]]
  • 插入[5,2]:[[5,0],[7,0],[5,2],[6,1],[7,1]]
  • 插入[4,4]:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]

此时就按照题目的要求完成了重新排列。

class Solution {
public:
    static bool cmp(vector<int>& a, 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>> queue; 
        for (int i = 0; i < people.size(); i++) {
            int position = people[i][1];
            queue.insert(queue.begin() + position,  people[i]); // 这里不在原来people上修改的原因是 插入之后索引都会发生变化 如果继续遍历的话会重复 并且 直接在queue上赋值不需要考虑这么多直接添加即可
        }

        return queue;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1846068.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NGINX_十六 nginx 错误页面配置

十六 nginx 错误页面配置 nginx错误页面包括404 403 500 502 503 504等页面&#xff0c;只需要在server中增加以下配置即可&#xff1a; #error_page 404 403 500 502 503 504 /404.html;location /404.html {root /usr/local/nginx/html;}注意&#xff1a; /usr/local…

PostgreSQL性能优化之分区表 #PG培训

在处理大规模数据时&#xff0c;PostgreSQL的性能优化是一个非常重要的话题&#xff0c;其中分区表&#xff08;Partitioned Tables&#xff09;是提高查询和数据管理效率的重要手段。本文将详细介绍PostgreSQL分区表的概念、优势、创建与管理方法以及一些常见的优化策略。 #P…

qml:一个基础的界面设计

文章目录 文章说明效果图重要代码说明组件矩形卡片窗口最大化后组件全部居中菜单栏Repeater实现重复8行图片加载直接加载图片文本转图片FluentUI中可供选择的图标 文章说明 qt6.5.3 qml写的一个界面配置设计软件&#xff0c;目前不含任何c代码&#xff0c;纯qml。windoms风格的…

【Java】已解决java.net.HttpRetryException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例 已解决java.net.HttpRetryException异常 在Java的网络编程中&#xff0c;尤其是使用Apache HttpClient或其他类似的HTTP客户端库时&#xff0c;可能会遇到java.net.HttpRetryException异常。这个…

华为200人园区网有线和无线

实验描述&#xff1a; 1 内网有有线业务、内部无线、外部无线三种业误。 2 内网服务器配置静态IP&#xff0c;网关192.168.108.1。 3 sW1和R1之间使用v1an200 192.168.200.9/30 互联。 4 R2向运营商申请企业宽带并获得了1个固定公网IP&#xff1a; 200.1.1.1 子网掩码 255.255.…

VMware虚拟机下载安装Windows Server 2016

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

Docker常用操作和命令

文章目录 1、卸载旧版本 2、yum安装Docker CE&#xff08;社区版&#xff09; 3、添加镜像加速器 4、docker --version 查看docker版本 5、docker info 或 docker system info 显示 Docker 系统的详细信息&#xff0c;包括容器、镜像、网络等 6、docker search 搜索镜像 …

MEMS环境传感器生产测试的挑战与未来趋势

微机电系统 (MEMS) 环境传感器无处不在&#xff0c;默默地支撑着我们日常生活中众多设备的功能。从智能手机和可穿戴设备到智能家居和工业自动化&#xff0c;这些微型产品可以测量温度、压力、湿度和大量其他环境参数。 由于环境监测需求不断增长以及空气质量严格法规的实施&am…

一站式家装服务管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;装修风格管理&#xff0c;主材管理&#xff0c;用户管理&#xff0c;基础数据管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;装修风格&#xff0…

极狐GitLab落户香港科学园并成功发布AI产品驭码CodeRider国际版

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

189.二叉树:将有序数组转换为二叉搜索树(力扣)

代码解决 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* Tre…

canvas绘制红绿灯路口(二)

系列文章 canvas绘制红绿灯路口&#xff08;一&#xff09; 无图不欢&#xff0c;先上图 优化项&#xff1a; 一&#xff1a;加入人行道红绿信号 二&#xff1a;加入专用车道标识&#xff08;无方向标识时采用专用车道标识&#xff09; 三&#xff1a;东南西北四项路口优化绘…

汇凯金业:现货黄金投资平仓策略有哪些

现货黄金作为全球投资者广泛关注与参与的财富增值途径&#xff0c;其双向交易制度为市场参与者在不同行情下提供了盈利的可能。然而&#xff0c;如何在波动的市场中把握最佳的平仓时机&#xff0c;从而最大化收益&#xff0c;是所有投资者心中的疑问。正确的平仓策略可以说是现…

【GD32F303红枫派使用手册】第二十节 SPI-SPI NAND FLASH读写实验

20.1 实验内容 通过本实验主要学习以下内容&#xff1a; SPI通信协议&#xff0c;参考19.2.1东方红开发板使用手册 GD32F303 SPI操作方式&#xff0c;参考19.2.2东方红开发板使用手册 NAND FLASH基本原理 SPI NAND介绍 使用GD32F303 SPI接口实现对GD5F1GQ5UEYIGY的读写…

深度学习 --- stanford cs231学习笔记四(训练神经网络的几个重要组成部分之一,激活函数)

训练神经网络的几个重要组成部分 一 1&#xff0c;激活函数&#xff08;activation functions&#xff09; 激活函数是神经网络之于线性分类器的最大进步&#xff0c;最大贡献&#xff0c;即&#xff0c;引入了非线性。这些非线性函数可以被分成两大类&#xff0c;饱和非线性函…

Nacos 2.x 系列【17】健康保护阈值

文章目录 1. 概述2. 案例演示2.1 设置阈值2.2 未触发2.3 触发 1. 概述 Nacos 支持通过配置健康保护阈值&#xff08;ProtectThreshold&#xff09;防止因过多实例故障&#xff0c;导致所有流量全部流入剩余实例&#xff0c;继而造成流量压力将剩余实例被压垮形成的雪崩效应。 …

神经网络模型的量化简介(工程版)

1.量化简介 模型量化&#xff08;Model Quantization&#xff09;是深度学习中一种优化技术&#xff0c;旨在减少模型的计算和存储需求&#xff0c;同时尽量保持模型的性能。具体来说&#xff0c;模型量化通过将模型的权重和激活值从高精度&#xff08;通常是32位浮点数&#…

昇思25天学习打卡营第3天 | 数据集

内容介绍&#xff1a;数据是深度学习的基础&#xff0c;高质量的数据输入将在整个深度神经网络中起到积极作用。MindSpore提供基于Pipeline的数据引擎&#xff0c;通过数据集&#xff08;Dataset&#xff09;实现高效的数据预处理。其中Dataset是Pipeline的起始&#xff0c;用于…

一些使用注意(XPTable控件使用说明十)

当XPTABLE放到线程中&#xff0c;列数据很多&#xff0c;不出现滚动条的解决代码&#xff1a; /// 这里神奇的代码&#xff0c;解决线程中XPTABLE 不出滚动条问题 , 执行UI相关的操作this.Invoke(new Action(() >{ // 列头&#xff0c;一行空的&#xff0c;这里列头设置…

AI全栈之logo生成:执文,描摹,妙哉~

前言 前几日体验了国产的AI-Agents产品coze 它是一种能够自主执行任务、与环境进行交互并根据所获取的信息做出决策和采取行动的软件程序 并且可以自己去创建属于自己的AIBot&#xff0c;还是很有意思的&#xff0c;大家可以去体验体验 在体验过程中&#xff0c;我发现在创…