代码随想录 day28 第七章 回溯算法part04

今日安排

●  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. 题外话

  • 组合是收集所有叶子节点
    • 从根节点到叶子节点的一条路径
  • 子集问题是收集树的所有节点
    • 每个节点到根节点的路径上的所有节点

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值