From af62d25da2a14db1c86b1398481d840eabda9422 Mon Sep 17 00:00:00 2001 From: Dmytro Horkhover Date: Thu, 16 Jul 2020 19:27:29 +0300 Subject: [PATCH 1/2] dev --- .../org/gd/leetcode/p0741/SimplePoint.java | 40 +++++++ .../java/org/gd/leetcode/p0741/Solution.java | 111 ++++++++++++++++++ .../org/gd/leetcode/p0741/SolutionTest.java | 39 ++++++ 3 files changed, 190 insertions(+) create mode 100644 src/main/java/org/gd/leetcode/p0741/SimplePoint.java create mode 100644 src/main/java/org/gd/leetcode/p0741/Solution.java create mode 100644 src/test/java/org/gd/leetcode/p0741/SolutionTest.java diff --git a/src/main/java/org/gd/leetcode/p0741/SimplePoint.java b/src/main/java/org/gd/leetcode/p0741/SimplePoint.java new file mode 100644 index 00000000..7db81b32 --- /dev/null +++ b/src/main/java/org/gd/leetcode/p0741/SimplePoint.java @@ -0,0 +1,40 @@ +package org.gd.leetcode.p0741; + +class SimplePoint { + + private int value; + private int sum; + private SimplePoint prev; + + SimplePoint(int value) { this.value = sum = value; } + + int value() { return value; } + + int pathSum() { return sum; } + + boolean isBlock() { return value == -1; } + + void addPrev(SimplePoint prev) { + if (prev.value == -1) + return; + + this.prev = prev; + sum += prev.pathSum(); + } + + void resetAll() { + sum = value = 0; + if (prev != null) { + prev.resetAll(); + prev = null; + } + } + + @Override + public String toString() { + String s = String.format("(%s)", value == -1 ? "block" : value); + if (prev != null) + s = String.format("%s->%s", prev.toString(), s); + return s; + } +} diff --git a/src/main/java/org/gd/leetcode/p0741/Solution.java b/src/main/java/org/gd/leetcode/p0741/Solution.java new file mode 100644 index 00000000..22224d0f --- /dev/null +++ b/src/main/java/org/gd/leetcode/p0741/Solution.java @@ -0,0 +1,111 @@ +package org.gd.leetcode.p0741; + +import org.gd.leetcode.common.LeetCode; + +/** + * https://leetcode.com/problems/cherry-pickup/ + * + * @author Horkhover D. + * @since 2020-07-16 + */ +@LeetCode( + name = "Cherry Pickup", + difficulty = LeetCode.Level.HARD, + state = LeetCode.State.TODO, + tags = LeetCode.Tags.DYNAMIC_PROGRAMMING +) +class Solution { + + private SimplePoint[][] grid; + private int rows, cols; + + private void reset(int[][] grid) { + rows = grid.length; + cols = grid[0].length; + this.grid = new SimplePoint[rows][cols]; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + this.grid[row][col] = new SimplePoint(grid[row][col]); + } + } + } + + private int forward() { + for (int row = 1; row < rows && !grid[row][0].isBlock(); row++) + grid[row][0].addPrev(grid[row - 1][0]); + + for (int col = 1; col < cols && !grid[0][col].isBlock(); col++) + grid[0][col].addPrev(grid[0][col - 1]); + + for (int row = 1; row < rows; row++) { + for (int col = 1; col < cols; col++) { + + if (grid[row][col].isBlock()) + continue; + + final SimplePoint up = grid[row - 1][col]; + final SimplePoint left = grid[row][col - 1]; + + if (up.isBlock()) { + if (!left.isBlock()) + grid[row][col].addPrev(left); + } else if (left.isBlock()) { + grid[row][col].addPrev(up); + } else if (up.value() > left.value()) { + grid[row][col].addPrev(up); + } else { + grid[row][col].addPrev(left); + } + } + } + + SimplePoint point = grid[rows - 1][cols - 1]; + int value = point.pathSum(); + point.resetAll(); + return value; + } + + private int backward() { + + for (int row = rows - 2; row >= 0 && !grid[row][0].isBlock(); row--) + grid[row][0].addPrev(grid[row + 1][0]); + + for (int col = cols - 2; col >= 0 && !grid[0][col].isBlock(); col--) + grid[0][col].addPrev(grid[0][col + 1]); + + for (int row = rows - 2; row >= 0; row--) { + for (int col = cols - 2; col >= 0; col--) { + if (grid[row][col].isBlock()) + continue; + + SimplePoint right = grid[row][col + 1]; + SimplePoint down = grid[row + 1][col]; + if (right.isBlock()) { + if (!down.isBlock()) + grid[row][col].addPrev(down); + } else if (down.isBlock()) { + grid[row][col].addPrev(right); + } else if (right.value() > down.value()) { + grid[row][col].addPrev(right); + } else { + grid[row][col].addPrev(down); + } + } + } + + SimplePoint point = grid[0][0]; + int value = point.pathSum(); + point.resetAll(); + return value; + } + + public int cherryPickup(int[][] intsGrid) { + reset(intsGrid); + + int forward = forward(); + int backward = backward(); + + return forward + backward; + } + +} diff --git a/src/test/java/org/gd/leetcode/p0741/SolutionTest.java b/src/test/java/org/gd/leetcode/p0741/SolutionTest.java new file mode 100644 index 00000000..9e7127b2 --- /dev/null +++ b/src/test/java/org/gd/leetcode/p0741/SolutionTest.java @@ -0,0 +1,39 @@ +package org.gd.leetcode.p0741; + +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Test for {@link Solution} + * + * @author Horkhover D. + * @since 2020-07-16.07.2020 + */ +class SolutionTest { + + private static Stream args() { + return Stream.of( + Arguments.of(new int[][]{ + {0, 1, -1}, + {1, 0, -1}, + {1, 1, 1}}, 5), + Arguments.of(new int[][]{ + {0, 1, -1, 1}, + {1, 0, -1, 1}, + {1, 1, 1, 0}}, 5) + ); + } + + @ParameterizedTest + @MethodSource("args") + @DisplayName("CherryPickup") + void test_CherryPickup(int[][] grid, int expected) { + assertEquals(expected, new Solution().cherryPickup(grid)); + } +} \ No newline at end of file From bb61b294492fccfb9113d47feb35f674e2f2b2e6 Mon Sep 17 00:00:00 2001 From: Dmytro Horkhover Date: Thu, 16 Jul 2020 20:47:11 +0300 Subject: [PATCH 2/2] dev --- src/main/java/org/gd/common/Commons.java | 2 +- .../org/gd/leetcode/p0741/BlockPoint.java | 39 +++++++++ .../java/org/gd/leetcode/p0741/Point.java | 25 ++++++ .../java/org/gd/leetcode/p0741/PointImpl.java | 80 +++++++++++++++++++ .../org/gd/leetcode/p0741/SimplePoint.java | 40 ---------- .../java/org/gd/leetcode/p0741/Solution.java | 62 +++++++------- .../org/gd/leetcode/p0741/SolutionTest.java | 22 ++++- 7 files changed, 199 insertions(+), 71 deletions(-) create mode 100644 src/main/java/org/gd/leetcode/p0741/BlockPoint.java create mode 100644 src/main/java/org/gd/leetcode/p0741/Point.java create mode 100644 src/main/java/org/gd/leetcode/p0741/PointImpl.java delete mode 100644 src/main/java/org/gd/leetcode/p0741/SimplePoint.java diff --git a/src/main/java/org/gd/common/Commons.java b/src/main/java/org/gd/common/Commons.java index b0e3536e..56216f00 100644 --- a/src/main/java/org/gd/common/Commons.java +++ b/src/main/java/org/gd/common/Commons.java @@ -357,7 +357,7 @@ public static boolean isPowerOfTwo(long n) { } public static int digitsCount(int num) { - return num == 0 ? 1 : (int) (Math.log10(Math.abs(num)) + 1); + return num == 0 ? 1 : (int) (Math.log10(Math.abs(num)) + (num < 0 ? 2 : 1)); } public static int maxDigitsCount(int[] arr) { diff --git a/src/main/java/org/gd/leetcode/p0741/BlockPoint.java b/src/main/java/org/gd/leetcode/p0741/BlockPoint.java new file mode 100644 index 00000000..29a63125 --- /dev/null +++ b/src/main/java/org/gd/leetcode/p0741/BlockPoint.java @@ -0,0 +1,39 @@ +package org.gd.leetcode.p0741; + +public class BlockPoint implements Point { + + static final org.gd.leetcode.p0741.BlockPoint INSTANCE = new org.gd.leetcode.p0741.BlockPoint(); + + private BlockPoint() {} + + @Override + public int value() { return -1; } + + @Override + public int pathSum() { + throw new UnsupportedOperationException(new String(new char[]{175, 92, 95, 40, 12_484, 41, 95, 47, 175})); + } + + @Override + public boolean isBlock() { return true; } + + @Override + public boolean isValid() { return false; } + + @Override + public void addPrev(Point prev) { + throw new UnsupportedOperationException(new String(new char[]{175, 92, 95, 40, 12_484, 41, 95, 47, 175})); + } + + @Override + public void reset() {} + + @Override + public void erase() {} + + @Override + public String path() { return ""; } + + @Override + public String toString() { return "(block)"; } +} diff --git a/src/main/java/org/gd/leetcode/p0741/Point.java b/src/main/java/org/gd/leetcode/p0741/Point.java new file mode 100644 index 00000000..20d5846b --- /dev/null +++ b/src/main/java/org/gd/leetcode/p0741/Point.java @@ -0,0 +1,25 @@ +package org.gd.leetcode.p0741; + +interface Point { + + static Point of(int row, int col, int value) { + return value == -1 ? BlockPoint.INSTANCE : new PointImpl(row, col, value); + } + + int value(); + + int pathSum(); + + boolean isBlock(); + + boolean isValid(); + + void addPrev(Point prev); + + void reset(); + + void erase(); + + String path(); + +} diff --git a/src/main/java/org/gd/leetcode/p0741/PointImpl.java b/src/main/java/org/gd/leetcode/p0741/PointImpl.java new file mode 100644 index 00000000..8f7755e1 --- /dev/null +++ b/src/main/java/org/gd/leetcode/p0741/PointImpl.java @@ -0,0 +1,80 @@ +package org.gd.leetcode.p0741; + +public class PointImpl implements Point { + + private final int row, col; + + private int value; + private int sum; + private Point prev; + private Boolean valid; + + PointImpl(int row, int col, int value) { + this.row = row; + this.col = col; + this.value = value; + sum = value; + } + + @Override + public int value() { return value; } + + @Override + public int pathSum() { return sum; } + + @Override + public boolean isBlock() { return false; } + + @Override + public boolean isValid() { + if (valid != null) + return valid; + + if (row == 0 && col == 0) + return valid = true; + + if (prev != null) + return valid = prev.isValid(); + + return valid = false; + } + + @Override + public void addPrev(Point prev) { + if (prev.isBlock()) return; + reset(); + this.prev = prev; + sum += prev.pathSum(); + isValid(); + } + + @Override + public void reset() { + sum = value; + if (prev != null) { + prev.reset(); + prev = null; + } + } + + @Override + public void erase() { + value = 0; + sum = 0; + if (prev != null) { + prev.erase(); + prev = null; + } + } + + @Override + public String path() { + String s = String.format("(%d;%d)", row, col); + if (prev != null) + s = String.format("%s->%s", prev.path(), s); + return s; + } + + @Override + public String toString() { return "" + value; } +} diff --git a/src/main/java/org/gd/leetcode/p0741/SimplePoint.java b/src/main/java/org/gd/leetcode/p0741/SimplePoint.java deleted file mode 100644 index 7db81b32..00000000 --- a/src/main/java/org/gd/leetcode/p0741/SimplePoint.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.gd.leetcode.p0741; - -class SimplePoint { - - private int value; - private int sum; - private SimplePoint prev; - - SimplePoint(int value) { this.value = sum = value; } - - int value() { return value; } - - int pathSum() { return sum; } - - boolean isBlock() { return value == -1; } - - void addPrev(SimplePoint prev) { - if (prev.value == -1) - return; - - this.prev = prev; - sum += prev.pathSum(); - } - - void resetAll() { - sum = value = 0; - if (prev != null) { - prev.resetAll(); - prev = null; - } - } - - @Override - public String toString() { - String s = String.format("(%s)", value == -1 ? "block" : value); - if (prev != null) - s = String.format("%s->%s", prev.toString(), s); - return s; - } -} diff --git a/src/main/java/org/gd/leetcode/p0741/Solution.java b/src/main/java/org/gd/leetcode/p0741/Solution.java index 22224d0f..09727d35 100644 --- a/src/main/java/org/gd/leetcode/p0741/Solution.java +++ b/src/main/java/org/gd/leetcode/p0741/Solution.java @@ -16,21 +16,22 @@ ) class Solution { - private SimplePoint[][] grid; + private Point[][] grid; private int rows, cols; private void reset(int[][] grid) { rows = grid.length; cols = grid[0].length; - this.grid = new SimplePoint[rows][cols]; + this.grid = new Point[rows][cols]; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { - this.grid[row][col] = new SimplePoint(grid[row][col]); + this.grid[row][col] = Point.of(row, col, grid[row][col]); } } } private int forward() { + for (int row = 1; row < rows && !grid[row][0].isBlock(); row++) grid[row][0].addPrev(grid[row - 1][0]); @@ -43,12 +44,13 @@ private int forward() { if (grid[row][col].isBlock()) continue; - final SimplePoint up = grid[row - 1][col]; - final SimplePoint left = grid[row][col - 1]; + final Point up = grid[row - 1][col]; + final Point left = grid[row][col - 1]; if (up.isBlock()) { - if (!left.isBlock()) + if (!left.isBlock()) { grid[row][col].addPrev(left); + } } else if (left.isBlock()) { grid[row][col].addPrev(up); } else if (up.value() > left.value()) { @@ -59,53 +61,57 @@ private int forward() { } } - SimplePoint point = grid[rows - 1][cols - 1]; - int value = point.pathSum(); - point.resetAll(); - return value; + Point point = grid[rows - 1][cols - 1]; + if (point.isValid()) { + int value = point.pathSum(); + point.erase(); + return value; + } + + return -1; } private int backward() { - for (int row = rows - 2; row >= 0 && !grid[row][0].isBlock(); row--) - grid[row][0].addPrev(grid[row + 1][0]); + for (int row = rows - 2; row >= 0 && !grid[row][cols - 1].isBlock(); row--) + grid[row][cols - 1].addPrev(grid[row + 1][cols - 1]); - for (int col = cols - 2; col >= 0 && !grid[0][col].isBlock(); col--) - grid[0][col].addPrev(grid[0][col + 1]); + for (int col = cols - 2; col >= 0 && !grid[rows - 1][col].isBlock(); col--) + grid[rows - 1][col].addPrev(grid[rows - 1][col + 1]); for (int row = rows - 2; row >= 0; row--) { for (int col = cols - 2; col >= 0; col--) { - if (grid[row][col].isBlock()) + Point current = grid[row][col]; + current.reset(); + if (current.isBlock()) continue; - SimplePoint right = grid[row][col + 1]; - SimplePoint down = grid[row + 1][col]; + Point right = grid[row][col + 1]; + Point down = grid[row + 1][col]; if (right.isBlock()) { if (!down.isBlock()) - grid[row][col].addPrev(down); + current.addPrev(down); } else if (down.isBlock()) { - grid[row][col].addPrev(right); + current.addPrev(right); } else if (right.value() > down.value()) { - grid[row][col].addPrev(right); + current.addPrev(right); } else { - grid[row][col].addPrev(down); + current.addPrev(down); } } } - SimplePoint point = grid[0][0]; - int value = point.pathSum(); - point.resetAll(); - return value; + return grid[0][0].pathSum(); } public int cherryPickup(int[][] intsGrid) { reset(intsGrid); - int forward = forward(); - int backward = backward(); + final int forward = forward(); + if (forward == -1) + return 0; - return forward + backward; + return forward + backward(); } } diff --git a/src/test/java/org/gd/leetcode/p0741/SolutionTest.java b/src/test/java/org/gd/leetcode/p0741/SolutionTest.java index 9e7127b2..ce0eb807 100644 --- a/src/test/java/org/gd/leetcode/p0741/SolutionTest.java +++ b/src/test/java/org/gd/leetcode/p0741/SolutionTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import java.util.List; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -15,14 +16,31 @@ * @author Horkhover D. * @since 2020-07-16.07.2020 */ +@DisplayName("LeetCode #741: Cherry Pickup") class SolutionTest { - private static Stream args() { - return Stream.of( + private static List args() { + return List.of( + + Arguments.of(new int[][]{ + {1, 1, 1, 1, 0, 0, 0}, + {0, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 1, 0, 0, 1}, + {1, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 1}}, 15), + + Arguments.of(new int[][]{ + {1, 1, -1}, + {1, -1, 1}, + {-1, 1, 1}}, 0), + Arguments.of(new int[][]{ {0, 1, -1}, {1, 0, -1}, {1, 1, 1}}, 5), + Arguments.of(new int[][]{ {0, 1, -1, 1}, {1, 0, -1, 1},