mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-06-07 04:33:31 +02:00
updated util packages
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
package algos
|
||||
|
||||
// MakePermutations will make all permutations of the numbers input
|
||||
// returns a pointer to avoid copying a large number of permutations
|
||||
func MakePermutations(numbers []int) *[][]int {
|
||||
result := make([][]int, 0)
|
||||
|
||||
swapRecurseBacktrack(numbers, 0, &result)
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
// helper function to generate permutations
|
||||
func swapRecurseBacktrack(numbers []int, startIndex int, results *[][]int) {
|
||||
if startIndex == len(numbers) {
|
||||
// make a copy of the perm
|
||||
perm := make([]int, len(numbers))
|
||||
copy(perm, numbers)
|
||||
|
||||
// assign the value at the pointer results to the appended slice (dereferenced) results w/ perm
|
||||
*results = append(*results, perm)
|
||||
}
|
||||
|
||||
for i := startIndex; i < len(numbers); i++ {
|
||||
// swap numbers
|
||||
numbers[startIndex], numbers[i] = numbers[i], numbers[startIndex]
|
||||
|
||||
// recurse with startIndex incremented
|
||||
swapRecurseBacktrack(numbers, startIndex+1, results)
|
||||
|
||||
// backtrack
|
||||
numbers[startIndex], numbers[i] = numbers[i], numbers[startIndex]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package algos
|
||||
|
||||
// RotateGrid returns the inputted grid, rotated counterclockwise
|
||||
// call it multiple times for 180, & 270 degree rotations
|
||||
func RotateStringGrid(grid [][]string) [][]string {
|
||||
rotated := make([][]string, len(grid[0]))
|
||||
for i := range rotated {
|
||||
rotated[i] = make([]string, len(grid))
|
||||
}
|
||||
|
||||
for i := 0; i < len(grid); i++ {
|
||||
for j := 0; j < len(grid[0]); j++ {
|
||||
rotated[len(grid[0])-1-j][i] = grid[i][j]
|
||||
}
|
||||
}
|
||||
return rotated
|
||||
}
|
||||
|
||||
// RotateGridInts will transpose a 2D array of ints
|
||||
func RotateIntGrid(grid [][]int) [][]int {
|
||||
rotated := make([][]int, len(grid[0]))
|
||||
for i := range rotated {
|
||||
rotated[i] = make([]int, len(grid))
|
||||
}
|
||||
|
||||
for i := 0; i < len(grid); i++ {
|
||||
for j := 0; j < len(grid[0]); j++ {
|
||||
rotated[len(grid[0])-1-j][i] = grid[i][j]
|
||||
}
|
||||
}
|
||||
return rotated
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package algos
|
||||
|
||||
// SlidingWindowSum returns the left and right indices of a window within the
|
||||
// nums slice, where all numbers in the slice [left:right] sum up to targetSum
|
||||
// It also returns a boolean indicating if a valid window is found
|
||||
func SlidingWindowSum(nums []int, targetSum int) (leftIndex, rightIndex int, found bool) {
|
||||
var left, right, sum int
|
||||
for right < len(nums) {
|
||||
switch {
|
||||
case left == right:
|
||||
sum += nums[right]
|
||||
right++
|
||||
case sum > targetSum:
|
||||
sum -= nums[left]
|
||||
left++
|
||||
case sum < targetSum:
|
||||
sum += nums[right]
|
||||
right++
|
||||
}
|
||||
if sum == targetSum {
|
||||
return left, right, true
|
||||
}
|
||||
}
|
||||
return 0, 0, false
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package algos
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSlidingWindowSum(t *testing.T) {
|
||||
type args struct {
|
||||
nums []int
|
||||
targetSum int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantLeftIndex int
|
||||
wantRightIndex int
|
||||
wantFound bool
|
||||
}{
|
||||
{"found 1", args{[]int{-1, 23, 12, 14, 3, 4}, 21}, 3, 6, true},
|
||||
{"found 2", args{[]int{-1, 23, 12, 14, 3, 4, 59}, 21}, 3, 6, true},
|
||||
{"not found 1", args{[]int{0, 1, 2, 3, 4, 5, 6}, 45}, 0, 0, false},
|
||||
{"not found 2", args{[]int{0, 1, 2, 3, 4, 5, 6}, -34}, 0, 0, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotLeftIndex, gotRightIndex, gotFound := SlidingWindowSum(tt.args.nums, tt.args.targetSum)
|
||||
if gotLeftIndex != tt.wantLeftIndex {
|
||||
t.Errorf("SlidingWindowSum() gotLeftIndex = %v, want %v", gotLeftIndex, tt.wantLeftIndex)
|
||||
}
|
||||
if gotRightIndex != tt.wantRightIndex {
|
||||
t.Errorf("SlidingWindowSum() gotRightIndex = %v, want %v", gotRightIndex, tt.wantRightIndex)
|
||||
}
|
||||
if gotFound != tt.wantFound {
|
||||
t.Errorf("SlidingWindowSum() gotFound = %v, want %v", gotFound, tt.wantFound)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package algos
|
||||
|
||||
// TwoSum returns the two numbers found within a slice that add up to
|
||||
// the input target, and a boolean to check if the sum is found or not
|
||||
func TwoSum(nums []int, target int) (num1 int, num2 int, found bool) {
|
||||
seen := make(map[int]bool, len(nums))
|
||||
|
||||
for _, v := range nums {
|
||||
if seen[target-v] {
|
||||
return target - v, v, true
|
||||
}
|
||||
seen[v] = true
|
||||
}
|
||||
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
// ThreeSum returns the three values within a slice that sum to the
|
||||
// target input and a boolean stating if a match was found
|
||||
func ThreeSum(nums []int, target int) (int, int, int, bool) {
|
||||
for i, v := range nums {
|
||||
if num1, num2, found := TwoSum(nums[i+1:], target-v); found {
|
||||
return v, num1, num2, true
|
||||
}
|
||||
}
|
||||
return 0, 0, 0, false
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package algos
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestTwoSum(t *testing.T) {
|
||||
type args struct {
|
||||
nums []int
|
||||
target int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantNum1 int
|
||||
wantNum2 int
|
||||
wantFound bool
|
||||
}{
|
||||
{"found 1", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 6}, 2, 4, true},
|
||||
{"found 2", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 17}, 8, 9, true},
|
||||
{"not found 1", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 62}, 0, 0, false},
|
||||
{"not found 2", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, -12}, 0, 0, false},
|
||||
{"found 3", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -13}, -12}, 1, -13, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotNum1, gotNum2, gotFound := TwoSum(tt.args.nums, tt.args.target)
|
||||
if gotNum1 != tt.wantNum1 {
|
||||
t.Errorf("TwoSum() gotNum1 = %v, want %v", gotNum1, tt.wantNum1)
|
||||
}
|
||||
if gotNum2 != tt.wantNum2 {
|
||||
t.Errorf("TwoSum() gotNum2 = %v, want %v", gotNum2, tt.wantNum2)
|
||||
}
|
||||
if gotFound != tt.wantFound {
|
||||
t.Errorf("TwoSum() gotFound = %v, want %v", gotFound, tt.wantFound)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestThreeSum(t *testing.T) {
|
||||
type args struct {
|
||||
nums []int
|
||||
target int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int
|
||||
want1 int
|
||||
want2 int
|
||||
want3 bool
|
||||
}{
|
||||
{"found 1", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 6}, 0, 2, 4, true},
|
||||
{"found 2", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 17}, 0, 8, 9, true},
|
||||
{"not found 1", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 62}, 0, 0, 0, false},
|
||||
{"not found 2", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, -12}, 0, 0, 0, false},
|
||||
{"found 3", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -13}, -12}, 0, 1, -13, true},
|
||||
{"found 3", args{[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 27}, 8, 9, 10, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, got1, got2, got3 := ThreeSum(tt.args.nums, tt.args.target)
|
||||
if got != tt.want {
|
||||
t.Errorf("ThreeSum() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if got1 != tt.want1 {
|
||||
t.Errorf("ThreeSum() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
if got2 != tt.want2 {
|
||||
t.Errorf("ThreeSum() got2 = %v, want %v", got2, tt.want2)
|
||||
}
|
||||
if got3 != tt.want3 {
|
||||
t.Errorf("ThreeSum() got3 = %v, want %v", got3, tt.want3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user