|
| 1 | +package highFrequencyLeetcode.leetcode_42; |
| 2 | + |
| 3 | +import java.util.Stack; |
| 4 | + |
| 5 | +/** |
| 6 | + * Hard |
| 7 | + * (注解文档查看快捷键 选中类名或方法名 按ctrl + Q) |
| 8 | + * <p> |
| 9 | + * 思维全过程记录方案:<p> |
| 10 | + * 1 背基础结构和算法 | 记录在课程笔记<p> |
| 11 | + * 2 看题 -> 悟题 思考过程 | 记录在wiki<p> |
| 12 | + * 3 悟题 -> 写题 实现难点 | 记录在代码注解<p> |
| 13 | + * 4 写题 -> 优化 多种解法 | 记录在leetcode提交 |
| 14 | + * <p> |
| 15 | + * 题解方案topics: |
| 16 | + * array、双指针、stack |
| 17 | + * |
| 18 | + * @author li tong |
| 19 | + * @date 2019/6/3 10:18 |
| 20 | + * @see Object |
| 21 | + * @since 1.0 |
| 22 | + */ |
| 23 | +public class LeetCode_42_025 { |
| 24 | + |
| 25 | + public static void main(String[] args) { |
| 26 | + int[] testcase = new int[]{2, 0, 2}; // 0, 2, 0 |
| 27 | + System.out.println("FORCE=" + bruteForce(testcase)); |
| 28 | + System.out.println(); |
| 29 | + System.out.println("DP_ONE=" + dpOne(testcase)); |
| 30 | + System.out.println(); |
| 31 | + System.out.println("DP_TWO=" + dpTwo(testcase)); |
| 32 | + System.out.println(); |
| 33 | + System.out.println("STACK=" + stack(testcase)); |
| 34 | + } |
| 35 | + |
| 36 | + /** |
| 37 | + * 解法1 暴力求解<p> |
| 38 | + * 看题解,提取主干思路:<p> |
| 39 | + * 从左向右遍历整个下标 每个下标从左、右分别找出最高的杆子<p> |
| 40 | + * 自己学习 思考 实践时的难点(难点是如何突破的见wiki):<p> |
| 41 | + * 看了题解才知道居然要从左、右分头遍历,这个一开始是想不到的 |
| 42 | + * |
| 43 | + * @param columns |
| 44 | + * @return |
| 45 | + */ |
| 46 | + public static int bruteForce(int[] columns) { |
| 47 | + int result = 0, length = columns.length; |
| 48 | + for (int i = 0; i < length; i++) { |
| 49 | + // Caution 1 声明位置在for循环里面而不是外面 |
| 50 | + int maxl = 0, maxr = 0; |
| 51 | + for (int j = i; j < length; j++) { |
| 52 | + maxr = Math.max(maxr, columns[j]); |
| 53 | + } |
| 54 | + for (int j = i; j >= 0; j--) { |
| 55 | + maxl = Math.max(maxl, columns[j]); |
| 56 | + } |
| 57 | + result += Math.min(maxl, maxr) - columns[i]; |
| 58 | + } |
| 59 | + return result; |
| 60 | + } |
| 61 | + |
| 62 | + /** |
| 63 | + * 解法2 DP求解<p> |
| 64 | + * 看题解,提取主干思路:<p> |
| 65 | + * 在解法一的基础上 由于是求极值问题 考虑DP<p> |
| 66 | + * 自己学习 思考 实践时的难点(难点是如何突破的见wiki):<p> |
| 67 | + * 由于在暴力求解中DP递推方程已得出,现在需要思考<p> |
| 68 | + * 1 如何用dp的方式遍历 还是和暴力一样吗?<p> |
| 69 | + * 2 如何归并?<p> |
| 70 | + * 看完样例代码,发现遍历的顺序和暴力是有区别的,为什么?<p> |
| 71 | + * |
| 72 | + * @param columns |
| 73 | + * @return |
| 74 | + */ |
| 75 | + public static int dpOne(int[] columns) { |
| 76 | + // Caution 1 if length == 0 |
| 77 | + if (columns.length == 0) { |
| 78 | + return 0; |
| 79 | + } |
| 80 | + int result = 0, length = columns.length; |
| 81 | + int[] maxl = new int[columns.length]; |
| 82 | + int[] maxr = new int[columns.length]; |
| 83 | + maxl[0] = columns[0]; |
| 84 | + // Caution 2 length - 1 |
| 85 | + maxr[length - 1] = columns[length - 1]; |
| 86 | + for (int i = 1; i < length; i++) { |
| 87 | + // Caution 3 i - 1 i + 1 |
| 88 | + maxl[i] = Math.max(maxl[i - 1], columns[i]); |
| 89 | + } |
| 90 | + // Caution 4 length - 2 |
| 91 | + for (int i = length - 2; i >= 0; i--) { |
| 92 | + maxr[i] = Math.max(maxr[i + 1], columns[i]); |
| 93 | + } |
| 94 | + for (int i = 1; i < columns.length - 1; i++) { |
| 95 | + result += Math.min(maxl[i], maxr[i]) - columns[i]; |
| 96 | + } |
| 97 | + return result; |
| 98 | + } |
| 99 | + |
| 100 | + /** |
| 101 | + * 解法3 DP求解 单次遍历<p> |
| 102 | + * 看题解,提取主干思路:<p> |
| 103 | + * 双指针替换两次遍历<p> |
| 104 | + * 自己学习 思考 实践时的难点(难点是如何突破的见wiki):<p> |
| 105 | + * 虽然用dp存储了一些计算结果,但还是和暴力一样遍历了两次,如何减少循环次数?<p> |
| 106 | + * |
| 107 | + * @param columns |
| 108 | + * @return |
| 109 | + */ |
| 110 | + public static int dpTwo(int[] columns) { |
| 111 | + int result = 0, left = 0, right = columns.length - 1; |
| 112 | + int maxl = 0, maxr = 0; |
| 113 | + while (left < right) { |
| 114 | + if (columns[left] < columns[right]) { |
| 115 | + if (columns[left] >= maxl) { |
| 116 | + maxl = columns[left]; |
| 117 | + } else { |
| 118 | + result += (maxl - columns[left]); |
| 119 | + } |
| 120 | + ++left; |
| 121 | + } else { |
| 122 | + if (columns[right] >= maxr) { |
| 123 | + maxr = columns[right]; |
| 124 | + } else { |
| 125 | + result += (maxr - columns[right]); |
| 126 | + } |
| 127 | + --right; |
| 128 | + } |
| 129 | + } |
| 130 | + return result; |
| 131 | + } |
| 132 | + |
| 133 | + /** |
| 134 | + * 解法4 栈解法<p> |
| 135 | + * 看题解,提取主干思路:<p> |
| 136 | + * 使用栈标记低谷和两界<p> |
| 137 | + * 自己学习 思考 实践时的难点(难点是如何突破的见wiki):<p> |
| 138 | + * 1 很难想到<p> |
| 139 | + * 2 即便看了答案也是很难理解<p> |
| 140 | + * |
| 141 | + * @param columns |
| 142 | + * @return |
| 143 | + */ |
| 144 | + public static int stack(int[] columns) { |
| 145 | + int result = 0, cursor = 0, length = columns.length; |
| 146 | + Stack<Integer> stack = new Stack<>(); |
| 147 | + while (cursor < length) { |
| 148 | +// System.out.print("CURSOR" + cursor + "->"); |
| 149 | +// System.out.print("COLUMN"); |
| 150 | + if (stack.isEmpty() || columns[cursor] < columns[stack.peek()]) { |
| 151 | +// System.out.println(cursor + "+"); |
| 152 | + stack.push(cursor++); |
| 153 | + } else { |
| 154 | + int bottom = stack.pop(); |
| 155 | +// System.out.print(bottom + "- RESULT+"); |
| 156 | + if (stack.isEmpty()) { |
| 157 | +// System.out.println(0); |
| 158 | + continue; |
| 159 | + } |
| 160 | + int left = stack.peek(); |
| 161 | + int square = (Math.min(columns[left], columns[cursor]) - columns[bottom]) * (cursor - left - 1); |
| 162 | +// System.out.println(square); |
| 163 | + result += square; |
| 164 | + } |
| 165 | + } |
| 166 | + return result; |
| 167 | + } |
| 168 | + |
| 169 | +} |
0 commit comments