Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/java/org/gd/common/Commons.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/org/gd/leetcode/p0741/BlockPoint.java
Original file line number Diff line number Diff line change
@@ -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)"; }
}
25 changes: 25 additions & 0 deletions src/main/java/org/gd/leetcode/p0741/Point.java
Original file line number Diff line number Diff line change
@@ -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();

}
80 changes: 80 additions & 0 deletions src/main/java/org/gd/leetcode/p0741/PointImpl.java
Original file line number Diff line number Diff line change
@@ -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; }
}
117 changes: 117 additions & 0 deletions src/main/java/org/gd/leetcode/p0741/Solution.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
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 Point[][] grid;
private int rows, cols;

private void reset(int[][] grid) {
rows = grid.length;
cols = grid[0].length;
this.grid = new Point[rows][cols];
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; 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]);

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 Point up = grid[row - 1][col];
final Point 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);
}
}
}

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][cols - 1].isBlock(); row--)
grid[row][cols - 1].addPrev(grid[row + 1][cols - 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--) {
Point current = grid[row][col];
current.reset();
if (current.isBlock())
continue;

Point right = grid[row][col + 1];
Point down = grid[row + 1][col];
if (right.isBlock()) {
if (!down.isBlock())
current.addPrev(down);
} else if (down.isBlock()) {
current.addPrev(right);
} else if (right.value() > down.value()) {
current.addPrev(right);
} else {
current.addPrev(down);
}
}
}

return grid[0][0].pathSum();
}

public int cherryPickup(int[][] intsGrid) {
reset(intsGrid);

final int forward = forward();
if (forward == -1)
return 0;

return forward + backward();
}

}
57 changes: 57 additions & 0 deletions src/test/java/org/gd/leetcode/p0741/SolutionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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.List;
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
*/
@DisplayName("LeetCode #741: Cherry Pickup")
class SolutionTest {

private static List<Arguments> 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},
{1, 1, 1, 0}}, 5)
);
}

@ParameterizedTest
@MethodSource("args")
@DisplayName("CherryPickup")
void test_CherryPickup(int[][] grid, int expected) {
assertEquals(expected, new Solution().cherryPickup(grid));
}
}