贪心算法经典例题讲解c语言
134. 加油站
力扣题目链接
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。
说明:
如果题目有解,该答案即为唯一答案。输入数组均为非空数组,且长度相同。输入数组中的元素均为非负数。
示例 1:
输入:
gas = [1,2,3,4,5]cost = [3,4,5,1,2]
输出: 3
解释:
从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。因此,3 可为起始索引。
示例 2:
输入:
gas = [2,3,4]
cost = [3,4,3]
输出: -1
解释:
你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油。开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油。开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油。你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。因此,无论怎样,你都不可能绕环路行驶一周。
环型,可以用2*一维数组表示所有可能性。
如果一开始车子的油量就不够发动,直接跳过。
否则先加油,再减去扣的油量,再判断够不够,够就下一站,直到最后一站。
不够跳过本次 i ,从下一个站开始重来。
package com.programmercarl.greed;
/** * @ClassName CanCompleteCircuit * @Descriotion TODO * @Author nitaotao * @Date 2022/7/16 9:02 * @Version 1.0 * https://leetcode.cn/problems/gas-station/ * 134. 加油站 **/
public class CanCompleteCircuit {
public int canCompleteCircuit(int[] gas, int[] cost) {
//加油站编号
int n = gas.length;
//构建环型数组的一维化
int[] gas2 = new int[2 * gas.length];
int[] cost2 = new int[2 * cost.length];
int gasSum = 0;
int costSum = 0;
for (int i = 0; i < n; i++) {
if (gas[i] == 0 && cost[i] == 0) {
continue;
}
gasSum += gas[i];
costSum += cost[i];
gas2[i] = gas[i];
gas2[i + n] = gas[i];
cost2[i] = cost[i];
cost2[i + n] = cost[i];
}
if (gasSum < costSum) {
return -1;
}
//当前车里的汽油
int curGas = 0;
for (int i = 0; i < n; i++) {
if (gas2[i] == 0) {
//没有初始油量
//车子动不起来
continue;
}
// System.out.println("----------------" + i + "----------------");
boolean noEnd = false;
//初始的汽车汽油容量
curGas = gas2[i];
for (int j = i; j < i + n - 1; j++) {
// System.out.println("" + curGas + "-" + cost2[j] + "+" + gas2[j + 1]);
curGas -= cost2[j];
if (curGas < 0) {
//中间不够用
noEnd = true;
break;
}
curGas += gas2[j + 1];
}
//最后一步
int temp = i + n - 1;
// System.out.println("" + curGas + "-" + cost2[temp]);
curGas = curGas - cost2[temp];
if (curGas < 0) {
//最后一步不够用
noEnd = true;
}
if (!noEnd) {
//够用
return i;
}
}
//都不够用
return -1;
}
public static void main(String[] args) {
System.out.println(new CanCompleteCircuit().canCompleteCircuit(new int[]{
1, 2, 3, 4, 5}, new int[]{
3, 4, 5, 1, 2}));
}
}
贪心思想:如果当前剩余油量<0,则本起始点不可用。直接回溯重置跳到下一个起始点。
public int canCompleteCircuit2(int[] gas, int[] cost) {
/** * 贪心思想 */
//当前油量
int curSum = 0;
int totalSum = 0;
int start = 0;
for (int i = start; i < gas.length; i++) {
//当前剩余油量
curSum += gas[i] - cost[i];
//总耗油量
totalSum += gas[i] - cost[i];
//如果剩余油量<0,则不够开往下一站,则本起始点不可用,回溯
if (curSum < 0) {
curSum = 0;
start = i + 1;
}
}
//如果总加油站油量不够总行程
if (totalSum < 0) {
//则无法完成环型
return -1;
}
return start;
}