打卡round1/day7/回溯算法:总结

1. 关于回溯

1.1 总体思路

  1. 为什么使用回溯?
    • 组合问题:提取哪些节点组成的path?
    • 分割问题:在字符串的哪个位置下刀?
    • 子集问题:
  2. 需要递归几层?
    • 返回条件是什么
  3. 每层递归要尝试哪些节点?
    • 注意不要漏掉回退
public void backtrack(//参数){
//终止条件,确定需要递归几层,即树的深度
if(condition){
result.add(...);
return;
}

//单层递归逻辑,记录本层集合的元素,即存储本层树中所有的节点,即树的宽度
for(//从哪里开始遍历?从0遍历到尾,还是从上次历史记录<startIndex>开始遍历剩余的数组?){
	处理节点,如path.add();
	调用递归,进入下一层;
	回退,撤销处理结果;
}

1.2 分治解法

问题

  • 给定的数组是单一集合/多个集合? (如果是单一集合,则每层递归都要考虑递归的起始位置问题!)
  • 在元素不重复/重复的情况下?
  • 满足的条件是?(如组合总和=?/组合中包含n个数字…)
  • 并返回所有的集合可能性,并确保集合不重复出现

解答

  1. 初始条件:给出一个数组nums

  2. 返回要求:
    每层遍历返回一条path,经过n层遍历后,return path的集合result
    2.1 情况1:以每个节点串联出一条path,如组合、分割类问题
    例题:很多
    2.2 情况2:每个节点内的组合就是一条path,如子集问题
    例题:子集78,90
    2.3 情况3: 返回的不是套娃数组,而是二维数组(或转换后的字符串),如棋盘问题。需要引入board[row][col]二维数组,在此基础上思考
    例题:51,37

  3. 终止条件:
    3.1 情况1:以满足特定(condition)作为终止,如求和if(sum==target) return;
    3.2 情况2:以遍历到最后一行/遍历满k个元素作为终止,如返回所有k个数的组合if(path.size() == k) return;,或遍历到最后一行if(row == n) /if(start > nums.length-1)

  4. 单层递归:
    4.1. 问:什么时候允许进入下一层遍历?

    • 4.1.1 无脑进入
    • 4.1.2 情况比较复杂,需要单独写一个判定方法,如排列结果是否符合ip地址规则、是否是回文字符串、是否符合数独/N皇后排列条件等 (如51,37,93,131)

    4.2 问:每层遍历中,需要递归的是除了nums[i]的部分,还是nums[i]之后的剩余部分?还是从0递归到尾?

    • 4.2.1 情况1:nums[i]之后的剩余部分,i= startIndex; i<nums.length
    • 4.2.2 情况2:除了nums[i]的部分,需要借助boolean[] used这个数组作为开关,标记nums中不同的index(及其对应的元素)是否用过,用过则打开开关:true
    • 4.2.3 情况3:从0到尾。如数据来自多个集合如电话号码数字对应字母 int i=0; i<str.length() (如lc17)
  5. 调用执行单层递归
    4.1 情况1:无重复元素。正常操作即可,处理元素-调用递归-回退(*注意:如果有sum等计算,回退时不要忘记
    4.2 情况2:需要去重。将数组有序化之后 Arrays.sort(nums),在每层从左到右遍历时比较前后元素是否相重 if(i>1 && arr[i]==arr[i-1]) contiunue; else…
    例题:组合(40)

  6. 关于回退
    注意:如果需要在递归中执行操作,如sum、增加字符、改变used[i]=true等,记得回退时一并删除

2. 关于字符串

字符串string

  • 字符串长度:str.length();
  • 提取字符串某索引位的值:str.charAt(i);
  • 提取字符串切片: str.substring(left,right) --注意:切片范围左闭右开,不包括right
  • 将字符转为数字:‘integer’ - ‘0’;Integer.parseInt(str);
  • 判断字符串引用是否相等: strA.equals(strB)
  • 字符串排序:String.sort(str);
  • 用stringbuilder拼接字符串:
    • 新增:sb.append()
    • 删除:sb.deleteCharAt(index)
    • 获取长度:sb.length()
    • 翻转字符串:string reverseStr = new StringBuilder(str).reverse().toString

记录path:ArrayList vs LinkedList

  • 回退
    • arraylist删除最后一位:path.remove(path.size()-1);
    • 链表删除最后一位:path.removeLast();
  • 将链表转为List< Integer >:result.add(new ArrayList<>(path));

将字符数组char[ ][ ]转为字符串string

遍历char[],String.copyValueOf(每一行字符数组)

//两个目的:1.把第n行二维数组合并成一个字符串 2.把n行字符串录入一个list
public List<String> boardToPath(char[][] board){
    List<String> path = new ArrayList<>();
    for(char[] c : board){
        path.add(String.copyValueOf(c)); //String.copyValueOf: 把字符串数组转为字符串
    }
    return path;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值