diff --git a/pullrequests/combination_sum/step1.go b/pullrequests/combination_sum/step1.go new file mode 100644 index 0000000..31819b8 --- /dev/null +++ b/pullrequests/combination_sum/step1.go @@ -0,0 +1,30 @@ +//lint:file-ignore U1000 Ignore all unused code +package template + +/* +時間:24分 +少し前にバックトラッキングの問題を解いたので、ある条件を満たす全ての組み合わせを求めるためにバックトラッキングを使って解きました。 +*/ +func combinationSumStep1(candidates []int, target int) [][]int { + var combinations [][]int + var stack []int + var findCombinations func(int, int) + findCombinations = func(curr int, sum int) { + if sum == target { + combination := make([]int, len(stack)) + copy(combination, stack) + combinations = append(combinations, combination) + return + } + if sum > target { + return + } + for i := curr; i < len(candidates); i++ { + stack = append(stack, candidates[i]) + findCombinations(i, sum+candidates[i]) + stack = stack[:len(stack)-1] + } + } + findCombinations(0, 0) + return combinations +} diff --git a/pullrequests/combination_sum/step2.go b/pullrequests/combination_sum/step2.go new file mode 100644 index 0000000..28644ff --- /dev/null +++ b/pullrequests/combination_sum/step2.go @@ -0,0 +1,56 @@ +//lint:file-ignore U1000 Ignore all unused code +package template + +/* +Step1では再帰を使ってバックトラッキングを解いたので、スタックを使った方法も実装しました。 +また、Step1の実装のリファクタもしました。 +*/ +func combinationSumBacktrackingStack(candidates []int, target int) [][]int { + combinations := [][]int{} + type state struct { + combination []int + sum int + index int + } + stack := []state{{[]int{}, 0, 0}} + for len(stack) > 0 { + current := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if current.sum == target { + combinations = append(combinations, append([]int{}, current.combination...)) + continue + } + for i := current.index; i < len(candidates); i++ { + newSum := current.sum + candidates[i] + if newSum > target { + continue + } + newCombination := append([]int{}, current.combination...) + newCombination = append(newCombination, candidates[i]) + stack = append(stack, state{newCombination, newSum, i}) + } + } + return combinations +} + +func combinationSumBacktrackingRecursion(candidates []int, target int) [][]int { + var combinations [][]int + var stack []int + var generateCombinations func(int, int) + generateCombinations = func(currentIndex int, sum int) { + if sum == target { + combinations = append(combinations, append([]int{}, stack...)) + return + } + if sum > target { + return + } + for i := currentIndex; i < len(candidates); i++ { + stack = append(stack, candidates[i]) + generateCombinations(i, sum+candidates[i]) + stack = stack[:len(stack)-1] + } + } + generateCombinations(0, 0) + return combinations +} diff --git a/pullrequests/combination_sum/step3.go b/pullrequests/combination_sum/step3.go new file mode 100644 index 0000000..13715f3 --- /dev/null +++ b/pullrequests/combination_sum/step3.go @@ -0,0 +1,21 @@ +//lint:file-ignore U1000 Ignore all unused code +package template + +/* +動的計画法を使った方法も実装しました。 +targetごとに組み合わせを求めると重複する組み合わせが生じてしまうので、candidateごとに組み合わせを求めるようにしました。 +*/ +func combinationSumDP(candidates []int, target int) [][]int { + combinationsGroups := make([][][]int, target+1) + combinationsGroups[0] = [][]int{{}} + for _, candidate := range candidates { + for i := candidate; i <= target; i++ { + for _, combination := range combinationsGroups[i-candidate] { + newCombination := append([]int{}, combination...) + newCombination = append(newCombination, candidate) + combinationsGroups[i] = append(combinationsGroups[i], newCombination) + } + } + } + return combinationsGroups[target] +} diff --git a/pullrequests/combination_sum/step4.go b/pullrequests/combination_sum/step4.go new file mode 100644 index 0000000..43e04ef --- /dev/null +++ b/pullrequests/combination_sum/step4.go @@ -0,0 +1,56 @@ +//lint:file-ignore U1000 Ignore all unused code +package template + +/* +Step1では再帰を使ってバックトラッキングを解いたので、スタックを使った方法も実装しました。 +また、Step1の実装のリファクタもしました。 +*/ +func combinationSumBacktrackingStackStep4(candidates []int, target int) [][]int { + combinations := [][]int{} + type state struct { + combination []int + sum int + index int + } + stack := []state{{[]int{}, 0, 0}} + for len(stack) > 0 { + current := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if current.sum == target { + combinations = append(combinations, current.combination) + continue + } + for i := current.index; i < len(candidates); i++ { + newSum := current.sum + candidates[i] + if newSum > target { + continue + } + newCombination := append([]int{}, current.combination...) + newCombination = append(newCombination, candidates[i]) + stack = append(stack, state{newCombination, newSum, i}) + } + } + return combinations +} + +func combinationSumBacktrackingRecursionStep4(candidates []int, target int) [][]int { + var combinations [][]int + var stack []int + var generateCombinations func(int, int) + generateCombinations = func(currentIndex int, sum int) { + if sum == target { + combinations = append(combinations, append([]int{}, stack...)) + return + } + if sum > target { + return + } + for i := currentIndex; i < len(candidates); i++ { + stack = append(stack, candidates[i]) + generateCombinations(i, sum+candidates[i]) + stack = stack[:len(stack)-1] + } + } + generateCombinations(0, 0) + return combinations +}