Skip to content

Commit

Permalink
feat(go/backtracking): add go code (krahets#488)
Browse files Browse the repository at this point in the history
* feat(go/backtracking): add go code

* feat(backtracking): add n_queens in go

* feat(backtracking): add /preorder_traversal_i_compact in go

* feat(backtracking): add /preorder_traversal_ii_compact in go

* feat(backtracking): add /preorder_traversal_ii_template in go

* feat(backtracking): add preorder_traversal_iii_compact in go

* feat(backtracking): add preorder_traversal_test in go

* feat(backtracking): add permutations_i in go

* feat(backtracking): add permutations_ii in go

* feat(backtracking): add permutation_test in go

* feat(backtracking): fix bug in go

* Update permutations_i.go

---------

Co-authored-by: Yudong Jin <[email protected]>
  • Loading branch information
Reanon and krahets authored May 14, 2023
1 parent 170713c commit a6b3f72
Show file tree
Hide file tree
Showing 10 changed files with 419 additions and 0 deletions.
55 changes: 55 additions & 0 deletions codes/go/chapter_backtracking/n_queens.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// File: n_queens.go
// Created Time: 2023-05-09
// Author: Reanon ([email protected])

package chapter_backtracking

/* 回溯算法:N 皇后 */
func backtrack(row, n int, state *[][]string, res *[][][]string, cols, diags1, diags2 *[]bool) {
// 当放置完所有行时,记录解
if row == n {
newState := make([][]string, len(*state))
for i, _ := range newState {
newState[i] = make([]string, len((*state)[0]))
copy(newState[i], (*state)[i])

}
*res = append(*res, newState)
}
// 遍历所有列
for col := 0; col < n; col++ {
// 计算该格子对应的主对角线和副对角线
diag1 := row - col + n - 1
diag2 := row + col
// 剪枝:不允许该格子所在 (列 或 主对角线 或 副对角线) 包含皇后
if !((*cols)[col] || (*diags1)[diag1] || (*diags2)[diag2]) {
// 尝试:将皇后放置在该格子
(*state)[row][col] = "Q"
(*cols)[col], (*diags1)[diag1], (*diags2)[diag2] = true, true, true
// 放置下一行
backtrack(row+1, n, state, res, cols, diags1, diags2)
// 回退:将该格子恢复为空位
(*state)[row][col] = "#"
(*cols)[col], (*diags1)[diag1], (*diags2)[diag2] = false, false, false
}
}
}

func nQueens(n int) [][][]string {
// 初始化 n*n 大小的棋盘,其中 'Q' 代表皇后,'#' 代表空位
state := make([][]string, n)
for i := 0; i < n; i++ {
row := make([]string, n)
for i := 0; i < n; i++ {
row[i] = "#"
}
state[i] = row
}
// 记录列是否有皇后
cols := make([]bool, n)
diags1 := make([]bool, 2*n-1)
diags2 := make([]bool, 2*n-1)
res := make([][][]string, 0)
backtrack(0, n, &state, &res, &cols, &diags1, &diags2)
return res
}
24 changes: 24 additions & 0 deletions codes/go/chapter_backtracking/n_queens_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// File: n_queens_test.go
// Created Time: 2023-05-14
// Author: Reanon ([email protected])

package chapter_backtracking

import (
"fmt"
"testing"
)

func TestNQueens(t *testing.T) {
n := 4
res := nQueens(n)

fmt.Println("输入棋盘长宽为 ", n)
fmt.Println("皇后放置方案共有 ", len(res), " 种")
for _, state := range res {
fmt.Println("--------------------")
for _, row := range state {
fmt.Println(row)
}
}
}
33 changes: 33 additions & 0 deletions codes/go/chapter_backtracking/permutation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// File: preorder_traversal_i_compact_test.go
// Created Time: 2023-05-09
// Author: Reanon ([email protected])

package chapter_backtracking

import (
"fmt"
"testing"

. "github.com/krahets/hello-algo/pkg"
)

func TestPermutationI(t *testing.T) {
/* 全排列 I */
nums := []int{1, 2, 3}
fmt.Printf("输入数组 nums = ")
PrintSlice(nums)

res := permutationsI(nums)
fmt.Printf("所有排列 res = ")
fmt.Println(res)
}

func TestPermutationII(t *testing.T) {
nums := []int{1, 2, 2}
fmt.Printf("输入数组 nums = ")
PrintSlice(nums)

res := permutationsII(nums)
fmt.Printf("所有排列 res = ")
fmt.Println(res)
}
38 changes: 38 additions & 0 deletions codes/go/chapter_backtracking/permutations_i.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// File: permutations_i.go
// Created Time: 2023-05-14
// Author: Reanon ([email protected])

package chapter_backtracking

/* 回溯算法:全排列 I */
func backtrackI(state *[]int, choices *[]int, selected *[]bool, res *[][]int) {
// 当状态长度等于元素数量时,记录解
if len(*state) == len(*choices) {
newState := append([]int{}, *state...)
*res = append(*res, newState)
}
// 遍历所有选择
for i := 0; i < len(*choices); i++ {
choice := (*choices)[i]
// 剪枝:不允许重复选择元素 且 不允许重复选择相等元素
if !(*selected)[i] {
// 尝试:做出选择,更新状态
(*selected)[i] = true
*state = append(*state, choice)
// 进行下一轮选择
backtrackI(state, choices, selected, res)
// 回退:撤销选择,恢复到之前的状态
(*selected)[i] = false
*state = (*state)[:len(*state)-1]
}
}
}

/* 全排列 I */
func permutationsI(nums []int) [][]int {
res := make([][]int, 0)
state := make([]int, 0)
selected := make([]bool, len(nums))
backtrackI(&state, &nums, &selected, &res)
return res
}
45 changes: 45 additions & 0 deletions codes/go/chapter_backtracking/permutations_ii.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// File: permutations_i.go
// Created Time: 2023-05-14
// Author: Reanon ([email protected])

// File: permutations_i.go
// Created Time: 2023-05-14
// Author: Reanon ([email protected])

package chapter_backtracking

/* 回溯算法:全排列 II */
func backtrackII(state *[]int, choices *[]int, selected *[]bool, res *[][]int) {
// 当状态长度等于元素数量时,记录解
if len(*state) == len(*choices) {
newState := append([]int{}, *state...)
*res = append(*res, newState)
}
// 遍历所有选择
duplicated := make(map[int]struct{}, 0)
for i := 0; i < len(*choices); i++ {
choice := (*choices)[i]
// 剪枝:不允许重复选择元素 且 不允许重复选择相等元素
if _, ok := duplicated[choice]; !ok && !(*selected)[i] {
// 尝试:做出选择,更新状态
// 记录选择过的元素值
duplicated[choice] = struct{}{}
(*selected)[i] = true
*state = append(*state, choice)
// 进行下一轮选择
backtrackI(state, choices, selected, res)
// 回退:撤销选择,恢复到之前的状态
(*selected)[i] = false
*state = (*state)[:len(*state)-1]
}
}
}

/* 全排列 II */
func permutationsII(nums []int) [][]int {
res := make([][]int, 0)
state := make([]int, 0)
selected := make([]bool, len(nums))
backtrackII(&state, &nums, &selected, &res)
return res
}
22 changes: 22 additions & 0 deletions codes/go/chapter_backtracking/preorder_traversal_i_compact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// File: preorder_traversal_i_compact.go
// Created Time: 2023-05-09
// Author: Reanon ([email protected])

package chapter_backtracking

import (
. "github.com/krahets/hello-algo/pkg"
)

/* 前序遍历:例题一 */
func preOrderI(root *TreeNode, res *[]*TreeNode) {
if root == nil {
return
}
if int(root.Val) == 7 {
// 记录解
*res = append(*res, root)
}
preOrderI(root.Left, res)
preOrderI(root.Right, res)
}
26 changes: 26 additions & 0 deletions codes/go/chapter_backtracking/preorder_traversal_ii_compact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// File: preorder_traversal_i_compact.go
// Created Time: 2023-05-09
// Author: Reanon ([email protected])

package chapter_backtracking

import (
. "github.com/krahets/hello-algo/pkg"
)

/* 前序遍历:例题二 */
func preOrderII(root *TreeNode, res *[][]*TreeNode, path *[]*TreeNode) {
if root == nil {
return
}
// 尝试
*path = append(*path, root)
if int(root.Val) == 7 {
// 记录解
*res = append(*res, *path)
}
preOrderII(root.Left, res, path)
preOrderII(root.Right, res, path)
// 回退
*path = (*path)[:len(*path)-1]
}
27 changes: 27 additions & 0 deletions codes/go/chapter_backtracking/preorder_traversal_iii_compact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// File: preorder_traversal_i_compact.go
// Created Time: 2023-05-09
// Author: Reanon ([email protected])

package chapter_backtracking

import (
. "github.com/krahets/hello-algo/pkg"
)

/* 前序遍历:例题三 */
func preOrderIII(root *TreeNode, res *[][]*TreeNode, path *[]*TreeNode) {
// 剪枝
if root == nil || root.Val == 3 {
return
}
// 尝试
*path = append(*path, root)
if int(root.Val) == 7 {
// 记录解
*res = append(*res, *path)
}
preOrderIII(root.Left, res, path)
preOrderIII(root.Right, res, path)
// 回退
*path = (*path)[:len(*path)-1]
}
58 changes: 58 additions & 0 deletions codes/go/chapter_backtracking/preorder_traversal_iii_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// File: preorder_traversal_i_compact.go
// Created Time: 2023-05-09
// Author: Reanon ([email protected])

package chapter_backtracking

import (
. "github.com/krahets/hello-algo/pkg"
)

/* 判断当前状态是否为解 */
func isSolution(state *[]*TreeNode) bool {
return len(*state) != 0 && (*state)[len(*state)-1].Val == 7
}

/* 记录解 */
func recordSolution(state *[]*TreeNode, res *[][]*TreeNode) {
*res = append(*res, *state)
}

/* 判断在当前状态下,该选择是否合法 */
func isValid(state *[]*TreeNode, choice *TreeNode) bool {
return choice != nil && choice.Val != 3
}

/* 更新状态 */
func makeChoice(state *[]*TreeNode, choice *TreeNode) {
*state = append(*state, choice)
}

/* 恢复状态 */
func undoChoice(state *[]*TreeNode, choice *TreeNode) {
*state = (*state)[:len(*state)-1]
}

/* 回溯算法:例题三 */
func backtrackIII(state *[]*TreeNode, choices *[]*TreeNode, res *[][]*TreeNode) {
// 检查是否为解
if isSolution(state) {
// 记录解
recordSolution(state, res)
return
}
// 遍历所有选择
for _, choice := range *choices {
// 剪枝:检查选择是否合法
if isValid(state, choice) {
// 尝试:做出选择,更新状态
makeChoice(state, choice)
// 进行下一轮选择
temp := make([]*TreeNode, 0)
temp = append(temp, choice.Left, choice.Right)
backtrackIII(state, &temp, res)
// 回退:撤销选择,恢复到之前的状态
undoChoice(state, choice)
}
}
}
Loading

0 comments on commit a6b3f72

Please sign in to comment.