重温算法之加油站

179 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

一.题目介绍

1.题目来源

链接:LeetCode

2.题目

在一条环路上有n个加油站,其中第i个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车,从第i个加油站开往第i+1个加油站需要消耗汽油cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。 给定两个整数数组gas和cost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则保证它是唯一的。 image.png

二.具体实现

1.实现思路

考虑暴力破解,一方面是验证下自己对题目的理解是否正确,另一方面后续的优化也可以从这里入手。
考虑从第 0 个点出发,能否回到第 0 个点。
考虑从第 1 个点出发,能否回到第 1 个点。
考虑从第 2 个点出发,能否回到第 2 个点。
......
考虑从第 n 个点出发,能否回到第 n 个点。
由于是个圆,得到下一个点的时候我们需要取余数。
另外针对暴力法,优化算法主要从圆上入手

2.实现代码

1)暴力法,缺点很明显,每一步都需要避开圆

public int canCompleteCircuit(int[] gas, int[] cost) {
    //汽油
    int n = gas.length;
    //考虑从每个点出发
    for (int i = 0; i < n; i++) {
        int j = i;
        int remain = gas[i];
        //说明可以到达下一个点
        while (remain -cost[j] >=0){
            //减去花费的 + 新的补给的
            remain = remain - cost[j] + gas[(j+1) % n];
            j = (j + 1) % n;
            //j 回到了 i
            if (j == i) {
                return i;
            }
        }
    }
    return -1;
}

2)针对暴力法的优化算法

public int canCompleteCircuit1(int[] gas, int[] cost) {
    int n = gas.length;
    for (int i = 0; i < n; i++) {
        int j = i;
        int remain = gas[i];
        while (remain - cost[j] >= 0) {
            //减去花费的加上新的点的补给
            remain = remain - cost[j] + gas[(j + 1) % n];
            j = (j + 1) % n;
            //j 回到了 i
            if (j == i) {
                return i;
            }
        }
        if (j < i) {
            return -1;
        }
        //i 直接跳到 j,外层 for 循环执行 i++,相当于从 j + 1 开始考虑
        i = j;
    }
    return -1;
}

3.运行结果

image.png

image.png

三.题后思考

可以看出来,即使是优化后的算法,其实也不是最优解。有时候自己一直找不到突破口是因为自己把问题想困难了,其实有的问题很简单,需要不断的分解。无论怎么样,这也是自己思考后的产物,算法题,每做一题再去看题友的解决方案都有所收获,哦,原来这个题还能这么做,也算是每天进步一点点吧,加油!