侵权投诉

代码中是数学图像解法和贪心解法

新材料在线 2021-09-01 14:14 次阅读

今天讲一个贪心的老司机的故事,就是力扣第 134 题「加油站」:

5fda8eb2-fbbe-11eb-9bcf-12bb97331649.jpg

题目应该不难理解,就是每到达一个站点i,可以加gas[i]升油,但离开站点i需要消耗cost[i]升油,问你从哪个站点出发,可以兜一圈回来。

要说暴力解法,肯定很容易想到,用一个 for 循环遍历所有站点,假设为起点,然后再套一层 for 循环,判断一下是否能够转一圈回到起点:

int n = gas.length;

for (int start = 0; start 《 n; start++) {

for (int step = 0; step 《 n; step++) {

int i = (start + step) % n;

tank += gas[i];

tank -= cost[i];

// 判断油箱中的油是否耗尽

}

}

很明显时间复杂度是 O(N^2),这么简单粗暴的解法一定不是最优的,我们试图分析一下是否有优化的余地。

暴力解法是否有重复计算的部分?是否可以抽象出「状态」,是否对同一个「状态」重复计算了多次?

我们前文 动态规划详解 说过,变化的量就是「状态」。那么观察这个暴力穷举的过程,变化的量有两个,分别是「起点」和「当前油箱的油量」,但这两个状态的组合肯定有不下 O(N^2) 种,显然没有任何优化的空间。

所以说这道题肯定不是通过简单的剪枝来优化暴力解法的效率,而是需要我们发现一些隐藏较深的规律,从而减少一些冗余的计算。

下面我们介绍两种方法巧解这道题,分别是数学图像解法和贪心解法。

图像解法

汽车进入站点i可以加gas[i]的油,离开站点会损耗cost[i]的油,那么可以把站点和与其相连的路看做一个整体,将gas[i] - cost[i]作为经过站点i的油量变化值:

这样,题目描述的场景就被抽象成了一个环形数组,数组中的第i个元素就是gas[i] - cost[i]。

有了这个环形数组,我们需要判断这个环形数组中是否能够找到一个起点start,使得从这个起点开始的累加和一直大于等于 0。

如何判断是否存在这样一个起点start?又如何计算这个起点start的值呢?

我们不妨就把 0 作为起点,计算累加和的代码非常简单:

int n = gas.length, sum = 0;

for (int i = 0; i 《 n; i++) {

// 计算累加和

sum += gas[i] - cost[i];

}

sum就相当于是油箱中油量的变化,上述代码中sum的变化过程可能是这样的:

显然,上图将 0 作为起点肯定是不行的,因为sum在变化的过程中小于 0 了,不符合我们「累加和一直大于等于 0」的要求。

那如果 0 不能作为起点,谁可以作为起点呢?

看图说话,图像的最低点最有可能可以作为起点:

如果把这个「最低点」作为起点,就是说将这个点作为坐标轴原点,就相当于把图像「最大限度」向上平移了。

再加上这个数组是环形数组,最低点左侧的图像可以接到图像的最右侧:

这样,整个图像都保持在 x 轴以上,所以这个最低点 4,就是题目要求我们找的起点。

不过,经过平移后图像一定全部在 x 轴以上吗?不一定,因为还有无解的情况:

如果sum(gas[。..]) 《 sum(cost[。..]),总油量小于总的消耗,那肯定是没办法环游所有站点的。

综上,我们就可以写出代码:

int canCompleteCircuit(int[] gas, int[] cost) {

int n = gas.length;

// 相当于图像中的坐标点和最低点

int sum = 0, minSum = Integer.MAX_VALUE;

int start = 0;

for (int i = 0; i 《 n; i++) {

sum += gas[i] - cost[i];

if (sum 《 minSum) {

// 经过第 i 个站点后,使 sum 到达新低

// 所以站点 i + 1 就是最低点(起点)

start = i + 1;

minSum = sum;

}

}

if (sum 《 0) {

// 总油量小于总的消耗,无解

return -1;

}

// 环形数组特性

return start == n ? 0 : start;

}

以上是观察函数图像得出的解法,时间复杂度为 O(N),比暴力解法的效率高很多。

下面我们介绍一种使用贪心思路写出的解法,和上面这个解法比较相似,不过分析过程不尽相同。

贪心解法

用贪心思路解决这道题的关键在于以下这个结论:

如果选择站点i作为起点「恰好」无法走到站点j,那么i和j中间的任意站点k都不可能作为起点。

比如说,如果从站点1出发,走到站点5时油箱中的油量「恰好」减到了负数,那么说明站点1「恰好」无法到达站点5;那么你从站点2,3,4任意一个站点出发都无法到达5,因为到达站点5时油箱的油量也必然被减到负数。

如何证明这个结论?

假设tank记录当前油箱中的油量,如果从站点i出发(tank = 0),走到j时恰好出现tank 《 0的情况,那说明走到i, j之间的任意站点k时都满足tank 》 0,对吧。

如果把k作为起点的话,相当于在站点k时tank = 0,那走到j时必然有tank 《 0,也就是说k肯定不能是起点。

拜托,从i出发走到k好歹tank 》 0,都无法达到j,现在你还让tank = 0了,那更不可能走到j了对吧。

综上,这个结论就被证明了。

回想一下我们开头说的暴力解法是怎么做的?

如果我发现从i出发无法走到j,那么显然i不可能是起点。

现在,我们发现了一个新规律,可以推导出什么?

如果我发现从i出发无法走到j,那么i以及i, j之间的所有站点都不可能作为起点。

看到冗余计算了吗?看到优化的点了吗?

这就是贪心思路的本质,如果找不到重复计算,那就通过问题中一些隐藏较深的规律,来减少冗余计算。

根据这个结论,就可以写出如下代码:

int canCompleteCircuit(int[] gas, int[] cost) {

int n = gas.length;

int sum = 0;

for (int i = 0; i 《 n; i++) {

sum += gas[i] - cost[i];

}

if (sum 《 0) {

// 总油量小于总的消耗,无解

return -1;

}

// 记录油箱中的油量

int tank = 0;

// 记录起点

int start = 0;

for (int i = 0; i 《 n; i++) {

tank += gas[i] - cost[i];

if (tank 《 0) {

// 无法从 start 走到 i

// 所以站点 i + 1 应该是起点

tank = 0;

start = i + 1;

}

}

return start == n ? 0 : start;

}

这个解法的时间复杂度也是 O(N),和之前图像法的解题思路有所不同,但代码非常类似。

其实,你可以把这个解法的思路结合图像来思考,可以发现它们本质上是一样的,只是理解方式不同而已。

对于这种贪心算法,没有特别套路化的思维框架,主要还是靠多做题多思考,将题目的场景进行抽象的联想,找出隐藏其中的规律,从而减少计算量,进行效率优化。

好了,这道题就讲到这里,希望对你拓宽思路有帮助。

责任编辑:haq

原文标题:当老司机学会了贪心算法

文章出处:【微信号:xincailiaozaixian,微信公众号:新材料在线】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
分享:

评论

相关推荐

华为创新性地推出“5G新通话”解决方案
在北京国家会议中心举行的2021年中国国际信息通信展览会上,由中国通信企业协会发起的“ICT中国(2....
的头像 华为云核心网 发表于 10-15 17:27 298次 阅读
华为发布SD-WAN逐包负载分担方案 提升带宽利用率
华为SD-WAN逐包负载分担方案,提升带宽利用率至90%,让您的广域网络更加高效。
的头像 华为产品资料 发表于 10-15 16:44 221次 阅读
教大家如何减小微量水分策略的结果中的误差
微量水分测定仪采用卡尔——菲休库仑法,对不同物质进行微量水分测定,是一种可靠的方法,微量水分测定仪成....
发表于 10-15 16:39 19次 阅读
详解工业液体密度测试步骤
业液体通常需要进行液体密度的测试来加以控制品质。行业内的测试仪就是搏仕的液体密度测试仪了。下面将演示....
发表于 10-15 16:27 16次 阅读
音频电路原理(双音频解码电子电路/TDA2822双声道功放电路/音频放大处理电路)
双音多频信号解码电路是目前在按键电话(固定电话、移动电话)、程控交换机及无线通信设备中广泛应用的集成....
发表于 10-15 16:08 501次 阅读
音频电路原理(双音频解码电子电路/TDA2822双声道功放电路/音频放大处理电路)
浅析压敏(热敏)陶瓷粉末水分测试实验报告
厦门搏仕检测设备有限公司  www.lboshi.cn 18959266236 陶瓷粉末水分含量介绍....
发表于 10-15 15:57 15次 阅读
探究塑料颗粒密度测试仪实验报告
密度计品牌:搏仕 型号:BOS-300系列 测试品:塑料颗粒 塑料种类纷多,密度值各不相同,如PP料....
发表于 10-15 15:47 15次 阅读
塑料水分测定仪测试经验总结
厦门搏仕检测设备有限公司  www.lboshi.cn 18959266236 塑料水分测定仪针对不....
发表于 10-15 15:38 17次 阅读
剖析汽车塑料零配件水分测试仪实验
水分仪品牌:搏仕     型号:BOS-180A系列     测试品:汽车塑料片 塑料的含水量是影响....
发表于 10-15 15:23 12次 阅读
四维图新构建现实世界三维还原的能力赋能智能网联应用
实时构建现实世界三维还原,将物理世界数字化,是四维图新近20年来一直努力的方向,通过对物理世界的人、....
的头像 四维图新NavInfo 发表于 10-15 14:40 845次 阅读
完整关注跨模态转换器网络
舞蹈是几乎所有文化中的一种通用语言,也是如今许多人在当代媒体平台上表达自己的一种方式。跳舞的能力(组....
的头像 TensorFlow 发表于 10-15 10:25 112次 阅读
PCB的设计、打板和焊接
最近MicroPython在嵌入式系统领域受到大家的喜爱,攻城狮们都纷纷研究起来,就连我们Funpa....
的头像 电子森林 发表于 10-15 10:04 134次 阅读
MySQL缓冲区设计介绍
1. Buffer 与 cache 的区别? Bbuffer 与 Cache 非常类似,因为它们都用....
的头像 数据分析与开发 发表于 10-15 09:50 99次 阅读
pandasgui安装与简单使用
pandasgui安装与简单使用 根据作者的介绍,pandasgui是用于分析 Pandas Dat....
的头像 数据分析与开发 发表于 10-15 09:46 96次 阅读
交换模式与路由模式有哪些异同点
交换模式是什么?路由模式又是什么? 交换模式与路由模式有哪些异同点? ...
发表于 10-15 09:35 0次 阅读
采集与分析用户行为数据的意义
本文属于用户行为数据领域入门级别文章,适合对用户行为数据略知一二但是对这个主题非常感兴趣的同学。 1....
的头像 数据分析与开发 发表于 10-15 09:32 126次 阅读
怎样去解决耳机的电流声问题
怎样去解决耳机的电流声问题? 怎样去解决archlinux开关机啪啪响的问题? ...
发表于 10-15 07:26 0次 阅读
怎样通过读取电流节点的方式去获取电流呢
怎样通过读取电流节点的方式去获取电流呢?其实验代码是怎样的?...
发表于 10-15 06:48 0次 阅读
JD-BQX7 七参数便携式气象站功能有哪些
七参数便携式气象站功能有哪些?在清凉谷旅游风景区的监测使用,满足风景区气象监测服务的需求,使得清凉谷....
发表于 10-14 16:29 34次 阅读
智慧电梯的运用能解决行业哪些需求
电梯作为与百姓生活最为密切相关的特种设备,直接关系人民群众生命和财产安全,关系经济发展大局和社会和谐....
发表于 10-14 16:28 23次 阅读
IBM利用AI 驱动帮助气候和数据科学家分析海量环境数据集
IBM (纽交所证券代码:IBM) 发布了一套环境智能应用软件,利用 AI 帮助企业做好准备并应对可....
的头像 IBM中国 发表于 10-14 16:01 730次 阅读
食品检测设备有哪些,其用途是什么
食品检测设备【恒美】有哪些,随着国家经济的大幅提高以及居民消费水平的普遍提高,休闲食品的食品种类与数....
发表于 10-14 10:43 24次 阅读
食品检测仪的工作原理及使用方法
食品检测仪【恒美 HM-G1200】的操作原理及方法。食品检测仪【恒美 HM-G1200】因其体积小....
发表于 10-14 10:29 19次 阅读
步进电机是如何实现正反转的
步进电机是如何实现正反转的?怎样去编写其代码?...
发表于 10-14 09:49 0次 阅读
PA_IK代码该如何去实现
PA_IK代码该如何去实现? PA_VMC算法的原理是什么?...
发表于 10-14 09:00 0次 阅读
STM32L151C8T6低功耗编程代码该如何去编写
STM32L151C8T6低功耗编程代码该如何去编写?
发表于 10-14 07:41 0次 阅读
怎样去定义一个结构体数组呢
数据结构的特点有哪些? 怎样去定义一个结构体数组呢? ...
发表于 10-14 07:25 0次 阅读
TableSQL API和Pyhton上相关的性能优化
一、简介 1.14 新版本原本规划有 35 个比较重要的新特性以及优化工作,目前已经有 26 个工作....
的头像 数据分析与开发 发表于 10-13 17:25 138次 阅读
能快速找到代码运行最慢部分的编程神器
天下武功,唯快不破。 编程也不例外,你的代码跑的快,你能快速找出代码慢的原因,你的码功就高。 今天分....
的头像 Linux爱好者 发表于 10-13 16:40 104次 阅读
胶水固含量测试注意事项
厦门搏仕检测设备有限公司  www.lboshi.cn 18959266236 1、无论是高粘性胶水....
发表于 10-13 16:16 32次 阅读
神经网络复杂性的基本下界
最近,人们对深度神经网络产生了极大的兴趣,因为它们在计算机视觉等领域取得了突破性的成果。 尽管如此,....
的头像 人工智能与大数据技术 发表于 10-13 15:40 162次 阅读
神经网络复杂性的基本下界
动态内存分配的注意事项及本质是什么
C语言中比较重要的就是指针,它可以用来链表操作,谈到链表,很多时候为此分配内存采用动态分配而不是静态....
的头像 C语言编程学习基地 发表于 10-13 15:37 222次 阅读
动态内存分配的注意事项及本质是什么
将FSoE部署到安全系统时面临的挑战
今年,瑞萨将高度关注Functional Safety over EtherCAT (FSoE) 解....
的头像 瑞萨电子 发表于 10-13 14:23 124次 阅读
浅谈商业智能BI给企业带来的价值
整体分析问题BI可以将企业信息化的数据孤岛整合起来,提供一个全局的视图,让决策者可以更加全面地看待问....
发表于 10-13 13:57 25次 阅读
IP知识百科之带你全面了解VPN技术
VPN是什么 VPN(Virtual Private Network)是依靠Internet服务提供....
的头像 华为产品资料 发表于 10-13 11:11 175次 阅读
红外遥控这么简单让我看看还有谁不会
平时我们经常会用到遥控器,那么现在遥控器也分很多种类,有使用红外通信的,也有使用蓝牙,无线的等,今天....
的头像 单片机匠人 发表于 10-13 11:06 249次 阅读
eBPF技术应用云原生网络实践系列之基于socket的service
背景介绍 Kubernetes 中的网络功能,主要包括 POD 网络,service 网络和网络策略....
的头像 Linux阅码场 发表于 10-13 10:54 204次 阅读
eBPF技术应用云原生网络实践系列之基于socket的service
汽车以太网数据通道的研究和发现
大家好!之前小编给大家做了两期汽车以太网的介绍,反响特别好,今天我们继续进行汽车以太网的探讨吧~ 由....
的头像 罗森伯格汽车电子 发表于 10-13 10:32 174次 阅读
汽车以太网数据通道的研究和发现
用Python实现3D地图教程
前言 本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题....
的头像 马哥Linux运维 发表于 10-13 10:09 158次 阅读
用Python实现3D地图教程
关于Python对交通路口的红绿灯进行颜色检测
转自 |   Python联盟 1.视频读取 首先把视频读取进来,因为我测试的视频是4k的所以我用r....
的头像 新机器视觉 发表于 10-13 09:32 216次 阅读
关于Python对交通路口的红绿灯进行颜色检测
spring中声明式事务实现原理猜想
  @Transactional注解简介 @Transactional 是spring中声明式事务管....
的头像 Android编程精选 发表于 10-13 09:20 182次 阅读
LiDAR测量物料体积能为行业带来哪些变化
在商业化竞争日益激烈的环境下,任何提高运营效率的机会对公司来说都是宝贵的。包括对原材料的精准测量和追....
的头像 广州虹科电子科技有限公司 发表于 10-13 09:11 160次 阅读
stm32启动代码如何进行分析
stm32启动代码如何进行分析
发表于 10-13 06:44 0次 阅读
xv6的文件系统是如何实现的
文件系统 本文继续来看 的文件系统部分, 将文件系统的设计分为 7 层: ,磁盘、缓存区、日志三个部....
的头像 Linux阅码场 发表于 10-12 18:00 125次 阅读
 xv6的文件系统是如何实现的
Linux中匿名页的访问分析
Linux 中 有后备文件支持的页称为文件页,如属于进程的代码段、数据段的页,内存回收的时候这些页面....
的头像 Linux阅码场 发表于 10-12 17:52 151次 阅读
处理器中异常和中断解决
异常是能够引起程序流偏离正常流程的事件,当异常发生时,正在执行的程序就会被挂起,处理器转而执行一块与....
的头像 单片机匠人 发表于 10-12 17:14 268次 阅读
禹山便携式溶氧传感器的使用方法
禹山便携式溶氧传感器采用了国际领先的荧光寿命技术,其基于物理学中特定物质对活性荧光的猝熄原理。这种荧....
发表于 10-12 16:43 22次 阅读
RUST的真实驱动案例
我们无法确定RUST在内核的最终趋势,有多少人愿意迁移,但是至少Linus愿意试水。 Wedson ....
的头像 Linux阅码场 发表于 10-12 15:59 81次 阅读
RUST的真实驱动案例
那些有着巨大影响力的代码盘点
2009 年,Facebook 推出了一份改变世界的代码——点「赞」按钮。「赞」是包括 Leah P....
的头像 strongerHuang 发表于 10-12 15:46 174次 阅读
那些有着巨大影响力的代码盘点
那些书本上都没有提到的C语言volatile用法
许多程序员都无法正确理解C语言关键字volatile,这并不奇怪。因为大多数C语言书籍通常都是一两句....
的头像 STM32嵌入式开发 发表于 10-12 14:47 870次 阅读
那些书本上都没有提到的C语言volatile用法
美政府索要芯片数据原因之一被公开 剑指中国大陆车用芯片产业链
前不久,美政府组织召开了第三轮半导体峰会,依然是为了解决目前严重的缺芯问题。在这一轮峰会上,美政府要....
的头像 电子发烧友网 发表于 10-12 14:31 303次 阅读
什么是MicroPython 它能做什么有什么局限
随着Python成为主流的编程语言,MicroPython在嵌入式系统领域也越来越热门起来,尤其是大....
的头像 电子森林 发表于 10-12 11:44 216次 阅读
PO VO DTO转换神器的思路
当然有的人喜欢写get set,或者用BeanUtils 进行复制,代码只是工具,本文只是提供一种思....
的头像 Linux爱好者 发表于 10-12 11:13 191次 阅读
SATA连接器:低成本下的高连接性
电子发烧友网报道(文/李宁远)SATA连接器,作为连接器细分种类之一,广泛应用于PC、SSD、服务器....
的头像 电子发烧友网 发表于 10-12 10:49 250次 阅读
全项目食品安全检测仪的检测项目
全项目食品安全检测仪检测项目,全项目食品安全检测仪【恒美HM-G1200】可以在餐饮行业、学校工厂食....
发表于 10-12 09:48 33次 阅读
如何在Colab中使用SQL
如今,编码测试在数据科学面试过程中几乎是标准的。 作为一名数据科学招聘经理,我发现一个20-30分钟....
的头像 智能感知与物联网技术研究所 发表于 10-12 09:39 158次 阅读
如何在Colab中使用SQL
命令行工具Kubectl的别样用法
  kubectl 是 K8s 官方附带的命令行工具,可以方便的操作 K8s 集群。这篇文章主要介绍....
的头像 马哥Linux运维 发表于 10-12 09:31 124次 阅读
C++中的背包问题说明和源码示例
  问题说明 有N件物品和一个容量为V的背包。 第i件物品的重量是w[i],价值是v[i]。 求解将....
的头像 C语言编程学习基地 发表于 10-12 09:27 122次 阅读
怎样去搭建一种STM32代码生成模型
怎样去搭建一种STM32代码生成模型?要注意哪些问题?...
发表于 10-11 06:25 0次 阅读
string与《string.h》有哪些区别
string与《string.h》的定义有何不同? string与《string.h》有哪些区别? ...
发表于 10-09 07:22 0次 阅读