谷歌面经题

1。

 

 

Paper Cut into Minimum Number of Squares
Given a paper of size A x B. Task is to cut the paper into squares of any size. Find the minimum number of squares that can be cut from the paper.
Examples:
Input  : 36 x 30
Output : 5
Explanation : 3 (squares of size 12x12) + 2 (squares of size 18x18)

Input  : 4 x 5
Output : 5
Explanation : 1 (squares of size 4x4) + 4 (squares of size 1x1)



Wrong Sol : Greedy solution doesn’t always produce optimal result.

For example if input is 36 x 30,

Greedy algorithm:

  1. One square of size 30 x 30

  2. Five squares of size 6 x 6

would produce output 6, but we can cut the paper in 5 squares,

  1. Three squares of size 12 x 12

  2. Two squares of size 18 x 18



Sol1 : DFS

红色分叉表示切在width上

蓝色分叉表示切在height上

黄色表示base case

绿色表示重复计算

                




 
public int dfsWithoutMem(int width, int height) {
    if (width == height) {
        return 1;
    }
    int vertMin = Integer.MAX_VALUE;
    int horMin = Integer.MAX_VALUE;
    for (int i = 1; i <= width / 2; i++) {
        vertMin = Math.min(dfsWithoutMem(width - i, height) + dfsWithoutMem(i, height), vertMin);
    }
    for (int j = 1; j <= height / 2; j++) {
        horMin = Math.min(dfsWithoutMem(width, height - j) + dfsWithoutMem(width, j), horMin);
    }
    int res = Math.min(vertMin, horMin);
    return res;
}
Sol2 : DFS apply memorization: map version

public int dfsWithMemI(int width, int height) {
    Map<String, Integer> cache = new HashMap<>();
    return dfsWithMemHelperI(width, height, cache);
}
private int dfsWithMemHelperI(int width, int height, Map<String, Integer> cache) {
    if (width % height == 0) {
        return width / height;
    }
    if (height % width == 0) {
        return height / width;
    }
    String key = Math.min(width, height) + "," + Math.max(width, height);
    Integer minNumber = cache.get(key);
    if (minNumber != null) {
        return minNumber;
    }
    int vertMin = Integer.MAX_VALUE;
    int horMin = Integer.MAX_VALUE;
    for (int i = 1; i <= width / 2; i++) {
        vertMin = Math.min(dfsWithMemHelperI(width - i, height, cache) + 
dfsWithMemHelperI(i, height, cache), vertMin);
        }
    for (int j = 1; j <= height / 2; j++) {
        horMin = Math.min(dfsWithMemHelperI(width, height - j, cache) + 
dfsWithMemelperI(width, j, cache), horMin);
    }
    int res = Math.min(vertMin, horMin);
    cache.put(key, res);
    return res;
}



Sol3 : DFS apply memorization: 2D matrix version

public int dfsWithMemII(int width, int height) {
    int[][] dp = new int[width + 1][height + 1];
    return dfsWithMemHelperII(width, height, dp);
}
private int dfsWithMemHelperII(int width, int height, int[][] dp) {
    if (width % height == 0) {
        return width / height;
    }
    if (height % width == 0) {
        return height / width;
    }
    if (dp[width][height] > 0) {
        return dp[width][height];
    }
    int vertMin = Integer.MAX_VALUE;
    int horMin = Integer.MAX_VALUE;
    for (int i = 1; i <= width / 2; i++) {
        horMin = Math.min(dfsWithMemHelperII(i, height, dp) + 
dfsWithMemHelperII(width - i,  height, dp), horMin);
    }
    for (int j = 1; j <= height / 2; j++) {
        vertMin = Math.min(dfsWithMemHelperII(width, j, dp) + 
dfsWithMemHelperII(width, height - j, dp), vertMin);
    }
    dp[width][height] = Math.min(horMin, vertMin);
    return dp[width][height];
}

Sol4 : DP

a. definition of DP state: using 2D dp, dp[i][j] represents the minimum number of squares

can be cut from paper with size i x j

note: dp[i][j] = dp[j][i] according to the physical meaning

b. induction rule: dp[i][j] = min(horizontal min, vertical min)

   Try all possible horizontal and vertically splits

   horizontal min = dp[i - x][j] + dp[x][j]  x from [1, i / 2] (including)

               vertically min = dp[i][j - x] + dp[i][x]  x from [1, j / 2] (including)

c. base case: dp[i][i] = 1     i from [1, min(W, H)]

d. result: dp[W][H]

e. filling order: from left to right, up to bottom because we need to know all left and up values

f. optimization on space and time:

 

   0     1 2         3 4      

0

0

0

0

0

0

1

2

3

4

0

2

1

3

2

0

3

3

1

4

 

 

   

dp[3][4] = min(dp[1][4] + dp[2][4], dp[3][1] + dp[3][3], dp[3][2] + dp[3][2])

public int MinPaperCut(int width, int height) {
    int[][] dp = new int[width + 1][height + 1];
    for (int x = 1; x < dp.length; x++) {
        for (int y = 1; y < dp[0].length; y++) {
            if (x == y) { //base case
                dp[x][y] = 1;
            } else {
                int vertical_min = Integer.MAX_VALUE;
                int horizontal_min = Integer.MAX_VALUE;
                for (int i = 1; i <= x / 2; i++) {
                    horizontal_min = Math.min(horizontal_min, 
                                              dp[x - i][y] + dp[i][y]);
                }
                for (int i = 1; i <= y / 2; i++) {
                    vertical_min = Math.min(vertical_min, 
                                            dp[x][y - i] + dp[x][i]);
                }
                dp[x][y] = Math.min(horizontal_min, vertical_min);
            }
        }
    }
    return dp[width][height];
}
Time: O(WH * max(W, H)) since three for loops => WH * (W+H)
Space: O(WH) since 2D array used

2. 

 

有一个隧道,有一些雷达,雷达有不同的半径,问小车能否通过


————————————————————————x  5

              .


                       

————————————————————————y  0



vertex: 雷达 (i, j) + r

neighbors: 跟雷达有overlap的所有雷达们



在y的维度上需要一个interval(m, n): m = j-r,  n = j+r

m >= x && n <= y 的时候: 小车不能通过

result boolean: yes or no pass the sui dao



connected component => 有重叠的雷达们 => interval (m, n) to represent the size of cc

List<Radius> radius;
UnionFind uf = new UnionFind();
Map<Radius, List<Radius>> neighbors = helper(radius);  // pre precessing : O(n)
for (Radius r : radius) { // O(n)
    for (Radius nei : neighbors.get(r)) { // O(1)
        uf.union(nei, r); // ranking + path compression O(c) => O(1)
        // update size of connected component
        if (uf.cc.m >= x && uf.cc.m <= y) {
            return false;
}
}
}
return true;

是男人就跳问题 best first search 
给一个二维坐标平面和一个起始点,从这点开始垂直下跳,下面有若干水平挡板,位置长度会在 input里给,板的形式是(x, y, distance),当跳到挡板上时,可以选择走到挡板的左端或者右端, 然后继续垂直下跳,直到落地位置,求从开始到落地需要走过的路程最短是多少。



                     5


                   |____|(i,j)    2,1                    a


    i - ib                  ib + d - i

                    1 |__|(i, jb)__________|2     b(ib, jb, d)         ____ d

 

                20                    10

___________________________|    c


__________________________________________地面

(i, j) + total cost reacing (i, j) pos

 

(i, j), cost


nei.cost = cur.cost + i - ib  = cur cost + cur 到nei cost == nei cost

i, j + 10


(x, y, distance) => x是板子的左端点, y是板子的垂直位置,右端点 = x + distance



y -> y0表示左端点, y1表示右端点

a d b c          a b d c

Queue<Point> q = new LinkedList<>();

q.offer(new Point(i, j, 0));

while (!q.isEmpty()) {

Point cur = q.poll();

for () {

 

}

}


















是男人就跳问题
给一个二维坐标平面和一个起始点,从这点开始垂直下跳,下面有若干水平挡板,位置长度会在 input里给,板的形式是(x, y, distance),当跳到挡板上时,可以选择走到挡板的左端或者右端, 然后继续垂直下跳,直到落地位置,求从开始到落地需要走过的路程最短是多少。



                     5


                   |____|(i,j)    2,1                    a


    i - ib                  ib + d - i

                    1 |__|(i, jb)__________|2     b(ib, jb, d)         ____ d

 

                20                    10

___________________________|    c


__________________________________________地面



(i, j) + total cost reacing (i, j) pos


(i, j), cost


nei.cost = cur.cost + i - ib  = cur cost + cur 到nei cost == nei cost

i, j + 10


(x, y, distance) => x是板子的左端点, y是板子的垂直位置,右端点 = x + distance



y -> y0表示左端点, y1表示右端点

a d b c          a b d c


Queue<Point> q = new LinkedList<>();

q.offer(new Point(i, j, 0));

while (!q.isEmpty()) {

Point cur = q.poll();

for () {

 

}

}

猜你喜欢

转载自www.cnblogs.com/tobeabetterpig/p/9646253.html