考虑一个城市,街道完美布局,形成无限的方格。在这个城市中,发现两个给定点(原点和目的地)之间的最短路径比其他更复杂的城市要容易得多。作为一名新的优步开发人员,您的任务是创建一个执行此计算的算法。
考虑到用户的出发地和目的地坐标,他们每个都位于某条街道上,找到他们之间最短路线的长度,假设汽车只能沿着街道行驶。您可以保证至少有一个坐标是整数。
我正在努力找出这里的逻辑。有很多情况,我不知道如何容纳它们。这就是我到目前为止所拥有的
double perfectCity(double[] departure, double[] destination) {
double yDist = Math.abs(destination[1]-departure[1]);
double xDist = Math.abs(departure[1] - departure[0] + departure[1]-destination[0]);
return xDist + yDist;
}
答案 0 :(得分:3)
如果输入是整数,算法非常简单,只需找到x和y坐标之间的绝对值,然后将它们加在一起。这称为Manhattan distance。
int distance = Math.abs(x1 - x2) + Math.abs(y1 - y2);
除了一种情况外,双打几乎完全相同。以下是一些可能性:
可能性1-3使用与查找整数距离相同的算法都可以正常工作,除了#4有可能使轴在同一个块上。
例如,如果输入为:{x: 0.5, y: 2}
和{x: 0.5, y: 3}
,则必须水平,垂直,然后再水平向后移动才能到达目的地。这与{x: 0.5, y: 2}
和{x: 1.5, y: 3}
的输入不同,因为无需在同一轴上向后移动。
因此,在除之外的所有情况下都可以使用常规算法,以便在X和Y都具有浮点值且具有相同floor
- ed值的情况下。
您的代码看起来应该是这样的。
import static java.lang.Math.*;
public static double perfectCity(double x1, double y1, double x2, double y2) {
double xDist = abs(x1 - x2);
double yDist = abs(y1 - y2);
if (floor(x1) != x1 && floor(x2) != x2 && // both Xs are doubles
floor(x1) == floor(x2)) { // on the same block
xDist = min(abs(x1 - floor(x1) + x2 - floor(x2)),
abs(x1 - ceil(x1) + x2 - ceil(x2)));
} else if (floor(y1) != y1 && floor(y2) != y2 && // both Ys are doubles
floor(y1) == floor(y2)) { // on the same block
yDist = min(abs(y1 - floor(y1) + y2 - floor(y2)),
abs(y1 - ceil(y1) + y2 - ceil(y2)));
}
return xDist + yDist;
}
通过使用辅助函数分别计算每个轴,可以进一步简化这一过程。
public static double perfectCity(double x1, double y1, double x2, double y2) {
return travelOnAxis(x1, x2) + travelOnAxis(y1, y2);
}
private static double travelOnAxis(double from, double to) {
if (Math.floor(from) == Math.floor(to)) {
double dist = Math.abs((from % 1) + (to % 1));
return Math.min(dist, 2 - dist);
} else {
return Math.abs(from - to);
}
}
答案 1 :(得分:1)
如果这是一个方格,你可以分别考虑x和y坐标;最小距离是两个方向上最小距离的总和。
在p
方向(x
或y
),您必须从p1
移至p2
。从p1
开始,您可以移至floor(p1)
或ceil(p1)
以前往道路(如果p1
是整数,则可能相等);从那里,您可以移至floor(p2)
或ceil(p2)
所在的道路p2
或p2
。从那里,您可以转到p
。
因此,min(abs(p1 - ceil(p1) ) + abs(ceil(p1) - floor(p2)) + abs(floor(p2) - p2), # (1)
abs(p1 - floor(p1)) + abs(floor(p1) - ceil(p2) ) + abs(ceil(p2) - p2), # (2)
abs(p1 - floor(p1)) + abs(floor(p1) - floor(p2)) + abs(floor(p2) - p2), # (3)
abs(p1 - ceil(p1) ) + abs(ceil(p1) - ceil(p2) ) + abs(ceil(p2) - p2)) # (4)
方向的最小距离是
x
因此,您可以针对y
和floor
方向单独计算,然后添加。
为了说明这一点(分别缩写ceil
和f
分别为p
和f(p1) p1 c(p1)
+---O>>>>+>>>>>>>>+
.
.
+>>>O----+
f(p2) p2 c(p2)
--------------------------------> p axis
):
>
这里用.
表示最短路线。 p
s在最短的路线上,但由于路线的那部分与p1 -> c(p1) -> f(p2) -> p2
方向正交,因此它“朝向该方向的最小距离”“不计数”。
此处显示的最小路线p1
,是上面的案例1.
可视化交换p2
和p1 ->f(p1) -> c(p2) -> p2
应该不难,在这种情况下,最小路由是从pN == f(pN) == c(pN)
开始(案例2)。
abs(pN - f(pN))
的情况并无太大差异;那么,表达式abs(pN - c(pN))
或f(p1) == f(p2)
的部分只是零。
略有不同的情况是f(p1) p1 c(p1) f(p1) p1 c(p1)
+---O>>>>+ +<<<O----+
. .
. .
+-----O<<+ +>>>>>O--+
f(p2) p2 c(p2) f(p2) p2 c(p2)
--------------------------------> p axis
:
p1 -> f(p1) -> f(p2) -> p2
在这种情况下,最小路线可以是p1 -> c(p1) -> c(p2) -> p2
或\(.*?\)
(分别是案例3和4)。
答案 2 :(得分:0)
正如4castle所提到的,如果仅考虑整数输入,则问题很简单。在这种情况下,在“向前移动”之后你永远不必“向后移动”,因为你总能在一次移动中到达你的目的地。
但由于最多每个出发地/目的地需要考虑一个浮点数,我们需要考虑3个案例,(警告:冗长的解释) 。下面是一个带有解释的python2实现。
出发地和目的地的x坐标是相同的,并且不是浮点数。在这种情况下,最短距离只是y坐标之间的绝对差。相反的逻辑反之亦然。
import math
class Location():
def __init__(self, cord):
self.x = cord[0]
self.y = cord[1]
def perfectCity(departure, destination):
l1 = Location(departure)
l2 = Location(destination)
if l1.x == l2.x and float(l1.x).is_integer() and float(l2.x).is_integer():
return abs(l1.y-l2.y)
if l1.y == l2.y and float(l1.y).is_integer() and float(l2.y).is_integer():
return abs(l1.x-l2.x)
当离开中的一个坐标是浮点时,则:
return min(calc_round_up_dist(l1, l2), cal_round_down_dist(l1, l2))
Lets take an example of (0.4, 1) and (0.9, 3)
用于以下计算。
在计算round_up时,我们需要计算3个距离:
1 - 0.4 = 0.6 in the above example
abs(3-1) = 2 in the above example
0.9 in the above case
中离港的浮点对应点与四舍五入后的离境点浮点值的新值0.4 + 0.6(this is the round_up distance) = 1.0
,即abs(0.9 - 1.0) = 0.1
0.6 + 2 + .1 = 2.7
这是最短的距离。需要进行相应的计算以进行四舍五入。我们在两者中选择最小值。 round_up和round_down的代码如下,
import math
class Location():
def __init__(self, cord):
self.x = cord[0]
self.y = cord[1]
def floating_point_round_up(self):
if not float(self.x).is_integer():
return math.ceil(self.x) - self.x
if not float(self.y).is_integer():
return math.ceil(self.y) - self.y
return 0
def floating_point_round_down(self):
if not float(self.x).is_integer():
return self.x - math.floor(self.x)
if not float(self.y).is_integer():
return self.y - math.floor(self.y)
return 0
def non_floating_point_diff(self, obj):
if not float(self.x).is_integer():
return abs(self.y - obj.y)
if not float(self.y).is_integer():
return abs(self.x - obj.x)
return abs(self.y - obj.y)
def floating_point_counterpart(self, obj):
if not float(self.x).is_integer():
return obj.x
if not float(self.y).is_integer():
return obj.y
return obj.x
def floating_point(self):
if not float(self.x).is_integer():
return self.x
if not float(self.y).is_integer():
return self.y
return self.x
上下舍入功能如下,
def calc_round_up_dist(l1, l2):
dist = l1.floating_point_round_up()
diff = l1.non_floating_point_diff(l2)
floating_point_counterpart = l1.floating_point_counterpart(l2)
new_val = dist + l1.floating_point()
return dist + diff + abs(new_val - floating_point_counterpart)
def cal_round_down_dist(l1, l2):
dist = l1.floating_point_round_down()
diff = l1.non_floating_point_diff(l2)
floating_point_counterpart = l1.floating_point_counterpart(l2)
new_val = l1.floating_point() - dist
return dist + diff + abs(floating_point_counterpart - new_val)
最后调用上述方法的主函数
def perfectCity(departure, destination):
l1 = Location(departure)
l2 = Location(destination)
if l1.x == l2.x and float(l1.x).is_integer() and float(l2.x).is_integer():
return abs(l1.y-l2.y)
if l1.y == l2.y and float(l1.y).is_integer() and float(l2.y).is_integer():
return abs(l1.x-l2.x)
return min(calc_round_up_dist(l1, l2), cal_round_down_dist(l1, l2))