赞
踩
在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas 和 cost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。
原题链接:https://leetcode.cn/problems/gas-station
上图描述了“环形”路线的含义,每个节点i表示加油站,其数值表示gas[i];节点之间的曲线表示从加油站i到加油站j之间的油耗,行驶过程必须顺时针进行。以节点1为起点,题目含义就是顺时针绕行,测试是否可以顺利回到起点。
很直观的方案,依次测试每个加油站是否可以作为起点即可,但是这道题正向遍历暴力解很容易报超时,因为测试样例中有几个极其离谱的,后面我展示了一个,所以尝试从数组末尾反向遍历,依次尝试当前加油站是否可以作为起点,一旦遇到第一个可作为起点的加油站,就为最优解。
说一下我的想法:如果以任意站点为起点start,我们逐步行驶,只要可以到达起点的前一个站点end,并且此时汽油剩余量curGas>=cost[end],说明可以顺利回到起点。
以样例1为例,看一下我的解决思路:
(1)第一次,假设站点4(指数组索引)为起点,既start=4,车辆剩余油量curGas=g[start]=5:
(2)第二次,假设站点3(指数组索引)为起点,既start=3,车辆剩余油量curGas=g[start]=4:
class Solution{ public int canCompleteCircuit(int[] gas, int[] cost) { int n=gas.length; int i=n-1; // 从后往前测试 int start=-1; // 为了保证没有找到起点返回-1的条件,初始化start=-1 boolean isCan=false; // 记录是否找到起点 while (i>=0){ if(gas[i]<cost[i]){ // 说明油量小于油耗,无法到达下一站,也就无法作为起点 i--; continue; } start=i; // 假设当前加油站为起点 int end=start-1; // 假设起点的前一站为终点 if (start==0){ // 因为是环形路线,第一站的前一站为整个数组的最后一站 end=n-1; } int curGas=gas[start]; // 测试以当前起点开始行驶,是否可以环绕一周 while (true){ if (curGas<cost[i]){ // 行驶过程中发现,当前汽油量无法到达下一各加油站 break; } if (i==end&&curGas>=cost[i]){ // 如果到达起点的前一个加油站时,发现汽油量足以到达起点,说明找到了合适的起点 isCan=true; break; } curGas=curGas-cost[i%n]+gas[(i+1)%n]; //计算到达下一站后的汽油量(需要加上下一站的油量) i=(i+1)%n; // 计算下一站 } if (isCan){ // 一旦找到起点就停止遍历 break; } i=start-1; // 说明当前站无法作为起点,则测试前一个站是否可以作为起点 } return isCan?start:-1; } }
说实话这道题能暴力解出来,真的是有些运气的,人都做崩溃了。。下次再研究大佬们的题解吧。
题外话,这种样例是什么神仙想出来的啊,要我老命。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。