1628.Driving problem
There is a road with a lengthL
and a widthW
. There are some circular obstacles in the road. The radius is 1, there is a circular car with a radius of 2. Ask if the car can pass this road. You can think of the road as a rectangle on two-dimensional coordinates. The four points are(0,0), (0,W), (L,0), (L,W)
. Now you need to start fromx=0
Tox=L
, contact with obstacles is not allowed, and all parts of the car are betweeny=0
andy=W
, contact is not allowed.
Example
GivenL=8
,W=8
, the obstacle coordinates are[[1,1],[6,6]]
. Returnyes
.
The center of the car can go from (0,5) to (2,5) to (5,2) to (8,2), so return yes.
你是怎麼想到的?
。題目假設
- The radius of each obstacle is 1.
- The radius of the car is 2.
- The car cannot go across the road.
- No contact is allowed between the car and any obstacle.
。重要問題
車子和障礙物不能有任何接觸,而且座標可以是 float
而且路徑不一定是要一點一點的,只要滿足車子不碰到障礙物即可
。直覺
直覺是要先確定各個障礙物的座標,然後從 x = 0 開始走
。解決方法可行性
如果用矩陣那會太複雜,用座標也是,而且還可以是 float 型態,是要判斷到什麼時候?
於是就直接看答案了,原來是要用 union find,用了 union find 會瞬間簡單很多,剛好也藉此學習了"並查集"
。解決方案
我們可以想到,如果車子可以通過兩個障礙物,表示圓心之間的距離是夠大的
所以我們將兩個障礙物計算圓心距離,如果不夠大,歸為同一組,然後每個障礙物也看一下是不是自己的上方也無法通過,如果無法通過就將這個障礙物與某一個數(這邊叫做n)聯集,下方無法通過則是跟 n+1 聯集
最後,我們從並查集裡去找 n 和 n+1 是不是在同一集合裡,如果在同一集合,
表示某個上方無法通過的障礙物和下方無法通過的障礙物在集合裡,又剛剛在這集合裡的都是兩兩無法讓車子通過的,所以 n 和 n+1 在同一集合裡表示車子過不去
。資料結構
UnionFind
。複雜度
掃描兩兩的關係,所以是 O(n^2)
class UnionFind {
int[] father;
//這邊 father的 index 表示元素,father[i]表示這個元素的 father
UnionFind(int n) {
father = new int[n];
for (int i=0; i<n; i++) {
father[i] = i;
}
}
int find_and_compress(int x) {
int parent = x;
//找出自己是自己的parent的那個點,就是x的parent
while (parent != father[parent]) {
parent = father[parent];
}
//compress path,把剛剛路徑上的點的 parent 更新
int temp;
while (x != father[x]) {
temp = father[x];
father[x] = parent;
x = temp;
}
return parent;
}
private static final String YES = "yes";
private static final String NO = "no";
public String drivingProblem(int L, int W, double[][] p) {
int n = p.length;
//+2 because we use n and n+1 as an element
UnionFind uf = new UnionFind(n+2);
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
double dx = (p[i][0] - p[j][0])*(p[i][0] - p[j][0]);
double dy = (p[i][1] - p[j][1])*(p[i][1] - p[j][1]);
//because the coordinate is float type, for convenience,
//we don't calculate sqrt
//36d because the minimal distance for a car to pass is 6d
if (dx + dy <= 36d) {
uf.union(i, j);
}
}
//表示這個點的y座標+半徑會碰到車子->上方沒有路
if (p[i][1]+1 >= W-4)
uf.union(i, n);
//表示這個點的y座標+半徑會碰到車子->下方沒有路
if (p[i][1]-1 <= 4)
uf.union(i, n+1);
}
if (uf.find_and_compress(n) == uf.find_and_compress(n+1))
return NO;
return YES;
}
}