返回

【刷题日记】1184. 公交站间的距离,列车时刻表几何也能巧妙计算

后端

【刷题日记】1184. 公交站间的距离,列车时刻表几何也能巧妙计算

好久不刷题,没有锻炼思维,今天重新捡起算法题,感觉思维都有点生锈了,本以为这是一道非常简单的题目,但没想到却花费了我不少时间,算法题的魅力就在于此,总能给人带来惊喜和挑战。

题目

好家伙,许久不刷题,一道公交车坐到屁股痛,然后走路回到起点的问题都能难得住我。题目是这样的:

给你一个整数数组 distances ,其中 distances[i] 表示第 i 个公交车站到第 i + 1 个公交车站的距离。另给你一个整数 start ,表示你从第 start 个公交车站开始。你决定沿途停靠在任意数目的公交车站,并最终回到第 start 个公交车站。

你需要返回从第 start 个公交车站到第 start 个公交车站的最小总距离。

示例 1:

输入:distances = [1, 2, 3, 4], start = 1
输出:11
解释:
第 1 步:从第 1 个公交车站走到第 2 个公交车站,距离为 2。
第 2 步:从第 2 个公交车站走到第 3 个公交车站,距离为 3。
第 3 步:从第 3 个公交车站走到第 4 个公交车站,距离为 4。
第 4 步:从第 4 个公交车站走到第 1 个公交车站,距离为 2。
最小总距离为 2 + 3 + 4 + 2 = 11。

示例 2:

输入:distances = [1, 2, 3], start = 0
输出:6
解释:
第 1 步:从第 0 个公交车站走到第 1 个公交车站,距离为 1。
第 2 步:从第 1 个公交车站走到第 2 个公交车站,距离为 2。
第 3 步:从第 2 个公交车站走到第 3 个公交车站,距离为 3。
第 4 步:从第 3 个公交车站走到第 0 个公交车站,距离为 0。
最小总距离为 1 + 2 + 3 + 0 = 6。

算法分析

这道题乍一看比较简单,只需要把公交站之间的距离相加起来就行了,但是仔细一想,发现事情并不简单。因为我们可以在任意公交车站停靠,所以我们可以选择不同的路线来达到起点,而不同的路线会有不同的总距离。

比如,在示例 1 中,我们可以选择从第 1 个公交车站出发,然后依次经过第 2 个、第 3 个和第 4 个公交车站,再回到第 1 个公交车站,这样总距离为 11。但我们也可以选择从第 1 个公交车站出发,然后直接回到第 1 个公交车站,这样总距离只有 0。

因此,为了找到最短的总距离,我们需要考虑所有可能的路线,并从中选择出总距离最短的一条。这显然是一个 NP 难的问题,因此我们只能采用启发式算法来求解。

这里我们采用一种贪心算法来求解。贪心算法的基本思想是,在每一步选择当前最优的方案,并以此作为下一步的起点。

在我们的问题中,我们可以把公交车站看成一个环,然后从起点出发,每次选择距离最近的公交车站作为下一站,直到回到起点。这样,我们就可以得到一条总距离最短的路线。

代码实现

public int distanceBetweenBusStops(int[] distances, int start, int destination) {
    // 计算公交车站之间的总距离
    int totalDistance = 0;
    for (int i = 0; i < distances.length; i++) {
        totalDistance += distances[i];
    }

    // 计算从起点到终点的顺时针距离
    int clockwiseDistance = 0;
    for (int i = start; i != destination; i = (i + 1) % distances.length) {
        clockwiseDistance += distances[i];
    }

    // 计算从起点到终点的逆时针距离
    int counterClockwiseDistance = totalDistance - clockwiseDistance;

    // 返回最短距离
    return Math.min(clockwiseDistance, counterClockwiseDistance);
}

总结

这道题是一道比较典型的贪心算法题,通过使用贪心算法,我们可以在最坏的情况下找到一条最短的路径。

这道题也告诉我们,在解决问题的时候,不要被表面现象所迷惑,要学会透过现象看本质,才能找到问题的真正解法。

好了,今天的刷题日记就到这里,希望对大家有所帮助。我们下期再见!