Skip to content

Commit 7e601cc

Browse files
authored
Merge pull request #70 from Jer3myYu/java-solutions-dynamic-programming
Java Chapter 15: Dynamic Programming
2 parents 7f3de4a + b0d5bc9 commit 7e601cc

20 files changed

+527
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
public class ClimbingStairsBottomUp {
2+
public int climbingStairsBottomUp(int n) {
3+
if (n <= 2) {
4+
return n;
5+
}
6+
int[] dp = new int[n + 1];
7+
// Base cases.
8+
dp[1] = 1;
9+
dp[2] = 2;
10+
// Starting from step 3, calculate the number of ways to reach each
11+
// step until the n-th step.
12+
for (int i = 3; i < n + 1; i++) {
13+
dp[i] = dp[i - 1] + dp[i - 2];
14+
}
15+
return dp[n];
16+
}
17+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
public record ClimbingStairsBottomUpOptimized() {
2+
public int climbingStairsBottomUpOptimized(int n) {
3+
if (n <= 2) {
4+
return n;
5+
}
6+
// Set 'oneStepBefore' and 'twoStepsBefore' as the base cases.
7+
int oneStepBefore = 2;
8+
int twoStepsBefore = 1;
9+
for (int i = 3; i < n + 1; i++) {
10+
// Calculate the number of ways to reach the current step.
11+
int current = oneStepBefore + twoStepsBefore;
12+
// Update the values for the next iteration.
13+
twoStepsBefore = oneStepBefore;
14+
oneStepBefore = current;
15+
}
16+
return oneStepBefore;
17+
}
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import java.util.HashMap;
2+
import java.util.Map;
3+
4+
public class ClimbingStairsTopDown {
5+
Map<Integer, Integer> memo = new HashMap<>();
6+
7+
public int climbingStairsTopDown(int n) {
8+
// Base cases: With a 1-step staircase, there's only one way to
9+
// climb it. With a 2-step staircase, there are two ways to climb it.
10+
if (n <= 2) {
11+
return n;
12+
}
13+
if (memo.containsKey(n)) {
14+
return memo.get(n);
15+
}
16+
// The number of ways to climb to the n-th step is equal to the sum
17+
// of the number of ways to climb to step n - 1 and to n - 2.
18+
memo.put(n, climbingStairsTopDown(n - 1) + climbingStairsTopDown(n - 2));
19+
return memo.get(n);
20+
}
21+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
public class Knapsack {
2+
public int knapsack(int cap, int[] weights, int[] values) {
3+
int n = values.length;
4+
// Base case: Set the first column and last row to 0 by
5+
// initializing the entire DP table to 0.
6+
int[][] dp = new int[n + 1][cap + 1];
7+
8+
// Populate the DP table.
9+
for (int i = n - 1; i >= 0; i--) {
10+
for (int c = 1; c < cap + 1; c++) {
11+
// If the item 'i' fits in the current knapsack capacity,
12+
// the maximum value at 'dp[i][c]' is the largest of either:
13+
// 1. The maximum value if we include item 'i'.
14+
// 2. The maximum value if we exclude item 'i'.
15+
if (weights[i] <= c) {
16+
dp[i][c] = Math.max(values[i] + dp[i + 1][c - weights[i]], dp[i + 1][c]);
17+
}
18+
// If it doesn't fit, we have to exclude it.
19+
else {
20+
dp[i][c] = dp[i + 1][c];
21+
}
22+
}
23+
}
24+
return dp[0][cap];
25+
}
26+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
public class KnapsackOptimized {
2+
public int knapsackOptimized(int cap, int[] weights, int[] values) {
3+
int n = values.length;
4+
// Initialize 'prevRow' as the DP values of the row below the
5+
// current row.
6+
int[] prevRow = new int[cap + 1];
7+
for (int i = n - 1; i >= 0; i--) {
8+
// Set the first cell of the 'currRow' to 0 to set the base
9+
// case for this row. This is done by initializing the entire
10+
// row to 0.
11+
int[] currRow = new int[cap + 1];
12+
for (int c = 1; c < cap + 1; c++) {
13+
// If item 'i' fits in the current knapsack capacity, the
14+
// maximum value at 'currRow[c]' is the largest of either:
15+
// 1. The maximum value if we include item 'i'.
16+
// 2. The maximum value if we exclude item 'i'.
17+
if (weights[i] <= c) {
18+
currRow[c] = Math.max(values[i] + prevRow[c - weights[i]], prevRow[c]);
19+
}
20+
// If item 'i' doesn't fit, we exclude it.
21+
else {
22+
currRow[c] = prevRow[c];
23+
}
24+
}
25+
// Set 'prevRow' to 'currRow' values for the next iteration.
26+
prevRow = currRow;
27+
}
28+
return prevRow[cap];
29+
}
30+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
public class LargestSquareInAMatrix {
2+
public int largestSquareInAMatrix(int[][] matrix) {
3+
if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
4+
return 0;
5+
}
6+
int m = matrix.length;
7+
int n = matrix[0].length;
8+
int[][] dp = new int[m][n];
9+
int maxLen = 0;
10+
// Base case: If a cell in row 0 is 1, the largest square ending there has a
11+
// length of 1.
12+
for (int j = 0; j < n; j++) {
13+
if (matrix[0][j] == 1) {
14+
dp[0][j] = 1;
15+
maxLen = 1;
16+
}
17+
}
18+
// Base case: If a cell in column 0 is 1, the largest square ending there has
19+
// a length of 1.
20+
for (int i = 0; i < m; i++) {
21+
if (matrix[i][0] == 1) {
22+
dp[i][0] = 1;
23+
maxLen = 1;
24+
}
25+
}
26+
// Populate the rest of the DP table.
27+
for (int i = 1; i < m; i++) {
28+
for (int j = 1; j < n; j++) {
29+
if (matrix[i][j] == 1) {
30+
// The length of the largest square ending here is determined by
31+
// the smallest square ending at the neighboring cells (left,
32+
// top-left, top), plus 1 to include this cell.
33+
dp[i][j] = 1 + Math.min(dp[i - 1][j], Math.min(dp[i - 1][j - 1], dp[i][j - 1]));
34+
}
35+
maxLen = Math.max(maxLen, dp[i][j]);
36+
}
37+
}
38+
return maxLen * maxLen;
39+
}
40+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
public class LargestSquareInAMatrixOptimized {
2+
public int largestSquareInAMatrixOptimized(int[][] matrix) {
3+
if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
4+
return 0;
5+
}
6+
int m = matrix.length;
7+
int n = matrix[0].length;
8+
int[] prevRow = new int[n];
9+
int maxLen = 0;
10+
// Iterate through the matrix.
11+
for (int i = 0; i < m; i++) {
12+
int[] currRow = new int[n];
13+
for (int j = 0; j < n; j++) {
14+
// Base cases: if we’re in row 0 or column 0, the largest square ending
15+
// here has a length of 1. This can be set by using the value in the
16+
// input matrix.
17+
if (i == 0 || j == 0) {
18+
currRow[j] = matrix[i][j];
19+
} else {
20+
if (matrix[i][j] == 1) {
21+
// currRow[j] = 1 + min(left, top-left, top)
22+
currRow[j] = 1 + Math.min(currRow[j - 1], Math.min(prevRow[j - 1], prevRow[j]));
23+
}
24+
}
25+
maxLen = Math.max(maxLen, currRow[j]);
26+
}
27+
// Update 'prevRow' with 'currRow' values for the next iteration.
28+
prevRow = currRow;
29+
}
30+
return maxLen * maxLen;
31+
}
32+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
public class LongestCommonSubsequence {
2+
public int longestCommonSubsequence(String s1, String s2) {
3+
// Base case: Set the last row and last column to 0 by
4+
// initializing the entire DP table with 0s.
5+
int[][] dp = new int[s1.length() + 1][s2.length() + 1];
6+
// Populate the DP table.
7+
for (int i = s1.length() - 1; i >= 0; i--) {
8+
for (int j = s2.length() - 1; j >= 0; j--) {
9+
// If the characters match, the length of the LCS at
10+
// 'dp[i][j]' is 1 + the LCS length of the remaining
11+
// substrings.
12+
if (s1.charAt(i) == s2.charAt(j)) {
13+
dp[i][j] = 1 + dp[i + 1][j + 1];
14+
}
15+
// If the characters don't match, the LCS length at
16+
// 'dp[i][j]' can be found by either:
17+
// 1. Excluding the current character of s1.
18+
// 2. Excluding the current character of s2.
19+
else {
20+
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
21+
}
22+
}
23+
}
24+
return dp[0][0];
25+
}
26+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
public class LongestCommonSubsequenceOptimized {
2+
public int longestCommonSubsequenceOptimized(String s1, String s2) {
3+
// Initialize 'prevRow' as the DP values of the last row.
4+
int[] prevRow = new int[s2.length() + 1];
5+
for (int i = s1.length() - 1; i >= 0; i--) {
6+
// Set the last cell of 'currRow' to 0 to set the base case for
7+
// this row. This is done by initializing the entire row to 0.
8+
int[] currRow = new int[s2.length() + 1];
9+
for (int j = s2.length() - 1; j >= 0; j--) {
10+
// If the characters match, the length of the LCS at
11+
// 'currRow[j]' is 1 + the LCS length of the remaining
12+
// substrings ('prevRow[j + 1]').
13+
if (s1.charAt(i) == s2.charAt(j)) {
14+
currRow[j] = 1 + prevRow[j + 1];
15+
}
16+
// If the characters don't match, the LCS length at
17+
// 'currRow[j]' can be found by either:
18+
// 1. Excluding the current character of s1 ('prevRow[j]').
19+
// 2. Excluding the current character of s2 ('currRow[j + 1]').
20+
else {
21+
currRow[j] = Math.max(prevRow[j], currRow[j + 1]);
22+
}
23+
}
24+
// Update 'prevRow' with 'currRow' values for the next
25+
// iteration.
26+
prevRow = currRow;
27+
}
28+
return prevRow[0];
29+
}
30+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
public class LongestPalindromeInAString {
2+
public String longestPalindromeInAString(String s) {
3+
int n = s.length();
4+
if (n == 0) {
5+
return "";
6+
}
7+
boolean[][] dp = new boolean[n][n];
8+
int maxLen = 1;
9+
int startIndex = 0;
10+
// Base case: a single character is always a palindrome.
11+
for (int i = 0; i < n; i++) {
12+
dp[i][i] = true;
13+
}
14+
// Base case: a substring of length two is a palindrome if both
15+
// characters are the same.
16+
for (int i = 0; i < n - 1; i++) {
17+
if (s.charAt(i) == s.charAt(i + 1)) {
18+
dp[i][i + 1] = true;
19+
maxLen = 2;
20+
startIndex = i;
21+
}
22+
}
23+
// Find palindromic substrings of length 3 or greater.
24+
for (int substringLen = 3; substringLen < n + 1; substringLen++) {
25+
// Iterate through each substring of length 'substringLen'.
26+
for (int i = 0; i < n - substringLen + 1; i++) {
27+
int j = i + substringLen - 1;
28+
// If the first and last characters are the same, and the
29+
// inner substring is a palindrome, then the current
30+
// substring is a palindrome.
31+
if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {
32+
dp[i][j] = true;
33+
maxLen = substringLen;
34+
startIndex = i;
35+
}
36+
}
37+
}
38+
return s.substring(startIndex, startIndex + maxLen);
39+
}
40+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
public class LongestPalindromeInAStringExpanding {
2+
public String longestPalindromeInAStringExpanding(String s) {
3+
int n = s.length();
4+
int start, maxLen;
5+
start = maxLen = 0;
6+
for (int center = 0; center < n; center++) {
7+
// Check for odd-length palindromes.
8+
int oddStart, oddLength;
9+
int[] oddResult = expandPalindrome(center, center, s);
10+
oddStart = oddResult[0];
11+
oddLength = oddResult[1];
12+
if (oddLength > maxLen) {
13+
start = oddStart;
14+
maxLen = oddLength;
15+
}
16+
// Check for even-length palindromes.
17+
if (center < n - 1 && s.charAt(center) == s.charAt(center + 1)) {
18+
int evenStart, evenLength;
19+
int[] evenResult = expandPalindrome(center, center + 1, s);
20+
evenStart = evenResult[0];
21+
evenLength = evenResult[1];
22+
if (evenLength > maxLen) {
23+
start = evenStart;
24+
maxLen = evenLength;
25+
}
26+
}
27+
}
28+
return s.substring(start, start + maxLen);
29+
}
30+
31+
// Expands outward from the center of a base case to identify the start
32+
// index and length of the longest palindrome that extends from this
33+
// base case.
34+
private int[] expandPalindrome(int left, int right, String s) {
35+
while (left > 0 && right < s.length() - 1 && s.charAt(left - 1) == s.charAt(right + 1)) {
36+
left--;
37+
right++;
38+
}
39+
return new int[]{left, right - left + 1};
40+
}
41+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import java.util.Arrays;
2+
3+
public class MatrixPathways {
4+
public int matrixPathways(int m, int n) {
5+
// Base cases: Set all cells in row 0 and column 0 to 1. We can
6+
// do this by initializing all cells in the DP table to 1.
7+
int[][] dp = new int[m][n];
8+
for (int i = 0; i < m; i++) {
9+
Arrays.fill(dp[i], 1);
10+
}
11+
// Fill in the rest of the DP table.
12+
for (int r = 1; r < m; r++) {
13+
for (int c = 1; c < n; c++) {
14+
// Paths to current cell = paths from above + paths from
15+
// left.
16+
dp[r][c] = dp[r - 1][c] + dp[r][c - 1];
17+
}
18+
}
19+
return dp[m - 1][n - 1];
20+
}
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import java.util.Arrays;
2+
3+
public class MatrixPathwaysOptimized {
4+
public int matrixPathwaysOptimized(int m, int n) {
5+
// Initialize 'prevRow' as the DP values of row 0, which are all 1s.
6+
int[] prevRow = new int[n];
7+
Arrays.fill(prevRow, 1);
8+
// Iterate through the matrix starting from row 1.
9+
for (int r = 1; r < m; r++) {
10+
// Set the first cell of 'curr_row' to 1. This is done by
11+
// setting the entire row to 1.
12+
int[] currRow = new int[n];
13+
Arrays.fill(currRow, 1);
14+
for (int c = 1; c < n; c++) {
15+
// The number of unique paths to the current cell is the sum
16+
// of the paths from the cell above it ('prevRow[c]') and
17+
// the cell to the left ('currRow[c - 1]').
18+
currRow[c] = prevRow[c] + currRow[c - 1];
19+
}
20+
// Update 'prevRow' with 'currRow' values for the next
21+
// iteration.
22+
prevRow = currRow;
23+
}
24+
// The last element in 'prevRow' stores the result for the
25+
// bottom-right cell.
26+
return prevRow[n - 1];
27+
}
28+
}

0 commit comments

Comments
 (0)