diff --git a/codes/kotlin/chapter_backtracking/n_queens/n_queens.kt b/codes/kotlin/chapter_backtracking/n_queens/n_queens.kt new file mode 100644 index 000000000..6baa12dfa --- /dev/null +++ b/codes/kotlin/chapter_backtracking/n_queens/n_queens.kt @@ -0,0 +1,85 @@ +/** + * File: n_queens.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.n_queens + +/* 回溯算法:n 皇后 */ +fun backtrack( + row: Int, + n: Int, + state: List>, + res: MutableList>?>, + cols: BooleanArray, + diags1: BooleanArray, + diags2: BooleanArray +) { + // 当放置完所有行时,记录解 + if (row == n) { + val copyState: MutableList> = ArrayList() + for (sRow in state) { + copyState.add(ArrayList(sRow)) + } + res.add(copyState) + return + } + // 遍历所有列 + for (col in 0..>?> { + // 初始化 n*n 大小的棋盘,其中 'Q' 代表皇后,'#' 代表空位 + val state: MutableList> = ArrayList() + for (i in 0.. = ArrayList() + for (j in 0..>?> = ArrayList() + + backtrack(0, n, state, res, cols, diags1, diags2) + + return res +} + +/* Driver Code */ +fun main() { + val n = 4 + val res: List?>?> = nQueens(n) + + println("输入棋盘长宽为 $n") + println("皇后放置方案共有 ${res.size} 种") + for (state in res) { + println("--------------------") + for (row in state!!) { + println(row) + } + } +} \ No newline at end of file diff --git a/codes/kotlin/chapter_backtracking/permutations_i/permutations_i.kt b/codes/kotlin/chapter_backtracking/permutations_i/permutations_i.kt new file mode 100644 index 000000000..28c677603 --- /dev/null +++ b/codes/kotlin/chapter_backtracking/permutations_i/permutations_i.kt @@ -0,0 +1,53 @@ +/** + * File: permutations_i.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.permutations_i + +/* 回溯算法:全排列 I */ +fun backtrack( + state: MutableList, + choices: IntArray, + selected: BooleanArray, + res: MutableList?> +) { + // 当状态长度等于元素数量时,记录解 + if (state.size == choices.size) { + res.add(ArrayList(state)) + return + } + // 遍历所有选择 + for (i in choices.indices) { + val choice = choices[i] + // 剪枝:不允许重复选择元素 + if (!selected[i]) { + // 尝试:做出选择,更新状态 + selected[i] = true + state.add(choice) + // 进行下一轮选择 + backtrack(state, choices, selected, res) + // 回退:撤销选择,恢复到之前的状态 + selected[i] = false + state.removeAt(state.size - 1) + } + } +} + +/* 全排列 I */ +fun permutationsI(nums: IntArray): List?> { + val res: MutableList?> = ArrayList() + backtrack(ArrayList(), nums, BooleanArray(nums.size), res) + return res +} + +/* Driver Code */ +fun main() { + val nums = intArrayOf(1, 2, 3) + + val res = permutationsI(nums) + + println("输入数组 nums = ${nums.contentToString()}") + println("所有排列 res = $res") +} \ No newline at end of file diff --git a/codes/kotlin/chapter_backtracking/permutations_ii/permutations_ii.kt b/codes/kotlin/chapter_backtracking/permutations_ii/permutations_ii.kt new file mode 100644 index 000000000..80be03f47 --- /dev/null +++ b/codes/kotlin/chapter_backtracking/permutations_ii/permutations_ii.kt @@ -0,0 +1,55 @@ +/** + * File: permutations_ii.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.permutations_ii + +/* 回溯算法:全排列 II */ +fun backtrack( + state: MutableList, + choices: IntArray, + selected: BooleanArray, + res: MutableList?> +) { + // 当状态长度等于元素数量时,记录解 + if (state.size == choices.size) { + res.add(ArrayList(state)) + return + } + // 遍历所有选择 + val duplicated: MutableSet = HashSet() + for (i in choices.indices) { + val choice = choices[i] + // 剪枝:不允许重复选择元素 且 不允许重复选择相等元素 + if (!selected[i] && !duplicated.contains(choice)) { + // 尝试:做出选择,更新状态 + duplicated.add(choice) // 记录选择过的元素值 + selected[i] = true + state.add(choice) + // 进行下一轮选择 + backtrack(state, choices, selected, res) + // 回退:撤销选择,恢复到之前的状态 + selected[i] = false + state.removeAt(state.size - 1) + } + } +} + +/* 全排列 II */ +fun permutationsII(nums: IntArray): MutableList?> { + val res: MutableList?> = ArrayList() + backtrack(ArrayList(), nums, BooleanArray(nums.size), res) + return res +} + +/* Driver Code */ +fun main() { + val nums = intArrayOf(1, 2, 2) + + val res = permutationsII(nums) + + println("输入数组 nums = ${nums.contentToString()}") + println("所有排列 res = $res") +} \ No newline at end of file diff --git a/codes/kotlin/chapter_backtracking/preorder_traversal_i_compact/preorder_traversal_i_compact.kt b/codes/kotlin/chapter_backtracking/preorder_traversal_i_compact/preorder_traversal_i_compact.kt new file mode 100644 index 000000000..a4b8530b3 --- /dev/null +++ b/codes/kotlin/chapter_backtracking/preorder_traversal_i_compact/preorder_traversal_i_compact.kt @@ -0,0 +1,43 @@ +/** + * File: preorder_traversal_i_compact.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.preorder_traversal_i_compact + +import utils.TreeNode +import utils.printTree + +var res: MutableList? = null + +/* 前序遍历:例题一 */ +fun preOrder(root: TreeNode?) { + if (root == null) { + return + } + if (root.value == 7) { + // 记录解 + res!!.add(root) + } + preOrder(root.left) + preOrder(root.right) +} + +/* Driver Code */ +fun main() { + val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7)) + println("\n初始化二叉树") + printTree(root) + + // 前序遍历 + res = ArrayList() + preOrder(root) + + println("\n输出所有值为 7 的节点") + val vals: MutableList = ArrayList() + for (node in res as ArrayList) { + vals.add(node.value) + } + println(vals) +} \ No newline at end of file diff --git a/codes/kotlin/chapter_backtracking/preorder_traversal_ii_compact/preorder_traversal_ii_compact.kt b/codes/kotlin/chapter_backtracking/preorder_traversal_ii_compact/preorder_traversal_ii_compact.kt new file mode 100644 index 000000000..cc5e02a19 --- /dev/null +++ b/codes/kotlin/chapter_backtracking/preorder_traversal_ii_compact/preorder_traversal_ii_compact.kt @@ -0,0 +1,51 @@ +/** + * File: preorder_traversal_ii_compact.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.preorder_traversal_ii_compact + +import utils.TreeNode +import utils.printTree + +var path: MutableList? = null +var res: MutableList>? = null + +/* 前序遍历:例题二 */ +fun preOrder(root: TreeNode?) { + if (root == null) { + return + } + // 尝试 + path!!.add(root) + if (root.value == 7) { + // 记录解 + res!!.add(ArrayList(path!!)) + } + preOrder(root.left) + preOrder(root.right) + // 回退 + path!!.removeAt(path!!.size - 1) +} + +/* Driver Code */ +fun main() { + val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7)) + println("\n初始化二叉树") + printTree(root) + + // 前序遍历 + path = java.util.ArrayList() + res = java.util.ArrayList>() + preOrder(root) + + println("\n输出所有根节点到节点 7 的路径") + for (path in res as ArrayList>) { + val values: MutableList = ArrayList() + for (node in path) { + values.add(node.value) + } + println(values) + } +} \ No newline at end of file diff --git a/codes/kotlin/chapter_backtracking/preorder_traversal_iii_compact/preorder_traversal_iii_compact.kt b/codes/kotlin/chapter_backtracking/preorder_traversal_iii_compact/preorder_traversal_iii_compact.kt new file mode 100644 index 000000000..dbb257e50 --- /dev/null +++ b/codes/kotlin/chapter_backtracking/preorder_traversal_iii_compact/preorder_traversal_iii_compact.kt @@ -0,0 +1,52 @@ +/** + * File: preorder_traversal_iii_compact.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.preorder_traversal_iii_compact + +import utils.TreeNode +import utils.printTree + +var path: MutableList? = null +var res: MutableList>? = null + +/* 前序遍历:例题三 */ +fun preOrder(root: TreeNode?) { + // 剪枝 + if (root == null || root.value == 3) { + return + } + // 尝试 + path!!.add(root) + if (root.value == 7) { + // 记录解 + res!!.add(ArrayList(path!!)) + } + preOrder(root.left) + preOrder(root.right) + // 回退 + path!!.removeAt(path!!.size - 1) +} + +/* Driver Code */ +fun main() { + val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7)) + println("\n初始化二叉树") + printTree(root) + + // 前序遍历 + path = ArrayList() + res = ArrayList() + preOrder(root) + + println("\n输出所有根节点到节点 7 的路径,路径中不包含值为 3 的节点") + for (path in res as ArrayList>) { + val values: MutableList = ArrayList() + for (node in path) { + values.add(node.value) + } + println(values) + } +} \ No newline at end of file diff --git a/codes/kotlin/chapter_backtracking/preorder_traversal_iii_template/preorder_traversal_iii_template.kt b/codes/kotlin/chapter_backtracking/preorder_traversal_iii_template/preorder_traversal_iii_template.kt new file mode 100644 index 000000000..128641954 --- /dev/null +++ b/codes/kotlin/chapter_backtracking/preorder_traversal_iii_template/preorder_traversal_iii_template.kt @@ -0,0 +1,83 @@ +/** + * File: preorder_traversal_iii_template.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.preorder_traversal_iii_template + +import utils.TreeNode +import utils.printTree +import java.util.* + +/* 判断当前状态是否为解 */ +fun isSolution(state: List): Boolean { + return state.isNotEmpty() && state[state.size - 1]?.value == 7 +} + +/* 记录解 */ +fun recordSolution(state: MutableList?, res: MutableList?>) { + res.add(state?.let { ArrayList(it) }) +} + +/* 判断在当前状态下,该选择是否合法 */ +fun isValid(state: List?, choice: TreeNode?): Boolean { + return choice != null && choice.value != 3 +} + +/* 更新状态 */ +fun makeChoice(state: MutableList, choice: TreeNode?) { + state.add(choice) +} + +/* 恢复状态 */ +fun undoChoice(state: MutableList, choice: TreeNode?) { + state.removeLast() +} + +/* 回溯算法:例题三 */ +fun backtrack( + state: MutableList, + choices: List, + res: MutableList?> +) { + // 检查是否为解 + if (isSolution(state)) { + // 记录解 + recordSolution(state, res) + } + // 遍历所有选择 + for (choice in choices) { + // 剪枝:检查选择是否合法 + if (isValid(state, choice)) { + // 尝试:做出选择,更新状态 + makeChoice(state, choice) + // 进行下一轮选择 + backtrack(state, listOf(choice!!.left, choice.right), res) + // 回退:撤销选择,恢复到之前的状态 + undoChoice(state, choice) + } + } +} + +/* Driver Code */ +fun main() { + val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7)) + println("\n初始化二叉树") + printTree(root) + + // 回溯算法 + val res: MutableList?> = ArrayList() + backtrack(ArrayList(), mutableListOf(root), res) + + println("\n输出所有根节点到节点 7 的路径,要求路径中不包含值为 3 的节点") + for (path in res) { + val vals = ArrayList() + for (node in path!!) { + if (node != null) { + vals.add(node.value) + } + } + println(vals) + } +} \ No newline at end of file diff --git a/codes/kotlin/chapter_backtracking/subset_sum_i/subset_sum_i.kt b/codes/kotlin/chapter_backtracking/subset_sum_i/subset_sum_i.kt new file mode 100644 index 000000000..0689b3a44 --- /dev/null +++ b/codes/kotlin/chapter_backtracking/subset_sum_i/subset_sum_i.kt @@ -0,0 +1,60 @@ +/** + * File: subset_sum_i.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.subset_sum_i + +import java.util.* + +/* 回溯算法:子集和 I */ +fun backtrack( + state: MutableList, + target: Int, + choices: IntArray, + start: Int, + res: MutableList?> +) { + // 子集和等于 target 时,记录解 + if (target == 0) { + res.add(ArrayList(state)) + return + } + // 遍历所有选择 + // 剪枝二:从 start 开始遍历,避免生成重复子集 + for (i in start..?> { + val state: MutableList = ArrayList() // 状态(子集) + Arrays.sort(nums) // 对 nums 进行排序 + val start = 0 // 遍历起始点 + val res: MutableList?> = ArrayList() // 结果列表(子集列表) + backtrack(state, target, nums, start, res) + return res +} + +/* Driver Code */ +fun main() { + val nums = intArrayOf(3, 4, 5) + val target = 9 + + val res = subsetSumI(nums, target) + + println("输入数组 nums = ${nums.contentToString()}, target = $target") + println("所有和等于 $target 的子集 res = $res") +} \ No newline at end of file diff --git a/codes/kotlin/chapter_backtracking/subset_sum_i_naive/subset_sum_i_naive.kt b/codes/kotlin/chapter_backtracking/subset_sum_i_naive/subset_sum_i_naive.kt new file mode 100644 index 000000000..923625738 --- /dev/null +++ b/codes/kotlin/chapter_backtracking/subset_sum_i_naive/subset_sum_i_naive.kt @@ -0,0 +1,56 @@ +/** + * File: subset_sum_i_native.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.subset_sum_i_naive + +/* 回溯算法:子集和 I */ +fun backtrack( + state: MutableList, + target: Int, + total: Int, + choices: IntArray, + res: MutableList?> +) { + // 子集和等于 target 时,记录解 + if (total == target) { + res.add(ArrayList(state)) + return + } + // 遍历所有选择 + for (i in choices.indices) { + // 剪枝:若子集和超过 target ,则跳过该选择 + if (total + choices[i] > target) { + continue + } + // 尝试:做出选择,更新元素和 total + state.add(choices[i]) + // 进行下一轮选择 + backtrack(state, target, total + choices[i], choices, res) + // 回退:撤销选择,恢复到之前的状态 + state.removeAt(state.size - 1) + } +} + +/* 求解子集和 I(包含重复子集) */ +fun subsetSumINaive(nums: IntArray, target: Int): List?> { + val state: MutableList = ArrayList() // 状态(子集) + val total = 0 // 子集和 + val res: MutableList?> = ArrayList() // 结果列表(子集列表) + backtrack(state, target, total, nums, res) + return res +} + +/* Driver Code */ +fun main() { + val nums = intArrayOf(3, 4, 5) + val target = 9 + + val res: List?> = subsetSumINaive(nums, target) + + println("输入数组 nums = ${nums.contentToString()}, target = $target") + println("所有和等于 $target 的子集 res = $res") + println("请注意,该方法输出的结果包含重复集合") +} \ No newline at end of file diff --git a/codes/kotlin/chapter_backtracking/subset_sum_ii/subset_sum_ii.kt b/codes/kotlin/chapter_backtracking/subset_sum_ii/subset_sum_ii.kt new file mode 100644 index 000000000..3902ebef8 --- /dev/null +++ b/codes/kotlin/chapter_backtracking/subset_sum_ii/subset_sum_ii.kt @@ -0,0 +1,65 @@ +/** + * File: subset_sum_ii.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_backtracking.subset_sum_ii + +import java.util.* + +/* 回溯算法:子集和 II */ +fun backtrack( + state: MutableList, + target: Int, + choices: IntArray, + start: Int, + res: MutableList?> +) { + // 子集和等于 target 时,记录解 + if (target == 0) { + res.add(ArrayList(state)) + return + } + // 遍历所有选择 + // 剪枝二:从 start 开始遍历,避免生成重复子集 + // 剪枝三:从 start 开始遍历,避免重复选择同一元素 + for (i in start.. start && choices[i] == choices[i - 1]) { + continue + } + // 尝试:做出选择,更新 target, start + state.add(choices[i]) + // 进行下一轮选择 + backtrack(state, target - choices[i], choices, i + 1, res) + // 回退:撤销选择,恢复到之前的状态 + state.removeAt(state.size - 1) + } +} + +/* 求解子集和 II */ +fun subsetSumII(nums: IntArray, target: Int): List?> { + val state: MutableList = ArrayList() // 状态(子集) + Arrays.sort(nums) // 对 nums 进行排序 + val start = 0 // 遍历起始点 + val res: MutableList?> = ArrayList() // 结果列表(子集列表) + backtrack(state, target, nums, start, res) + return res +} + +/* Driver Code */ +fun main() { + val nums = intArrayOf(4, 4, 5) + val target = 9 + + val res = subsetSumII(nums, target) + + println("输入数组 nums = ${nums.contentToString()}, target = $target") + println("所有和等于 $target 的子集 res = $res") +} \ No newline at end of file