有一颗树,一只松鼠,和几个见过,位置由二维网络中的单元格表示。你的目标是找到最短距离,让松鼠收集所有的见过,并把它们一个一个地放在树下。松鼠每次只能携带一个坚果。可以在四个方向上移动——上、下、左、右,到相邻的单元格。距离用移动的次数表示。
所有给定的位置都不会重叠;
松鼠一次只能携带一个坚果;
给定的坚果位置没有顺序;
宽度和高度是正整数。3 <= 高度 * 宽度 <= 10,000。
给定的网格中至少包含一个坚果,但只有一棵树和一只松鼠。
例子:
输入:height=5, width=7, tree=[2,2], squirrel=[4,4], nuts=[[3,0],[2,5]]
输出:12
解释:
网格规模5 * 7,树在(2,2),松鼠在(4,4),有两个坚果,分别在(3,0),(2,5)。
松鼠先去(2,5)拿坚果,放到树下,然后去拿(3,0)的坚果,放到树下。
总共走了:3 + 3 + 3 + 3 = 12 步。
思路:
首先,计算两点的距离,就是横纵坐标的差的绝对值的和。
const distance = (a, b) => {
return Math.abs(a[0], b[0]) + Math.abs(a[1], b[1]);
}
松鼠的移动轨迹是:先到一个坚果处,然后走到树,最后在树和剩下的坚果之间往返。所以只要找出第一个坚果,就好说。
我最开始想到的是,第一个坚果就应该是离松鼠最近的那个,结果发现错误。画了图之后发现的确不行,
0 0 0 0 0
0 0 0 0 0
0 树 0 0 果1
果2 0 果3 0 0
0 0 0 鼠 0
坚果3离松鼠最近,但计算一下,就会发现,首先去坚果1,距离是最短的。
试验多次,发现:(我们要遍历坚果,找出最先走的那一个,最先走的坚果first初始值为nuts第一个元素)若当前坚果与树的距离之和first坚果与松鼠的距离之和 大于 当前坚果与松鼠的距离和first坚果与树的距离之和,就更新first坚果为当前坚果。
这句话很绕,多读几遍。
for (let i in nuts) {
let now = distance(nuts[first], squirrel) + distance(nuts[i], tree),
before = distance(nuts[i], squirrel) + distance(nuts[first], tree);
if (now > before)
first = i;
}
求出第一个要去坚果之后,从nuts坚果数组中删掉这个坚果,计算其他坚果与树的距离的2倍的总和,加上第一次去坚果与第一次去树的距离,即为最终结果。
/**
* @param height: the height
* @param width: the width
* @param tree: the position of tree
* @param squirrel: the position of squirrel
* @param nuts: the position of nuts
* @return: the minimal distance
*/
const minDistance = function (height, width, tree, squirrel, nuts) {
// Write your code here
const distance = (a, b) => {
return Math.abs(a[0]-b[0]) + Math.abs(a[1]-b[1]);
}
let first = 0; // 第一次去最近的坚果
for (let i in nuts) {
let now = distance(nuts[first], squirrel) + distance(nuts[i], tree),
before = distance(nuts[i], squirrel) + distance(nuts[first], tree);
if (now > before)
first = i;
}
let firstDistance = distance(nuts[first], squirrel) + distance(nuts[first], tree);
let res = firstDistance;
nuts.splice(first, 1);
for (let nut of nuts) {
res += distance(nut, tree)*2;
}
return res;
}
PS:输入参数中的 height 与 width 没用!