LeetCode 1184. 公交站间的距离
题目描述详见LeetCode原题目。
这道题的题目可以抽象成,给定一个环,环上有若干个结点,它们彼此相继连接,形成一个环形图。结点有距离,保存在数组 a a a当中, a = [ 1 , 2 , 3 , 4 ] a=[1, 2, 3, 4] a=[1,2,3,4]表示的是结点 a 1 → a 2 a_1 \rightarrow a_2 a1→a2之间的距离为 1 1 1, a 2 → a 3 a_2 \rightarrow a_3 a2→a3之间的距离为 2 2 2, a 3 → a 4 a_3 \rightarrow a_4 a3→a4之间的距离为 3 3 3, a 4 → a 1 a_4 \rightarrow a_1 a4→a1之间的距离为 4 4 4。注意图的连接关系是双向的,即从某个结点可以向前走也可以向后走。
现在给定一个query,它有start和destination组成,二者均对应于环形图当中的结点编号,求从 s t a r t → d e s t i n a t i o n start \rightarrow destination start→destination之间的最短距离,也就是双向距离当中的最小者。
给出这道题之后我的思路是非常明确的,先后求从 s t a r t → d e s t i n a t i o n start \rightarrow destination start→destination向前走和向后走的最短距离即可,但是在实现上遇到了坑。
参考了LeetCode C++部分的题解,豁然开朗,其中利用到了C++ numeric库当中的accumulate,我感觉非常的使用,便在此进行记录。
accumulate有四个参数,分别是迭代器的起始位置、终点位置、累加的初始值以及自定义操作函数,前三个参数是必须的,第四个由于还没有用到所以不做深究。
在最开始,如果 s t a r t start start的位置在 d e s t i n a t i o n destination destination的右侧,那么可以交换二者的位置,使得 s t a r t start start永远比 d e s t i n a t i o n destination destination小,有助于后续的问题分析,二者是等价的。
现在,答案是显而易见的,由两部分当中的较小者组成,第一部分是从 s t a r t start start直接"向右"走到 d e s t i n a t i o n destination destination的距离,而第二部分是从 s t a r t start start向相反方向(此时一定经过了编号为0的结点)走到 d e s t i n a t i o n destination destination的距离。分别对应于accumulate(distance.begin() + start, distance.begin() + destination, 0)
和accumulate(distance.begin(), distance.begin() + start, 0) + accumulate(distance.begin() + destination, distance.end(), 0)
。
经过我自己的实验发现,accumulate
当中迭代器的位置也是左闭右开的,意味着第二个参数"迭代器的终点"将不会被累加,累加一直持续到"迭代器终点的前一个位置" 。这与vector容器的begin(), end()
也是左闭右开是对应的,因此使用accumulate(v.begin(), v.end(), 0)
可以完成对vector对象v
当中元素的累加。
本题最关键的一点也就是要意识到给定的distance数组是左开右闭的,需要利用这一点来进行累加。
本题的代码实现如下:
cpp
class Solution {
public:
int distanceBetweenBusStops(vector<int>& distance, int start, int destination) {
if(start > destination) {
swap(start, destination);
}
cout << accumulate(distance.begin()+start, distance.begin()+destination, 0) << endl;
cout << accumulate(distance.begin(), distance.begin()+start, 0) +
accumulate(distance.begin()+destination, distance.end(), 0) << endl;
return min(
accumulate(distance.begin()+start, distance.begin()+destination, 0),
accumulate(distance.begin(), distance.begin()+start, 0) +
accumulate(distance.begin()+destination, distance.end(), 0)
);
}
};
Go语言对应的实现,Go语言的实现中没有用到累加函数,而是直接使用for循环进行累加,注意处理左开右闭这条性质即可:
go
func distanceBetweenBusStops(distance []int, start int, destination int) int {
if start > destination {
start, destination = destination, start // 注意start和destination是参数, 它们已经被声明了
// 此处不能够使用 := 进行swap, 而应该直接使用 =
}
ans_1, ans_2 := 0, 0
for i:=0; i<len(distance); i++ {
if start <= i && i < destination { // 处理左开右闭, 计算的是从start正向走到destination的距离
ans_1 += distance[i]
} else { // 从start反向走到destination的距离
ans_2 += distance[i]
}
}
return min(ans_1, ans_2)
}