Skip to content

Commit f5262c9

Browse files
authored
add max number and interleaving strings problems (#114)
1 parent ae14306 commit f5262c9

7 files changed

+211
-10
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
Welcome to **Data Structures and Algorithms in Go**! 🎉 This project is designed as a dynamic, hands-on resource for learning and practicing data structures and algorithms in the Go programming language.
1010

11+
* At least six problems and solutions for each of the fourteen topics
1112
* Completely free, community-driven, and continuously evolving
1213
* Executes and comes with 100% test coverage, ensuring a high level of quality
1314
* Ability to use in your favorite IDE, editor, or web browser
@@ -122,11 +123,13 @@ Welcome to **Data Structures and Algorithms in Go**! 🎉 This project is design
122123
* [Activity Selector](./greedy/activity_selector_test.go)
123124
* [Knapsack](./greedy/knapsack_test.go)
124125
* [Jump Game](./greedy/jump_game_test.go)
126+
* [Maximum Number](./greedy/max_number_test.go)
125127
* [Task Scheduling](./greedy/task_scheduling_test.go)
126128
* [Dynamic Programming](./dp/README.md)
127129
* [Rod Cutting](./dp/rod_cutting_test.go)
128130
* [Sum Up to Number](./dp/sum_up_to_integer_test.go)
129131
* [House Robber](./dp/house_robber_test.go)
132+
* [Interleaving String](./dp/interleaving_string_test.go)
130133
* [Minimum Deletion to Make a Palindrome](./dp/minimum_deletion_to_make_palindrome_test.go)
131134
* [Word Distance](./dp/word_distance_test.go)
132135

dp/README.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ DP is well-suited for tackling complex problems, including logistics, game theor
3131

3232
## Rehearsal
3333

34-
* [Rod Cutting](rod_cutting_test.go), [Solution](rod_cutting.go)
35-
* [Sum Up to Number](sum_up_to_integer_test.go), [Solution](sum_up_to_integer.go)
36-
* [House Robber](house_robber_test.go), [Solution](house_robber.go).
37-
* [Minimum Deletion to Make a Palindrome](minimum_deletion_to_make_palindrome_test.go), [Solution](minimum_deletion_to_make_palindrome.go)
38-
* [Word Distance](word_distance_test.go), [Solution](word_distance.go.go)
34+
* [Rod Cutting](./rod_cutting_test.go), [Solution](./rod_cutting.go)
35+
* [Sum Up to Number](./sum_up_to_integer_test.go), [Solution](./sum_up_to_integer.go)
36+
* [House Robber](./house_robber_test.go), [Solution](./house_robber.go).
37+
* [Interleaving String](./interleaving_string_test.go), [Solution](./interleaving_string.go)
38+
* [Minimum Deletion to Make a Palindrome](./minimum_deletion_to_make_palindrome_test.go), [Solution](./minimum_deletion_to_make_palindrome.go)
39+
* [Word Distance](./word_distance_test.go), [Solution](./word_distance.go.go)

dp/interleaving_string.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package dp
2+
3+
// IsInterleavingString solves the problem in O(m*n) time and O(m*n) space.
4+
func IsInterleavingString(a, b, input string) bool {
5+
m, n := len(a), len(b)
6+
if len(input) != m+n {
7+
return false
8+
}
9+
10+
dp := dpMap(m, n, a, b, input)
11+
for i := 1; i <= m; i++ {
12+
for j := 1; j <= n; j++ {
13+
if a[i-1] == input[i+j-1] {
14+
dp[i][j] = dp[i][j] || dp[i-1][j]
15+
}
16+
if b[j-1] == input[i+j-1] {
17+
dp[i][j] = dp[i][j] || dp[i][j-1]
18+
}
19+
}
20+
}
21+
return dp[m][n]
22+
}
23+
24+
func dpMap(m, n int, a, b, input string) [][]bool {
25+
dp := make([][]bool, m+1)
26+
for i := range dp {
27+
dp[i] = make([]bool, n+1)
28+
}
29+
dp[0][0] = true
30+
for i := 1; i <= m; i++ {
31+
if a[i-1] == input[i-1] {
32+
dp[i][0] = dp[i-1][0]
33+
}
34+
}
35+
36+
for j := 1; j <= n; j++ {
37+
if b[j-1] == input[j-1] {
38+
dp[0][j] = dp[0][j-1]
39+
}
40+
}
41+
return dp
42+
}

dp/interleaving_string_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package dp
2+
3+
import (
4+
"testing"
5+
)
6+
7+
/*
8+
TestIsInterleavingString tests solution(s) with the following signature and problem description:
9+
10+
IsInterleavingString(a, b, input string) bool
11+
12+
Given three strings a,b, and input, return true if input is made by interleaving a and b such that
13+
it contains all their characters while maintaining their order.
14+
15+
Example:
16+
"a", "bcd", "abcd" would return true.
17+
"a", "bdc", "abd" would return false, because c is missing.
18+
"a", "bdc", "abc" would return false, because d is missing.
19+
*/
20+
func TestIsInterleavingString(t *testing.T) {
21+
tests := []struct {
22+
a, b, input string
23+
isInterleavingString bool
24+
}{
25+
{"a", "b", "ab", true},
26+
{"abc", "def", "abcdef", true},
27+
{"ac", "bdef", "abcdef", true},
28+
{"abe", "cdf", "abcdef", true},
29+
{"abd", "cef", "abcdef", true},
30+
{"a", "bdc", "abdc", true},
31+
{"a", "bdc", "abd", false},
32+
{"a", "bdc", "abc", false},
33+
{"bdc", "a", "abc", false},
34+
{"bcd", "a", "abcd", true},
35+
{"abcd", "a", "aabcd", true},
36+
{"aaac", "aaab", "aaaaaabc", true},
37+
}
38+
39+
for i, test := range tests {
40+
if got := IsInterleavingString(test.a, test.b, test.input); test.isInterleavingString != got {
41+
t.Fatalf("Failed test case #%d. Want %t got %t", i, test.isInterleavingString, got)
42+
}
43+
}
44+
}

greedy/README.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ Greedy algorithms can be applied to optimization problems in which the aim is to
2929

3030
## Rehearsal
3131

32-
* [Maximum Stock Profit](max_stock_profit_test.go), [Solution](max_stock_profit.go)
33-
* [Activity Selector](activity_selector_test.go), [Solution](activity_selector.go)
34-
* [Knapsack](knapsack_test.go), [Solution](knapsack.go)
35-
* [Jump Game](jump_game_test.go), [Solution](jump_game.go)
36-
* [Task Scheduling](task_scheduling_test.go), [Solution](task_scheduling.go)
32+
* [Maximum Stock Profit](./max_stock_profit_test.go), [Solution](./max_stock_profit.go)
33+
* [Activity Selector](./activity_selector_test.go), [Solution](./activity_selector.go)
34+
* [Knapsack](./knapsack_test.go), [Solution](./knapsack.go)
35+
* [Jump Game](./jump_game_test.go), [Solution](./jump_game.go)
36+
* [Maximum Number](./max_number_test.go), [Solution](./max_number.go)
37+
* [Task Scheduling](./task_scheduling_test.go), [Solution](./task_scheduling.go)

greedy/max_number.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package greedy
2+
3+
// MaxNumber solves the problem in O(n^2) time and O(n) space.
4+
func MaxNumber(number1, number2 []int, n int) []int {
5+
output := []int{}
6+
if n > len(number1)+len(number2) {
7+
return output
8+
}
9+
10+
for pickFromNumber1 := min(len(number1), n); pickFromNumber1 >= 0; pickFromNumber1-- {
11+
pickFromNumber2 := n - pickFromNumber1
12+
if pickFromNumber2 <= len(number2) {
13+
merged := merge(maximumNumberInSequence(number1, pickFromNumber1), maximumNumberInSequence(number2, pickFromNumber2))
14+
if len(output) == 0 || isGreater(merged, output) {
15+
output = merged
16+
}
17+
}
18+
}
19+
return output
20+
}
21+
22+
func merge(a, b []int) []int {
23+
output := make([]int, len(a)+len(b))
24+
var i, j int
25+
for k := 0; k < len(a)+len(b); k++ {
26+
if isGreater(a[i:], b[j:]) {
27+
output[k] = a[i]
28+
i++
29+
continue
30+
}
31+
output[k] = b[j]
32+
j++
33+
}
34+
return output
35+
}
36+
37+
func isGreater(a, b []int) bool {
38+
for i := 0; i < len(a) && i < len(b); i++ {
39+
if a[i] != b[i] {
40+
return a[i] > b[i]
41+
}
42+
}
43+
return len(a) > len(b)
44+
}
45+
46+
func maximumNumberInSequence(input []int, k int) []int {
47+
stack := make([]int, 0, k)
48+
for i, num := range input {
49+
for len(stack) > 0 && len(input)-i > k-len(stack) && num > stack[len(stack)-1] {
50+
stack = stack[:len(stack)-1]
51+
}
52+
if len(stack) < k {
53+
stack = append(stack, num)
54+
}
55+
}
56+
return stack
57+
}
58+
59+
func min(a, b int) int {
60+
if a < b {
61+
return a
62+
}
63+
return b
64+
}

greedy/max_number_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package greedy
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
/*
9+
TestMaxNumber tests solution(s) with the following signature and problem description:
10+
11+
func MaxNumber(number1, number2 []int, n int) []int
12+
13+
Given two numbers represented as list of positive integers, and an integer n, return the
14+
largest possible integer with n digits that can be constructed by merging digits from two
15+
numbers while respecting the order of digits in each number.
16+
17+
For example given {5, 4, 3, 2, 1}, {9, 8, 7, 6} and 9, it should return a 9 digit number
18+
{9, 8, 7, 6, 5, 4, 3, 2, 1}.
19+
*/
20+
func TestMaxNumber(t *testing.T) {
21+
tests := []struct {
22+
number1 []int
23+
number2 []int
24+
k int
25+
largestNumber []int
26+
}{
27+
{[]int{}, []int{}, 1, []int{}},
28+
{[]int{}, []int{1}, 1, []int{1}},
29+
{[]int{0}, []int{1}, 1, []int{1}},
30+
{[]int{0}, []int{1}, 2, []int{1, 0}},
31+
{[]int{1}, []int{0}, 2, []int{1, 0}},
32+
{[]int{1}, []int{2}, 4, []int{}},
33+
{[]int{2}, []int{1}, 4, []int{}},
34+
{[]int{3, 2, 1}, []int{1}, 3, []int{3, 2, 1}},
35+
{[]int{6, 9}, []int{6, 0, 4}, 5, []int{6, 9, 6, 0, 4}},
36+
{[]int{1, 2, 3}, []int{1, 2, 3}, 4, []int{3, 1, 2, 3}},
37+
{[]int{5, 4, 3, 2, 1}, []int{9, 8, 7, 6}, 9, []int{9, 8, 7, 6, 5, 4, 3, 2, 1}},
38+
{[]int{5, 4, 3, 2, 1}, []int{9, 8, 7, 6}, 8, []int{9, 8, 7, 6, 5, 4, 3, 2}},
39+
}
40+
41+
for i, test := range tests {
42+
if got := MaxNumber(test.number1, test.number2, test.k); !reflect.DeepEqual(got, test.largestNumber) {
43+
t.Fatalf("Failed test case #%d. Want %#v got %#v", i, test.largestNumber, got)
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)