Skip to content

Commit 4adff4c

Browse files
author
turingfly
committed
Recursion and Dynamic Programming
1 parent e62dcfe commit 4adff4c

8 files changed

+602
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package chapter08RecursionAndDynamicProgramming;
2+
3+
import java.util.HashMap;
4+
5+
/**
6+
*
7+
* Problem: Given a boolean expression consisting of the symbols 0 (false),
8+
* 1(true),
9+
*
10+
*/
11+
public class BooleanEvaluation {
12+
13+
/**
14+
* Method 1: Brute force
15+
*/
16+
public static int count = 0;
17+
18+
public static boolean stringToBool(String c) {
19+
return c.equals("1") ? true : false;
20+
}
21+
22+
public static int countEval1(String s, boolean result) {
23+
count++;
24+
if (s.length() == 0) {
25+
return 0;
26+
}
27+
if (s.length() == 1) {
28+
return stringToBool(s) == result ? 1 : 0;
29+
}
30+
int ways = 0;
31+
for (int i = 1; i < s.length(); i += 2) {
32+
char c = s.charAt(i);
33+
String left = s.substring(0, i);
34+
String right = s.substring(i + 1, s.length());
35+
int leftTrue = countEval1(left, true);
36+
int leftFalse = countEval1(left, false);
37+
int rightTrue = countEval1(right, true);
38+
int rightFalse = countEval1(right, false);
39+
int total = (leftTrue + leftFalse) * (rightTrue + rightFalse);
40+
int totalTrue = 0;
41+
if (c == '^') { // required: one true and one false
42+
totalTrue = leftTrue * rightFalse + leftFalse * rightTrue;
43+
} else if (c == '&') { // required: both true
44+
totalTrue = leftTrue * rightTrue;
45+
} else if (c == '|') { // required: anything but both false
46+
totalTrue = leftTrue * rightTrue + leftFalse * rightTrue + leftTrue * rightFalse;
47+
}
48+
int subWays = result ? totalTrue : total - totalTrue;
49+
ways += subWays;
50+
}
51+
return ways;
52+
}
53+
54+
/**
55+
* Method 2: Memorization
56+
*/
57+
public static int countEval2(String s, boolean result) {
58+
return countEval2(s, result, new HashMap<String, Integer>());
59+
}
60+
61+
public static int countEval2(String s, boolean result, HashMap<String, Integer> memo) {
62+
count++;
63+
if (s.length() == 0) {
64+
return 0;
65+
}
66+
if (s.length() == 1) {
67+
return stringToBool(s) == result ? 1 : 0;
68+
}
69+
if (memo.containsKey(result + s)) {
70+
return memo.get(result + s);
71+
}
72+
int ways = 0;
73+
for (int i = 1; i < s.length(); i += 2) {
74+
char c = s.charAt(i);
75+
String left = s.substring(0, i);
76+
String right = s.substring(i + 1, s.length());
77+
int leftTrue = countEval2(left, true, memo);
78+
int leftFalse = countEval2(left, false, memo);
79+
int rightTrue = countEval2(right, true, memo);
80+
int rightFalse = countEval2(right, false, memo);
81+
int total = (leftTrue + leftFalse) * (rightTrue + rightFalse);
82+
int totalTrue = 0;
83+
if (c == '^') {
84+
totalTrue = leftTrue * rightFalse + leftFalse * rightTrue;
85+
} else if (c == '&') {
86+
totalTrue = leftTrue * rightTrue;
87+
} else if (c == '|') {
88+
totalTrue = leftTrue * rightTrue + leftFalse * rightTrue + leftTrue * rightFalse;
89+
}
90+
int subWays = result ? totalTrue : total - totalTrue;
91+
ways += subWays;
92+
}
93+
memo.put(result + s, ways);
94+
return ways;
95+
}
96+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package chapter08RecursionAndDynamicProgramming;
2+
3+
/**
4+
*
5+
* Problem: Given an infinite number of quarters(25 cents), dimes(10 cents),
6+
* nickels(5 cents), and pennies (1 cent), write code to calculate the number of
7+
* ways of representing n cents
8+
*/
9+
public class Coins {
10+
/**
11+
* Method 1: Recursively call helper several times for the same values of
12+
* amount and index. Duplicates
13+
*/
14+
15+
public int makeChange1(int n) {
16+
int[] denoms = { 25, 10, 5, 1 };
17+
return helper1(n, denoms, 0);
18+
}
19+
20+
public int helper1(int amount, int[] denoms, int index) {
21+
if (index >= denoms.length - 1) {
22+
// last denom
23+
return 1;
24+
}
25+
int denomAmount = denoms[index];
26+
int res = 0;
27+
for (int i = 0; i * denomAmount <= amount; i++) {
28+
int amountRemaining = amount - i * denomAmount;
29+
res += helper1(amountRemaining, denoms, index + 1);
30+
}
31+
return res;
32+
}
33+
34+
/**
35+
* Method 2: Memorization. Store the previously computed values. Store a
36+
* mapping from each pair to the precomputed result
37+
*/
38+
public int makeChange2(int n) {
39+
int[] denoms = { 25, 10, 5, 1 };
40+
int[][] map = new int[n + 1][denoms.length];
41+
return helper2(n, denoms, 0, map);
42+
}
43+
44+
public int helper2(int amount, int[] denoms, int index, int[][] map) {
45+
if (map[amount][index] > 0) {
46+
return map[amount][index];
47+
}
48+
if (index >= denoms.length - 1) {
49+
// last denom
50+
return 1;
51+
}
52+
int denomAmount = denoms[index];
53+
int res = 0;
54+
for (int i = 0; i * denomAmount <= amount; i++) {
55+
int amountRemaining = amount - i * denomAmount;
56+
res += helper1(amountRemaining, denoms, index + 1);
57+
}
58+
map[amount][index] = res;
59+
return res;
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package chapter08RecursionAndDynamicProgramming;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
*
8+
* Problem: Write an algorithm to print all ways of arranging eight queens on a
9+
* 8*8 chess board so that none of them share the same row, column, or diagonal.
10+
* In this case, "diagonal" means all diagonals, not just the two that bisect
11+
* the board.
12+
*
13+
*/
14+
public class EightQueues {
15+
public List<Integer[]> set(int size) {
16+
Integer[] columns = new Integer[size];
17+
List<Integer[]> res = new ArrayList<>();
18+
placeQueens(0, columns, res, size);
19+
return res;
20+
}
21+
22+
public void placeQueens(int row, Integer[] columns, List<Integer[]> res, int size) {
23+
if (row == size) {
24+
res.add(columns.clone());
25+
} else {
26+
for (int col = 0; col < size; col++) {
27+
if (checkValid(columns, row, col)) {
28+
columns[row] = col;
29+
placeQueens(row + 1, columns, res, size);
30+
}
31+
}
32+
}
33+
}
34+
35+
/**
36+
* Check if (row1, column1) is a valid spot for a queen by checking if there
37+
* is a queen in the same column or diagonal. We don't need to check it for
38+
* queens in the same row because the calling placeQueen only attempts to
39+
* place one queen at a time. We know this row is empty.
40+
*/
41+
private boolean checkValid(Integer[] columns, int row1, int column1) {
42+
for (int row2 = 0; row2 < row1; row2++) {
43+
int column2 = columns[row2];
44+
if (column1 == column2) {
45+
return false;
46+
}
47+
// check diagonal
48+
int columnDistance = Math.abs(column2 - column1);
49+
int rowDistance = row1 - row2;
50+
if (columnDistance == rowDistance) {
51+
return false;
52+
}
53+
}
54+
return true;
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package chapter08RecursionAndDynamicProgramming;
2+
3+
/**
4+
*
5+
* Problem: Implement the "paint fill" function that one might see on many image
6+
* editing programs. That is, given a screen(represented by a two-dimensional
7+
* array of colors), a point, and a new color, fill in the surrounding area
8+
* until the color changes from the original color.
9+
*
10+
*/
11+
enum Color {
12+
Black, White, Red, Yellow, Green
13+
}
14+
15+
public class PaintFill {
16+
public boolean paintFill(Color[][] screen, int row, int col, Color nColor) {
17+
if (screen[row][col] == nColor) {
18+
return false;
19+
}
20+
return helper(screen, row, col, screen[row][col], nColor);
21+
}
22+
23+
private boolean helper(Color[][] screen, int row, int col, Color oColor, Color nColor) {
24+
if (row < 0 || row >= screen.length || col < 0 || col >= screen[0].length) {
25+
return false;
26+
}
27+
if (screen[row][col] == oColor) {
28+
screen[row][col] = nColor;
29+
helper(screen, row - 1, col, oColor, nColor); // up
30+
helper(screen, row + 1, col, oColor, nColor); // down
31+
helper(screen, row, col - 1, oColor, nColor); // left
32+
helper(screen, row, col + 1, oColor, nColor); // right
33+
}
34+
return true;
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package chapter08RecursionAndDynamicProgramming;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
*
8+
* Problem:Implement an algorithm to print all valid combinations of n pairs of
9+
* parentheses.
10+
*
11+
*/
12+
public class Parenthesis {
13+
/**
14+
* DFS, open and close variable. open < numberOfparis and close < open
15+
*/
16+
public List<String> generateParenthesis(int n) {
17+
List<String> res = new ArrayList<>();
18+
helper(res, "", 0, 0, n);
19+
return res;
20+
}
21+
22+
public void helper(List<String> res, String s, int open, int close, int numberOfPairs) {
23+
if (s.length() == numberOfPairs * 2) {
24+
res.add(s);
25+
return;
26+
}
27+
if (open < numberOfPairs) {
28+
helper(res, s + "(", open + 1, close, numberOfPairs);
29+
}
30+
if (close < open) {
31+
helper(res, s + ")", open, close + 1, numberOfPairs);
32+
}
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package chapter08RecursionAndDynamicProgramming;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
/**
9+
*
10+
* Problem: Write a method to compute all permutations of a string whose
11+
* characters are not necessarily unique. The list of permutations should not
12+
* have duplicates.
13+
*
14+
* Solution: HashTable, key: char, value count
15+
*
16+
* p(a - 2| b - 4| c - 1) = {a + p(a - 1| b - 4| c - 1 )} + {b + p(a - 2| b - 3|
17+
* c - 1 )} + {c + p(a - 2| b - 4| c - 0 )}
18+
*/
19+
public class PermutationsWithDuplicates {
20+
public List<String> getPerms(String s) {
21+
List<String> res = new ArrayList<>();
22+
Map<Character, Integer> map = buildFreqTable(s);
23+
helper(map, "", s.length(), res);
24+
return res;
25+
}
26+
27+
private Map<Character, Integer> buildFreqTable(String s) {
28+
Map<Character, Integer> map = new HashMap<>();
29+
for (char c : s.toCharArray()) {
30+
if (!map.containsKey(c)) {
31+
map.put(c, 0);
32+
}
33+
map.put(c, map.get(c) + 1);
34+
}
35+
return map;
36+
}
37+
38+
private void helper(Map<Character, Integer> map, String prefix, int remaining, List<String> res) {
39+
// base case
40+
if (remaining == 0) {
41+
res.add(prefix);
42+
return;
43+
}
44+
for (Character c : map.keySet()) {
45+
int count = map.get(c);
46+
if (count > 0) {
47+
map.put(c, count - 1);
48+
helper(map, prefix + c, remaining - 1, res);
49+
map.put(c, count);
50+
}
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)