今日安排
● 93.复原IP地址
● 78.子集
● 90.子集II
1. 复原IP地址
关联 leetcode 93.复原IP地址
-
切割问题
- 使用回溯搜索可以把所有可能性搜索出来
- 切割问题可以抽象为树形结构
- N叉树
-
不能重复切割
- startIndex 每次切割需要累加一
-
终止条件
- 明确要求:切成 四组 地址
- 三个逗号
- 明确要求:切成 四组 地址
-
题解
func restoreIpAddresses(s string) []string { ret := make([]string, 0) path := make([]string, 0) //记录临时切割的子串集合 var backtracking func(src string, startIdx int) backtracking = func(src string, startIdx int) { // 终止退出 if len(path) == 4 { //切成四段了 // 校验第四段是否复合ip要求, 如果合法就加入结果集中 if startIdx == len(s) { str := strings.Join(path, ".") ret = append(ret, str) } return } // 单层循环 for i := startIdx; i < len(s); i++ { // 截取的字串: s[startIdx:i+1] subStr := s[startIdx : i+1] if isValid(subStr) { path = append(path, subStr) backtracking(s, i+1) path = path[:len(path)-1] } else {//当前字串不合规, 再从当前位置往后切也就没意义了: 02 已经不合法了, 再切:023 也没意义了 break } } } backtracking(s, 0) return ret } func isValid(str string) bool { if len(str) > 3 || len(str) < 1 { return false } if len(str) > 1 { if strings.HasPrefix(str, "0") { return false } } num, err := strconv.Atoi(str) if err != nil { return false } if num < 0 || num > 255 { return false } return true }
2. 子集
关联 leetcode 78.子集
-
思路
- 子集问题,就是收集树形结构中,每一个节点的结果
- 终止条件:
- 搜索到叶子节点
- 注意空集的处理
- 单层循环时的逻辑处理,【特例:叶子结点的处理】
-
题解
func subsets(nums []int) [][]int { rets, ret := make([][]int, 0), make([]int, 0) var backtracking func(nums []int, startIdx int) backtracking = func(nums []int, startIdx int) { // 每次回溯, 收集当前结果集 tmp := make([]int, len(ret)) copy(tmp,ret) rets = append(rets, tmp) // 终止条件, 走到叶子节点 if startIdx == len(nums) { return } // 单层循环 for i := startIdx; i < len(nums); i++ { ret = append(ret, nums[i])//追加当前元素 backtracking(nums,i+1) ret=ret[:len(ret)-1] } } backtracking(nums, 0) return rets }
3. 子集II
关联 leetcode 90.子集II
-
思路
- 子集+去重
-
题解
func subsetsWithDup(nums []int) [][]int { rets, ret := make([][]int, 0), make([]int, 0) sort.Ints(nums) //先对数组排序, 便于后面去重 var backtracking func(nums []int, startIdx int) backtracking = func(nums []int, startIdx int) { // append subset tmp := make([]int, len(ret)) copy(tmp, ret) rets = append(rets, tmp) if startIdx == len(nums) { return } for i := startIdx; i < len(nums); i++ { // 使用 startIdx 来去重, 同一层的元素 startIdx 相同, 只用判断不是该层出现的第一个该值的元素即可 if i != startIdx && nums[i] == nums[i-1] { continue } ret = append(ret, nums[i]) backtracking(nums, i+1) ret = ret[:len(ret)-1] } } backtracking(nums, 0) return rets }
9. 题外话
- 组合是收集所有叶子节点
- 从根节点到叶子节点的一条路径
- 子集问题是收集树的所有节点
- 每个节点到根节点的路径上的所有节点