diff --git a/1_partition/main.go b/1_partition/main.go new file mode 100644 index 0000000..f8e022a --- /dev/null +++ b/1_partition/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" +) + +func rearrange(s []int, pivot int) (i int) { + p := s[pivot] + for j := 0; j < len(s); j++ { + if s[j] < p { + s[i], s[j] = s[j], s[i] + i++ + } + } + return +} + +func main() { + s := []int{3, 2, 4, 6, 1} + fmt.Println(rearrange(s, 2), s) +} diff --git a/1_partition/main_test.go b/1_partition/main_test.go new file mode 100644 index 0000000..ec9b513 --- /dev/null +++ b/1_partition/main_test.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" + "testing" +) + +func TestRearrange(t *testing.T) { + for _, tc := range []struct { + s []int + pivot int + want int + }{ + {[]int{1, 2}, 1, 1}, + {[]int{3, 2, 4, 6}, 2, 2}, + {[]int{3, 2, 4, 6, 1}, 2, 3}, + {[]int{4, 4, 4, 4}, 2, 0}, + {[]int{8, 4, 1, 0, 5, 9, 3, 7, 2, 6}, 4, 5}, // no repeated elements + {[]int{9, 6, 1, 7, 5, 9, 6, 5, 2, 6}, 9, 4}, // repeated elements + {[]int{9, 6, 1, 7, 5, 9, 6, 5, 2, 0}, 9, 0}, // empty left side + } { + t.Run(fmt.Sprint(tc.s)+"_"+fmt.Sprint(tc.pivot), func(t *testing.T) { + got := rearrange(tc.s, tc.pivot) + CompareLeftAndRight(tc.s, got) + if got != tc.want { + t.Errorf("rearrange(%v, %v) = %v, want %v", tc.s, tc.pivot, got, tc.want) + } + }) + } +} + +func CompareLeftAndRight(s []int, index int) error { + for _, i := range s[:index] { + for _, j := range s[index:] { + if i >= j { + panic("the returned slice is incorrect") + } + } + } + return nil +} diff --git a/2_numbers/main.go b/2_numbers/main.go new file mode 100644 index 0000000..fa79724 --- /dev/null +++ b/2_numbers/main.go @@ -0,0 +1,22 @@ +package main + +import "fmt" + +func Numbers(n int) ([]int, []int) { + return Num(n, nil, nil) +} + +func Num(n int, ascending, descenging []int) ([]int, []int) { + if n == 0 { + return ascending, descenging + } + ascending, descenging = Num(n-1, ascending, append(descenging, n)) // (2) + return append(ascending, n), descenging // (1) +} + +func main() { + fmt.Println(Numbers(4)) +} + +// Time complexity: O(n) +// Space complexity: O(n) diff --git a/2_numbers/main_test.go b/2_numbers/main_test.go new file mode 100644 index 0000000..41071a9 --- /dev/null +++ b/2_numbers/main_test.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + "reflect" + "testing" +) + +func TestNumbers(t *testing.T) { + for _, tc := range []struct { + input int + }{ + {0}, + {1}, + {2}, + {3}, + {4}, + {5}, + {6}, + {7}, + {8}, + {9}, + {10}, + {11}, + {19}, + {20}, + {23}, + {25}, + {33}, + {57}, + {68}, + {100}, + {101}, + {123}, + {376}, + {1279}, + {98764}, + } { + t.Run(fmt.Sprint(tc.input), func(t *testing.T) { + var wantascending, wantdescending []int + for i, j := 1, tc.input; i <= tc.input; i, j = i+1, j-1 { + wantascending, wantdescending = append(wantascending, i), append(wantdescending, j) + } + if gotascending, gotdescending := Numbers(tc.input); !reflect.DeepEqual(gotascending, wantascending) || !reflect.DeepEqual(gotdescending, wantdescending) { + t.Errorf("Numbers(%v) = %v %v, want %v %v", tc.input, gotascending, gotdescending, wantascending, wantdescending) + } + }) + } +} diff --git a/3_fibonacci/main.go b/3_fibonacci/main.go new file mode 100644 index 0000000..64da8eb --- /dev/null +++ b/3_fibonacci/main.go @@ -0,0 +1,23 @@ +package main + +import "fmt" + +func Fibonacci(n int) []int { + return fib(n, 0, 1, nil) +} + +func fib(n, a, b int, result []int) []int { + result = append(result, a) + if b > n { + return result + } + return fib(n, b, a+b, result) +} + +func main() { + fmt.Println(Fibonacci(13)) + fmt.Println(Fibonacci(15)) +} + +// Time complexity: O(n) +// Space complexity: O(n) diff --git a/3_fibonacci/main_test.go b/3_fibonacci/main_test.go new file mode 100644 index 0000000..9877116 --- /dev/null +++ b/3_fibonacci/main_test.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "reflect" + "testing" +) + +var numbers = []int{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181} + +func TestFibonacci(t *testing.T) { + for _, tc := range []struct { + input int + }{ + {1}, + {2}, + {3}, + {4}, + {5}, + {6}, + {7}, + {8}, + {12}, + {13}, + {18}, + {20}, + {25}, + {30}, + {56}, + {99}, + {100}, + {143}, + {144}, + {145}, + {228}, + {4200}, + } { + t.Run(fmt.Sprint(tc.input), func(t *testing.T) { + want := numbers + for i := range numbers { + if numbers[i] > tc.input { + want = numbers[:i] + break + } + } + if got := Fibonacci(tc.input); !reflect.DeepEqual(got, want) { + t.Errorf("Fibonacci(%v) = %v, want %v", tc.input, got, want) + } + }) + } +} diff --git a/4_is_power_of_2/main.go b/4_is_power_of_2/main.go new file mode 100644 index 0000000..02f0e38 --- /dev/null +++ b/4_is_power_of_2/main.go @@ -0,0 +1,22 @@ +package main + +import "fmt" + +func IsPowerOf2(n int) bool { + if n == 1 { + return true + } + if n%2 != 0 || n == 0 { + return false + } + return IsPowerOf2(n / 2) +} + +func main() { + fmt.Println(IsPowerOf2(32)) + fmt.Println(IsPowerOf2(31)) + fmt.Println(IsPowerOf2(48)) +} + +// Time complexity: O(log(n)) +// Space complexity: O(log(n)) diff --git a/4_is_power_of_2/main_test.go b/4_is_power_of_2/main_test.go new file mode 100644 index 0000000..170fd84 --- /dev/null +++ b/4_is_power_of_2/main_test.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + "testing" +) + +func TestIsPowerOf2(t *testing.T) { + for _, tc := range []struct { + input int + want bool + }{ + {0, false}, + {1, true}, + {-1, false}, + {2, true}, + {3, false}, + {4, true}, + {5, false}, + {6, false}, + {7, false}, + {8, true}, + {9, false}, + {10, false}, + {15, false}, + {16, true}, + {20, false}, + {32, true}, + {-32, false}, + {64, true}, + {-64, false}, + {65, false}, + {-65, false}, + {66, false}, + {-66, false}, + {128, true}, + {256, true}, + {512, true}, + {1024, true}, + {1524, false}, + {2048, true}, + } { + t.Run(fmt.Sprint(tc.input), func(t *testing.T) { + if got := IsPowerOf2(tc.input); got != tc.want { + t.Errorf("IsPowerOf2(%v) = %v, want %v", tc.input, got, tc.want) + } + }) + } +} diff --git a/5_sum_digits/main.go b/5_sum_digits/main.go new file mode 100644 index 0000000..552cc72 --- /dev/null +++ b/5_sum_digits/main.go @@ -0,0 +1,17 @@ +package main + +import "fmt" + +func SumDigits(n int) int { + if n == 0 { + return 0 + } + return SumDigits(n/10) + n%10 +} + +func main() { + fmt.Println(SumDigits(561)) +} + +// Time complexity: O(log(n)) +// Space complexity: O(log(n)) diff --git a/5_sum_digits/main_test.go b/5_sum_digits/main_test.go new file mode 100644 index 0000000..4cf93e9 --- /dev/null +++ b/5_sum_digits/main_test.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "testing" +) + +func TestSumDigits(t *testing.T) { + for _, tc := range []struct { + input int + want int + }{ + {0, 0}, + {1, 1}, + {2, 2}, + {5, 5}, + {9, 9}, + {10, 1}, + {11, 2}, + {12, 3}, + {18, 9}, + {19, 10}, + {20, 2}, + {24, 6}, + {55, 10}, + {89, 17}, + {100, 1}, + {123, 6}, + {561, 12}, + {345678, 33}, + } { + t.Run(fmt.Sprint(tc.input), func(t *testing.T) { + if got := SumDigits(tc.input); got != tc.want { + t.Errorf("SumDigits(%v) = %v, want %v", tc.input, got, tc.want) + } + }) + } +} diff --git a/6_max_number/main.go b/6_max_number/main.go new file mode 100644 index 0000000..cc3b682 --- /dev/null +++ b/6_max_number/main.go @@ -0,0 +1,28 @@ +package main + +import "fmt" + +func MaxNumber(s []int) (int, int) { + return Max(s, -1, -1) +} + +func Max(s []int, max, secondmax int) (int, int) { + if len(s) == 0 { + return max, secondmax + } + if s[0] >= max { + secondmax = max + max = s[0] + } + if s[0] > secondmax && s[0] < max { + secondmax = s[0] + } + return Max(s[1:], max, secondmax) +} + +func main() { + fmt.Println(MaxNumber([]int{1, 2, 6, 9, 3, 1, 10, 15, 7, 11})) +} + +// Time complexity: O(n) +// Space complexity: O(n) diff --git a/6_max_number/main_test.go b/6_max_number/main_test.go new file mode 100644 index 0000000..f8cf9fd --- /dev/null +++ b/6_max_number/main_test.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "testing" +) + +func TestMaxNumber(t *testing.T) { + for _, tc := range []struct { + input []int + wantmax int + wantsecondmax int + }{ + {[]int{}, -1, -1}, + {[]int{0}, 0, -1}, + {[]int{1}, 1, -1}, + {[]int{1, 1}, 1, 1}, + {[]int{0, 1}, 1, 0}, + {[]int{1, 0}, 1, 0}, + {[]int{2, 1}, 2, 1}, + {[]int{1, 2}, 2, 1}, + {[]int{2, 2}, 2, 2}, + {[]int{1, 2, 3}, 3, 2}, + {[]int{4, 2, 3, 1}, 4, 3}, + {[]int{1, 2, 6, 9, 3, 1, 10, 15, 7, 11}, 15, 11}, + {[]int{1, 2, 6, 9, 3, 1, 10, 15, 7, 15}, 15, 15}, + {[]int{1, 2, 6, 9, 3, 1, 10, 15, 7, 16}, 16, 15}, + {[]int{1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1}, 2, 1}, + } { + t.Run(fmt.Sprint(tc.input), func(t *testing.T) { + if gotmax, gotsecondmax := MaxNumber(tc.input); gotmax != tc.wantmax || gotsecondmax != tc.wantsecondmax { + t.Errorf("MaxNumber(%v) = %v %v, want %v %v", tc.input, gotmax, gotsecondmax, tc.wantmax, tc.wantsecondmax) + } + }) + } +} diff --git a/optional_exercise/main.go b/optional_exercise/main.go new file mode 100644 index 0000000..3b5137b --- /dev/null +++ b/optional_exercise/main.go @@ -0,0 +1,64 @@ +package main + +import "fmt" + +func partition(s []int) (i int) { + p := s[(len(s) - 1)] + for j := 0; j < len(s); j++ { + if s[j] < p { + s[i], s[j] = s[j], s[i] + i++ + } + } + s[i], s[(len(s)-1)] = s[(len(s)-1)], s[i] + return i +} + +// For each call: +// - partition: space complexity O(1) +// - for the quick sort itself (one call): +// - best case: O(1) * O(LogN) = O(LogN) +// - worst case: O(1) * O(N) = O(N) +// +// Stack, LIFO (Last In First Out) +// In: 1 2 3 4 5 +// Out: 5 4 3 2 1 +// Stack contains: Local variables, Arguments, Return address + +func QuickSort(s []int) (result []int) { + s1, s2 := make([]int, len(s)), make([]int, len(s)) + copy(s1, s) + copy(s2, s) + for len(s1) >= 2 || len(s2) >= 2 { + if len(s1) >= 2 { + p := partition(s1) + s1 = s1[:p] + fmt.Println("s1:", s1) + } + result = append(result, s1...) + if len(s2) >= 2 { + p := partition(s2) + s2 = s2[p+1:] + fmt.Println("s2:", s2) + } + result = append(result, s2...) + } + return +} + +// 1 2 3 4 5 6 7 8 +// Ideal case depth: LogN +// Time complexity: O(NLogN) +// +// Worst case depth: N +// Time complexity: O(N^2) +// +// Pivot is everything!!! +// +// 25% 75% NLogN + +func main() { + s := []int{4, 3, 17, 33, 101, 17, 6, 2} + fmt.Println(QuickSort(s)) + //fmt.Println(s) +} diff --git a/optional_exercise/main_test.go b/optional_exercise/main_test.go new file mode 100644 index 0000000..d658543 --- /dev/null +++ b/optional_exercise/main_test.go @@ -0,0 +1,53 @@ +package main + +import ( + "fmt" + "reflect" + "testing" +) + +func TestQuickSort(t *testing.T) { + for _, tc := range []struct { + input []int + want []int + }{ + {[]int{0}, []int{0}}, + {[]int{1}, []int{1}}, + {[]int{2}, []int{2}}, + {[]int{12}, []int{12}}, + {[]int{1, 1}, []int{1, 1}}, + {[]int{1, 2}, []int{1, 2}}, + {[]int{2, 1}, []int{1, 2}}, + {[]int{2, 2}, []int{2, 2}}, + {[]int{1, 1, 1}, []int{1, 1, 1}}, + {[]int{1, 3, 3}, []int{1, 3, 3}}, + {[]int{1, 2, 3}, []int{1, 2, 3}}, + {[]int{1, 3, 2}, []int{1, 2, 3}}, + {[]int{2, 1, 3}, []int{1, 2, 3}}, + {[]int{2, 3, 1}, []int{1, 2, 3}}, + {[]int{3, 2, 1}, []int{1, 2, 3}}, + {[]int{3, 1, 2}, []int{1, 2, 3}}, + {[]int{1, 1, 1, 1}, []int{1, 1, 1, 1}}, + {[]int{4, 4, 4, 4}, []int{4, 4, 4, 4}}, + {[]int{1, 2, 3, 5}, []int{1, 2, 3, 5}}, + {[]int{5, 1, 2, 3}, []int{1, 2, 3, 5}}, + {[]int{5, 1, 2, 3, 5}, []int{1, 2, 3, 5, 5}}, + {[]int{5, 1, 2, 3, 5, 2}, []int{1, 2, 2, 3, 5, 5}}, + {[]int{8, 2, 5, 1, 3, 1, 7, 5}, []int{1, 1, 2, 3, 5, 5, 7, 8}}, + {[]int{8, 4, 1, 0, 5, 9, 3, 7, 2, 6}, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}, + {[]int{9, 6, 1, 7, 5, 9, 6, 5, 2, 6}, []int{1, 2, 5, 5, 6, 6, 6, 7, 9, 9}}, + {[]int{9, 6, 1, 7, 5, 9, 6, 5, 2, 0}, []int{0, 1, 2, 5, 5, 6, 6, 7, 9, 9}}, + {[]int{4, 3, 17, 33, 101, 17, 6, 2}, []int{2, 3, 4, 6, 17, 17, 33, 101}}, + {[]int{4, 3, 17, 33, 101, 33, 17, 6, 2}, []int{2, 3, 4, 6, 17, 17, 33, 33, 101}}, + {[]int{4, 3, 17, 33, 101, 34, 17, 6, 2}, []int{2, 3, 4, 6, 17, 17, 33, 34, 101}}, + {[]int{4, 3, 17, 34, 101, 33, 17, 6, 2}, []int{2, 3, 4, 6, 17, 17, 33, 34, 101}}, + } { + t.Run(fmt.Sprint(tc.input), func(t *testing.T) { + got := make([]int, len(tc.input)) + copy(got, tc.input) + if QuickSort(got); !reflect.DeepEqual(got, tc.want) { + t.Errorf("QuickSort(%v) = %v, want %v", tc.input, got, tc.want) + } + }) + } +}