Skip to content

Commit 1ed1643

Browse files
Add dynamic programming problem implementations and their tests
1 parent e8cbbce commit 1ed1643

24 files changed

+858
-0
lines changed

dynamic/burstballoons.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// burstballoons.go
2+
// description: Solves the Burst Balloons problem using dynamic programming
3+
// reference: https://en.wikipedia.org/wiki/Burst_balloon_problem
4+
// time complexity: O(n^3)
5+
// space complexity: O(n^2)
6+
7+
package dynamic
8+
9+
import "github.com/TheAlgorithms/Go/math/max"
10+
11+
// MaxCoins returns the maximum coins we can collect by bursting the balloons
12+
func MaxCoins(nums []int) int {
13+
n := len(nums)
14+
dp := make([][]int, n+2)
15+
for i := range dp {
16+
dp[i] = make([]int, n+2)
17+
}
18+
19+
for i := 1; i <= n; i++ {
20+
nums[i] = nums[i-1]
21+
}
22+
nums = append([]int{1}, nums...)
23+
nums = append(nums, 1)
24+
25+
for length := 1; length <= n; length++ {
26+
for left := 1; left+length-1 <= n; left++ {
27+
right := left + length - 1
28+
for k := left; k <= right; k++ {
29+
dp[left][right] = max.Int(dp[left][right], dp[left][k-1]+dp[k+1][right]+nums[left-1]*nums[k]*nums[right+1])
30+
}
31+
}
32+
}
33+
return dp[1][n]
34+
}

dynamic/burstballoons_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package dynamic_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/TheAlgorithms/Go/dynamic"
7+
)
8+
9+
type testCaseBurstBalloons struct {
10+
nums []int
11+
expected int
12+
}
13+
14+
func getBurstBalloonsTestCases() []testCaseBurstBalloons {
15+
return []testCaseBurstBalloons{
16+
{[]int{3, 1, 5, 8}, 167}, // Maximum coins from [3,1,5,8]
17+
{[]int{1, 5}, 10}, // Maximum coins from [1,5]
18+
{[]int{7, 9, 8, 0, 7}, 392}, // Maximum coins from [7,9,8,0,7]
19+
{[]int{1}, 1}, // Single balloon
20+
{[]int{}, 0}, // No balloons
21+
{[]int{9, 7, 8, 3}, 233}, // Maximum coins from [9,7,8,3]
22+
}
23+
24+
}
25+
26+
func TestMaxCoins(t *testing.T) {
27+
t.Run("Burst Balloons test cases", func(t *testing.T) {
28+
for _, tc := range getBurstBalloonsTestCases() {
29+
actual := dynamic.MaxCoins(tc.nums)
30+
if actual != tc.expected {
31+
t.Errorf("MaxCoins(%v) = %d; expected %d", tc.nums, actual, tc.expected)
32+
}
33+
}
34+
})
35+
}

dynamic/dicethrow.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// dicethrow.go
2+
// description: Solves the Dice Throw Problem using dynamic programming
3+
// reference: https://www.geeksforgeeks.org/dice-throw-problem/
4+
// time complexity: O(m * n)
5+
// space complexity: O(m * n)
6+
7+
package dynamic
8+
9+
// DiceThrow returns the number of ways to get sum `sum` using `m` dice with `n` faces
10+
func DiceThrow(m, n, sum int) int {
11+
dp := make([][]int, m+1)
12+
for i := range dp {
13+
dp[i] = make([]int, sum+1)
14+
}
15+
16+
for i := 1; i <= n; i++ {
17+
if i <= sum {
18+
dp[1][i] = 1
19+
}
20+
}
21+
22+
for i := 2; i <= m; i++ {
23+
for j := 1; j <= sum; j++ {
24+
for k := 1; k <= n; k++ {
25+
if j-k >= 0 {
26+
dp[i][j] += dp[i-1][j-k]
27+
}
28+
}
29+
}
30+
}
31+
32+
return dp[m][sum]
33+
}

dynamic/dicethrow_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package dynamic_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/TheAlgorithms/Go/dynamic"
7+
)
8+
9+
type testCaseDiceThrow struct {
10+
m, n, sum int
11+
expected int
12+
}
13+
14+
func getDiceThrowTestCases() []testCaseDiceThrow {
15+
return []testCaseDiceThrow{
16+
{2, 6, 7, 6}, // Two dice, six faces each, sum = 7
17+
{1, 6, 3, 1}, // One die, six faces, sum = 3
18+
{3, 4, 5, 6}, // Three dice, four faces each, sum = 5
19+
{2, 4, 8, 5}, // Two dice, four faces each, sum = 8
20+
{1, 6, 1, 1}, // One die, six faces, sum = 1
21+
{2, 6, 12, 1}, // Two dice, six faces each, sum = 12
22+
{3, 6, 18, 1}, // Three dice, six faces each, sum = 18
23+
{2, 6, 20, 0}, // Two dice, six faces each, sum = 20 (impossible)
24+
{3, 8, 15, 51}, // Three dice, eight faces each, sum = 15
25+
{1, 1, 1, 1}, // One die, one face, sum = 1
26+
{1, 1, 2, 0}, // One die, one face, sum = 2 (impossible)
27+
{2, 1, 2, 1}, // Two dice, one face each, sum = 2
28+
}
29+
}
30+
31+
func TestDiceThrow(t *testing.T) {
32+
t.Run("Basic test cases", func(t *testing.T) {
33+
for _, tc := range getDiceThrowTestCases() {
34+
actual := dynamic.DiceThrow(tc.m, tc.n, tc.sum)
35+
if actual != tc.expected {
36+
t.Errorf("DiceThrow(%d, %d, %d) = %d; expected %d", tc.m, tc.n, tc.sum, actual, tc.expected)
37+
}
38+
}
39+
})
40+
}

dynamic/eggdropping.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// eggdropping.go
2+
// description: Solves the Egg Dropping Problem using dynamic programming
3+
// reference: https://en.wikipedia.org/wiki/Egg_dropping_puzzle
4+
// time complexity: O(k*n)
5+
// space complexity: O(k*n)
6+
7+
package dynamic
8+
9+
import (
10+
"github.com/TheAlgorithms/Go/math/max"
11+
"github.com/TheAlgorithms/Go/math/min"
12+
)
13+
14+
// EggDropping finds the minimum number of attempts needed to find the critical floor
15+
// with `eggs` number of eggs and `floors` number of floors
16+
func EggDropping(eggs, floors int) int {
17+
dp := make([][]int, eggs+1)
18+
for i := range dp {
19+
dp[i] = make([]int, floors+1)
20+
}
21+
22+
for i := 1; i <= eggs; i++ {
23+
dp[i][0] = 0
24+
dp[i][1] = 1
25+
}
26+
27+
for j := 0; j <= floors; j++ {
28+
dp[1][j] = j
29+
}
30+
31+
for i := 2; i <= eggs; i++ {
32+
for j := 2; j <= floors; j++ {
33+
dp[i][j] = int(^uint(0) >> 1) // initialize with a large number
34+
for x := 1; x <= j; x++ {
35+
res := max.Int(dp[i-1][x-1], dp[i][j-x]) + 1
36+
dp[i][j] = min.Int(dp[i][j], res)
37+
}
38+
}
39+
}
40+
return dp[eggs][floors]
41+
}

dynamic/eggdropping_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package dynamic_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/TheAlgorithms/Go/dynamic"
7+
)
8+
9+
type testCaseEggDropping struct {
10+
eggs int
11+
floors int
12+
expected int
13+
}
14+
15+
func getEggDroppingTestCases() []testCaseEggDropping {
16+
return []testCaseEggDropping{
17+
{1, 10, 10}, // One egg, need to test all floors
18+
{2, 10, 4}, // Two eggs and ten floors
19+
{3, 14, 4}, // Three eggs and fourteen floors
20+
{2, 36, 8}, // Two eggs and thirty-six floors
21+
{3, 100, 9}, // Three eggs and one hundred floors
22+
{4, 50, 7}, // Four eggs and fifty floors
23+
{1, 1, 1}, // One egg, one floor
24+
{2, 0, 0}, // Two eggs, zero floors
25+
}
26+
27+
}
28+
29+
func TestEggDropping(t *testing.T) {
30+
t.Run("Egg Dropping test cases", func(t *testing.T) {
31+
for _, tc := range getEggDroppingTestCases() {
32+
actual := dynamic.EggDropping(tc.eggs, tc.floors)
33+
if actual != tc.expected {
34+
t.Errorf("EggDropping(%d, %d) = %d; expected %d", tc.eggs, tc.floors, actual, tc.expected)
35+
}
36+
}
37+
})
38+
}

dynamic/interleavingstrings.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// interleavingstrings.go
2+
// description: Solves the Interleaving Strings problem using dynamic programming
3+
// reference: https://en.wikipedia.org/wiki/Interleaving_strings
4+
// time complexity: O(m*n)
5+
// space complexity: O(m*n)
6+
7+
package dynamic
8+
9+
// IsInterleave checks if string `s1` and `s2` can be interleaved to form string `s3`
10+
func IsInterleave(s1, s2, s3 string) bool {
11+
if len(s1)+len(s2) != len(s3) {
12+
return false
13+
}
14+
15+
dp := make([][]bool, len(s1)+1)
16+
for i := range dp {
17+
dp[i] = make([]bool, len(s2)+1)
18+
}
19+
20+
dp[0][0] = true
21+
for i := 1; i <= len(s1); i++ {
22+
dp[i][0] = dp[i-1][0] && s1[i-1] == s3[i-1]
23+
}
24+
25+
for j := 1; j <= len(s2); j++ {
26+
dp[0][j] = dp[0][j-1] && s2[j-1] == s3[j-1]
27+
}
28+
29+
for i := 1; i <= len(s1); i++ {
30+
for j := 1; j <= len(s2); j++ {
31+
dp[i][j] = (dp[i-1][j] && s1[i-1] == s3[i+j-1]) || (dp[i][j-1] && s2[j-1] == s3[i+j-1])
32+
}
33+
}
34+
35+
return dp[len(s1)][len(s2)]
36+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package dynamic_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/TheAlgorithms/Go/dynamic"
7+
)
8+
9+
type testCaseInterleaving struct {
10+
s1, s2, s3 string
11+
expected bool
12+
}
13+
14+
func getInterleavingTestCases() []testCaseInterleaving {
15+
return []testCaseInterleaving{
16+
{"aab", "axy", "aaxaby", true}, // Valid interleaving
17+
{"aab", "axy", "abaaxy", false}, // Invalid interleaving
18+
{"", "", "", true}, // All empty strings
19+
{"abc", "", "abc", true}, // Only s1 matches s3
20+
{"", "xyz", "xyz", true}, // Only s2 matches s3
21+
{"abc", "xyz", "abxcyz", true}, // Valid interleaving
22+
{"abc", "xyz", "abxycz", false}, // Invalid interleaving
23+
{"aaa", "aaa", "aaaaaa", true}, // Identical strings
24+
{"aaa", "aaa", "aaaaaaa", false}, // Extra character
25+
{"abc", "def", "abcdef", true}, // Concatenation order
26+
{"abc", "def", "adbcef", true}, // Valid mixed interleaving
27+
{"abc", "def", "abdecf", false}, // Invalid mixed interleaving
28+
}
29+
}
30+
31+
func TestIsInterleave(t *testing.T) {
32+
t.Run("Interleaving Strings test cases", func(t *testing.T) {
33+
for _, tc := range getInterleavingTestCases() {
34+
actual := dynamic.IsInterleave(tc.s1, tc.s2, tc.s3)
35+
if actual != tc.expected {
36+
t.Errorf("IsInterleave(%q, %q, %q) = %v; expected %v", tc.s1, tc.s2, tc.s3, actual, tc.expected)
37+
}
38+
}
39+
})
40+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// longestarithmeticsubsequence.go
2+
// description: Implementation of the Longest Arithmetic Subsequence problem
3+
// reference: https://en.wikipedia.org/wiki/Longest_arithmetic_progression
4+
// time complexity: O(n^2)
5+
// space complexity: O(n^2)
6+
7+
package dynamic
8+
9+
// LongestArithmeticSubsequence returns the length of the longest arithmetic subsequence
10+
func LongestArithmeticSubsequence(nums []int) int {
11+
n := len(nums)
12+
if n <= 1 {
13+
return n
14+
}
15+
16+
dp := make([]map[int]int, n)
17+
for i := range dp {
18+
dp[i] = make(map[int]int)
19+
}
20+
21+
maxLength := 1
22+
23+
for i := 1; i < n; i++ {
24+
for j := 0; j < i; j++ {
25+
diff := nums[i] - nums[j]
26+
dp[i][diff] = dp[j][diff] + 1
27+
if dp[i][diff]+1 > maxLength {
28+
maxLength = dp[i][diff] + 1
29+
}
30+
}
31+
}
32+
33+
return maxLength
34+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package dynamic_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/TheAlgorithms/Go/dynamic"
7+
)
8+
9+
type testCaseLongestArithmeticSubsequence struct {
10+
nums []int
11+
expected int
12+
}
13+
14+
func getLongestArithmeticSubsequenceTestCases() []testCaseLongestArithmeticSubsequence {
15+
return []testCaseLongestArithmeticSubsequence{
16+
{[]int{3, 6, 9, 12}, 4}, // Arithmetic sequence of length 4
17+
{[]int{9, 4, 7, 2, 10}, 3}, // Arithmetic sequence of length 3
18+
{[]int{20, 1, 15, 3, 10, 5, 8}, 4}, // Arithmetic sequence of length 4
19+
{[]int{1, 2, 3, 4, 5}, 5}, // Arithmetic sequence of length 5
20+
{[]int{10, 7, 4, 1}, 4}, // Arithmetic sequence of length 4
21+
{[]int{1, 5, 7, 8, 5, 3, 4, 3, 1, 2}, 4}, // Arithmetic sequence of length 4
22+
{[]int{1, 3, 5, 7, 9}, 5}, // Arithmetic sequence of length 5
23+
{[]int{5, 10, 15, 20}, 4}, // Arithmetic sequence of length 4
24+
{[]int{1}, 1}, // Single element, length is 1
25+
{[]int{}, 0}, // Empty array, length is 0
26+
}
27+
}
28+
29+
func TestLongestArithmeticSubsequence(t *testing.T) {
30+
t.Run("Longest Arithmetic Subsequence test cases", func(t *testing.T) {
31+
for _, tc := range getLongestArithmeticSubsequenceTestCases() {
32+
actual := dynamic.LongestArithmeticSubsequence(tc.nums)
33+
if actual != tc.expected {
34+
t.Errorf("LongestArithmeticSubsequence(%v) = %v; expected %v", tc.nums, actual, tc.expected)
35+
}
36+
}
37+
})
38+
}

0 commit comments

Comments
 (0)