forked from Turingfly/cracking-the-coding-interview
-
Notifications
You must be signed in to change notification settings - Fork 0
/
StackOfBoxes.java
160 lines (143 loc) · 3.94 KB
/
StackOfBoxes.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package chapter08RecursionAndDynamicProgramming;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
*
* Problem: You have a stack of n boxes, with width Wi, height Hi, and depth Di.
* The boxes cannot be rotated and can only be stacked on top of one another if
* each each box in the stack is strictly larger than the box above it in width,
* height, and depth. Implement a method to compute the height of the tallest
* possible stack. The height of a stack is the sum of the heights of each box.
*
*/
public class StackOfBoxes {
/**
* Method 1:
*
*/
public int createStack1(List<Box> boxes) {
Comparator<Box> byHeight = new Comparator<Box>() {
@Override
public int compare(Box a, Box b) {
return b.height - a.height;
}
};
Collections.sort(boxes, byHeight);
int max = 0;
for (int i = 0; i < boxes.size(); i++) {
int height = createStack1(boxes, i);
max = Math.max(max, height);
}
return max;
}
public int createStack1(List<Box> boxes, int bottomIndex) {
Box bottom = boxes.get(bottomIndex);
int max = 0;
for (int i = bottomIndex + 1; i < boxes.size(); i++) {
if (boxes.get(i).canBeAbove(bottom)) {
int height = createStack1(boxes, i);
max = Math.max(height, max);
}
}
max += bottom.height;
return max;
}
/**
* Method 2: Cache results using memorization
*/
public static int createStack2(List<Box> boxes) {
Comparator<Box> byHeight = new Comparator<Box>() {
@Override
public int compare(Box a, Box b) {
return b.height - a.height;
}
};
Collections.sort(boxes, byHeight);
int max = 0;
int[] stackMap = new int[boxes.size()];
for (int i = 0; i < boxes.size(); i++) {
int height = createStack2(boxes, i, stackMap);
max = Math.max(max, height);
}
return max;
}
public static int createStack2(List<Box> boxes, int bottomIndex, int[] stackMap) {
if (bottomIndex < boxes.size() && stackMap[bottomIndex] > 0) {
return stackMap[bottomIndex];
}
Box bottom = boxes.get(bottomIndex);
int max = 0;
for (int i = bottomIndex + 1; i < boxes.size(); i++) {
if (boxes.get(i).canBeAbove(bottom)) {
int height = createStack2(boxes, i, stackMap);
max = Math.max(height, max);
}
}
max += bottom.height;
stackMap[bottomIndex] = max;
return max;
}
/**
*
* Method 3: Think about the recursive algorithm as making a choice, at each
* step, whether to put a particular box in the stack.
*/
public static int createStack3(List<Box> boxes) {
Comparator<Box> byHeight = new Comparator<Box>() {
@Override
public int compare(Box a, Box b) {
return b.height - a.height;
}
};
Collections.sort(boxes, byHeight);
int[] stackMap = new int[boxes.size()];
return createStack3(boxes, null, 0, stackMap);
}
public static int createStack3(List<Box> boxes, Box bottom, int offset, int[] stackMap) {
if (offset >= boxes.size()) {
return 0;
}
/* height with this bottom */
Box newBottom = boxes.get(offset);
int heightWithBottom = 0;
if (bottom == null || newBottom.canBeAbove(bottom)) {
if (stackMap[offset] == 0) {
stackMap[offset] = createStack3(boxes, newBottom, offset + 1, stackMap);
stackMap[offset] += newBottom.height;
}
heightWithBottom = stackMap[offset];
}
/* without this bottom */
int heightWithoutBottom = createStack3(boxes, bottom, offset + 1, stackMap);
return Math.max(heightWithBottom, heightWithoutBottom);
}
}
class Box {
public int width;
public int height;
public int depth;
public Box(int w, int h, int d) {
width = w;
height = h;
depth = d;
}
public boolean canBeUnder(Box b) {
if (width > b.width && height > b.height && depth > b.depth) {
return true;
}
return false;
}
public boolean canBeAbove(Box b) {
if (b == null) {
return true;
}
if (width < b.width && height < b.height && depth < b.depth) {
return true;
}
return false;
}
public String toString() {
return "Box(" + width + "," + height + "," + depth + ")";
}
}