回溯理论基础及leetcode例题

这篇具有很好参考价值的文章主要介绍了回溯理论基础及leetcode例题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

学习参考

回溯

与递归相辅相成;回溯是递归的副产品,只要有递归就会有回溯。
回溯函数也就是递归函数,指的都是一个函数。

回溯搜索法

纯暴力搜索
解决的问题

组合问题:N个数里面按一定规则找出k个数的集合
切割问题:一个字符串按一定规则有几种切割方式
子集问题:一个N个数的集合里有多少符合条件的子集
排列问题:N个数按一定规则全排列,有几种排列方式(与组合差别,排列有元素顺序)
棋盘问题:N皇后,解数独等等

理解

抽象的不易理解;抽象为图形结构--树形结构
N叉树【树的宽度:集合的大小(for处理);深度:递归的深度(递归处理)】

模板

void backtracking(参数){
  if(终止条件){
    收集结果;
    return;
  }

  //单层搜索
   for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小)){//集合元素集
      处理节点;
      backtracking(路径,选择列表);//递归函数;
      回溯操作; //(12,把2回溯,变13;没有回溯操作就会递归为123)
    }
  return;
}

递归里面嵌套for循环,for循环里又有递归

leetcode题目

组合

77.组合

for循环嵌套太多层了

树形结构
回溯理论基础及leetcode例题
不能取前面的的:因为组合是无序的,会重复;
每个节点都是一个for循环

回溯三部曲

递归函数参数返回值
确定终止条件
单层递归逻辑

伪代码

全局变量:二维数组res【返回值】
         一维数组path【单个结果】
//确定返回值参数
void backtracking(n,k,start){//n集合大小;k需要的子集合大小;start每个取值的开始;
  //确定终止条件
  if(path.size == k){
    res.add(path);
    return;
  }
  //单层递归逻辑
  //对于1,234节点
  for(i=start,i<=n;i++){
    path.push(i);//1
    backtracking(n,k,i+1);//遍历剩下的集合234;
    path.pop();//回溯过程
  } 
}

实现
java版本

class Solution {
    List<List<Integer>> res = new ArrayList<List<Integer>>();
    List<Integer> path = new ArrayList<Integer>();

    public List<List<Integer>> combine(int n, int k) {
        backtracking(n,k,1);
        return res;
    }

    public void backtracking(int n,int k,int start){
        if(path.size() == k){
            res.add(new ArrayList<>(path));//容易犯错误
            return;
        }

        for(int i=start;i<=n;i++){//i<=n -(k-path.size()) + 1 会减少运行时间【剪枝操作】
            path.add(i);
            backtracking(n,k,i+1);
            path.remove(path.size()-1);
        }
        
    }
}

问题:参考
在链表path里面添加值,然后把path链表添加进res链表中,在做算法题的时候,平时使用res.add(path),结果发现输出打印为空:

在链表path里面添加值,然后把path链表添加进res链表中,在做算法题的时候,平时使用res.add(path),结果发现输出打印为空: res.add(new ArrayList<>(path))和res.add(path)的区别
共同点: 都是向res这个ArrayList中填加了一个名为path的链表
不同点: res.add(new ArrayList(path)):开辟一个独立地址,地址中存放的内容为path链表,后续path的变化不会影响到res
res.add(path):将res尾部指向了path地址,后续path内容的变化会导致res的变化。

优化:剪枝
可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。

如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了。

回溯理论基础及leetcode例题
优化过程如下:

已经选择的元素个数:path.size();
所需需要的元素个数为: k - path.size();
列表中剩余元素(n-i) >= 所需需要的元素个数(k - path.size())
在集合n中至多要从该起始位置 : i <= n - (k - path.size()) + 1,开始遍历

分割

131. 分割回文串

树形结构
回溯理论基础及leetcode例题

回溯三部曲

递归函数参数返回值
确定终止条件
单层递归逻辑

伪代码
收集结果路径

void backtracking(string s,startIndex){
    //终止条件
    //即切割线是终止条件
    if(startIndex >= s.length()){
        res.add(path);
        return;
    }

    //单层递归逻辑
    //切割字串范围:(startIndex,i]
    for(i=startIndex;i< s.length();i++){
      if(isPalindrome(s,startIndex,i)){
          path.add(子串);
      }else continue;
      
      backtracking(s,i+1);
      path.remove(path.size()-1);
    }
}

实现

java版本

class Solution {
    List<List<String>> result = new ArrayList<List<String>>();
    List<String> path = new ArrayList<String>();

    public List<List<String>> partition(String s) {
        backtracking(s,0);
        return result;
    }

    public void backtracking(String s,int startIndex){
        if(startIndex >= s.length()){
            result.add(new ArrayList<String>(path));
            return;
        }

        for(int i=startIndex;i<s.length();i++){
            String sub = s.substring(startIndex,i+1);
            if(isPalindrome(sub)){
                path.add(sub);
            }else {continue;}

            backtracking(s,i+1);
            path.remove(path.size()-1);
        }
    }

    public boolean isPalindrome(String s){
        int left = 0;
        int right = s.length()-1;

        while(left<right){
            if(s.charAt(left) != s.charAt(right)){
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

子集问题

78. 子集

树形结构
回溯理论基础及leetcode例题
收获结果的时候:在每个节点收获结果
组合和分割问题都是在叶子节点里取结果;
伪代码

void backtracking(nums,stratIndex){
  result.add(path);

  if(stratIndex >= path.size()) return;

  for(int i=startIndex;i<nums.length;i++){
    path.add(nums[i]);
    backtracking(nums,i+1);
    path.remove(path.size()-1);
  }
}

实现

class Solution {
    List<List<Integer>> list = new ArrayList<List<Integer>>();
    List<Integer> path= new ArrayList<Integer>();
    public List<List<Integer>> subsets(int[] nums) {
        backtracking(nums,0);
        return list;
    }

    public void backtracking(int[] nums,int stratIndex){
        list.add(new ArrayList<Integer>(path));
        if(stratIndex>=nums.length){
            return;
        }

        for(int i=stratIndex;i<nums.length;i++){
            path.add(nums[i]);
            backtracking(nums,i+1);
            path.remove(path.size()-1);
        }
    }
} 

排列

46.全排列

树形结构
回溯理论基础及leetcode例题

伪代码:文章来源地址https://www.toymoban.com/news/detail-412147.html

void backtracking(nums,used){
  if(path.size() == nums.length){
    res.add(path);
    return;
  }

  for(i=0;i<nums.length;i++){
    if(used[i] == true) continue;
    used[i] = true;
    path.add(nums[i]);
    backtracking(nums,used);
    used[i] = false;
    path.remove(path.size()-1);
  }
}

实现

class Solution {
    List<List<Integer>> list = new ArrayList<List<Integer>>();
    List<Integer> path = new ArrayList<Integer>();

    public List<List<Integer>> permute(int[] nums) {
        boolean[] used = new boolean[nums.length];
        backtracking(nums,used);
        return list;
    }

    public void backtracking(int[] nums,boolean[] used){
        if(path.size() >= nums.length){
            list.add(new ArrayList<>(path));
            return;
        }

        for(int i=0;i<nums.length;i++){
            if(used[i] == true) continue;
            
            path.add(nums[i]);
            used[i] = true;
            backtracking(nums,used);
            path.remove(path.size()-1);
            used[i] = false;
        }
    }
}

到了这里,关于回溯理论基础及leetcode例题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 回溯递归(例题+思路+代码)

    leetcode 77 组合问题适合用回溯求解。 经典解法:for循环 + 内部回溯。 每次进入回溯方法时,先判断终止条件,再进行当前层的循环,循环进行下一层递归。 由于递归本质其实就是暴力解法,所以会经过许多没有必要的节点。 该题中,如果n=4,k=3,那么在第二层中的3和4都是

    2023年04月19日
    浏览(86)
  • 回溯算法例题(剪枝策略)

    链接: 77. 组合 链接: 216. 组合总和 III 链接: 17. 电话号码的字母组合 链接: 39. 组合总和 注:使用剪枝必须对原数组进行排序 链接: 40. 组合总和 II 链接: 131. 分割回文串 链接: 93. 复原 IP 地址 链接: 78. 子集 链接: 90. 子集 II 链接: 46. 全排列 链接: 47. 全排列 II 链接: 51. N 皇后 链接

    2024年02月04日
    浏览(90)
  • 递归回溯两个例题:1.数组组合 2.在矩阵中搜索单词

    题目1:组合 给定两个整数 n 和 k ,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 输入:n = 4, k = 2 输出: [   [2,4],   [3,4],   [2,3],   [1,2],   [1,3],   [1,4], ]  解题思路: 1.定义一个temp数组,存放临时的组合结果 2.两种选择:1.选择当前元素2.不选

    2024年02月15日
    浏览(43)
  • 代码随想录第三天|链表理论基础,LeetCode203.移除链表元素, LeetCode707.设计链表,LeetCode 206.反转链表

    链表: 链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。 链表的入口节点称为链表的头结点也就是head。 链表类型: 1.单链表 单链表中的指

    2024年02月11日
    浏览(53)
  • 整数规划、对偶理论、线性规划经典例题讲解

    整数规划是一类要求问题的解中的全部或一部分变量为整数的数学规划,应用范围极其广泛。不仅在工业和工程设计和科学研究方面有许多应用,而且在计算机设计、系统可靠性和经济分析等方面也有新的应用。 通过前面的学习,我们已经掌握了整数规划的数学模型、割平面

    2024年02月05日
    浏览(56)
  • 算法训练day31贪心算法理论基础Leetcode455分发饼干376摆动序列53最大子序和

    文章链接 代码随想录 (programmercarl.com) 说实话贪心算法并没有固定的套路 。 最好用的策略就是举反例,如果想不到反例,那么就试一试贪心吧 。 面试中基本不会让面试者现场证明贪心的合理性,代码写出来跑过测试用例即可,或者自己能自圆其说理由就行了 。 刷题或者面

    2024年02月20日
    浏览(46)
  • 区间合并(超详细逐步讲解/例题/思路分析/参考代码)

    我们要了解区间合并是什么,首先来看这样的一个例子。 区间2是区间1的一个子区间 区间3和区间1有交集 区间4和区间1端点在同一个点上 区间5和区间1没有交集 所以区间2,3,4都可以和区间1合并形成一个新的区间,区间5则不行。 总结:区间合并就是把多个区间有交集的部分

    2024年02月14日
    浏览(40)
  • 代码随想录第6天| 哈希表理论基础 ,LeetCode242.有效的字母异位词,LeetCode349. 两个数组的交集,LeetCode202. 快乐数,LeetCode1. 两数之和

    哈希表(散列表)理论基础 : 哈希表是根据关键码的值而直接进行访问的数据结构。 直白来讲其实数组就是一张哈希表。   什么时候想到用哈希法, 当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法 。 当我们遇到了要快速判断一个元素是否出现集

    2024年02月10日
    浏览(66)
  • fMRI基础理论知识学习

    时隔多年,再次上线,重新经营csdn。自读研以来,不是干饭就是摆烂,实在颓废,能重新开始写博客,已然不易。在这里立下flag,争取以后每周都能写点什么东西,一来锻炼文笔,二来记录学习历程 我的研究方向与功能磁共振成像fMRI有关,此前从未接触过该领域,完全是从

    2024年02月09日
    浏览(42)
  • AUTOSAR - CANTP - 学习一 :理论基础

    目录 1、概述 2、名词缩写 2.1、前缀含义 2.2、协议数据缩写 3、帧类别

    2024年02月03日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包