学习参考

回溯

与递归相辅相成;回溯是递归的副产品,只要有递归就会有回溯。

回溯函数也就是递归函数,指的都是一个函数。

回溯搜索法

纯暴力搜索

解决的问题

组合问题:N个数里面按一定规则找出k个数的集合

切割问题:一个字符串按一定规则有几种切割方式

子集问题:一个N个数的集合里有多少符合条件的子集

排列问题:N个数按一定规则全排列,有几种排列方式(与组合差别,排列有元素顺序)

棋盘问题:N皇后,解数独等等

理解

抽象的不易理解;抽象为图形结构--树形结构

N叉树【树的宽度:集合的大小(for处理);深度:递归的深度(递归处理)】

模板

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

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

leetcode题目

组合

77.组合

for循环嵌套太多层了

树形结构



不能取前面的的:因为组合是无序的,会重复;

每个节点都是一个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循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了。



优化过程如下:

已经选择的元素个数:path.size();

所需需要的元素个数为: k - path.size();

列表中剩余元素(n-i) >= 所需需要的元素个数(k - path.size())

在集合n中至多要从该起始位置 : i <= n - (k - path.size()) + 1,开始遍历

分割

131. 分割回文串

树形结构

回溯三部曲

递归函数参数返回值

确定终止条件

单层递归逻辑

伪代码

收集结果路径

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. 子集

树形结构



收获结果的时候:在每个节点收获结果

组合和分割问题都是在叶子节点里取结果;

伪代码

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.全排列

树形结构

伪代码:

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例题的更多相关文章

  1. 滑动窗口法——Leetcode例题

    滑动窗口法--Leetcode例题(连更未完结) 1. 方法简介 滑动窗口法可以理解为一种特殊的双指针法,通常用来解决数组和字符串连续几个元素满足特殊性质问题(对于字符串来说就是子串).滑动窗口法的显 ...

  2. 【题解】【排列组合】【回溯】【Leetcode】Generate Parentheses

    Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...

  3. 【题解】【排列组合】【回溯】【Leetcode】Gray Code

    The gray code is a binary numeral system where two successive values differ in only one bit. Given a ...

  4. 【题解】【矩阵】【回溯】【Leetcode】Unique Paths II

    A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...

  5. 回溯法和DFS leetcode Combination Sum

    代码: 个人浅薄的认为DFS就是回溯法中的一种,一般想到用DFS我们脑中一般都有一颗解法树,然后去按照深度优先搜索去寻找解.而分支界限法则不算是回溯,无论其是采用队列形式的还是优先队列形式的分支界限法 ...

  6. 【题解】【矩阵】【回溯】【Leetcode】Rotate Image

    You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise). ...

  7. 由Leetcode详解算法 之 动态规划(DP)

    因为最近一段时间接触了一些Leetcode上的题目,发现许多题目的解题思路相似,从中其实可以了解某类算法的一些应用场景. 这个随笔系列就是我尝试的分析总结,希望也能给大家一些启发. 动态规划的基本概念 ...

  8. Poj 1321 棋盘问题 【回溯、类N皇后】

    id=1321" target="_blank">棋盘问题 Time Limit: 1000MS   Memory Limit: 10000K Total Subm ...

  9. [LeetCode]sum合集

    LeetCode很喜欢sum,里面sum题一堆. 1.Two Sum Given an array of integers, return indices of the two numbers suc ...

  10. 8皇后问题SQL求解(回溯算法)

    问题 八皇后问题是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一 ...

随机推荐

  1. MySQL学习(三)DQL/DML/DDL/DCL 介绍

    参考博客:https://blog.csdn.net/tomatofly/article/details/5949070 DQL(data query language) :数据查询语言 select ...

  2. Goravel ORM 新增模型关联,用 Golang 写关联也可以跟 Laravel 一样简单

    关于 Goravel Goravel 是一个功能完备.具有良好扩展能力的 Web 应用程序框架.作为一个起始脚手架帮助 Golang 开发者快速构建自己的应用.框架风格与 Laravel 保持一致,让 ...

  3. 给生活加点惊喜,做创意生活的原型设计师丨编程挑战赛 x 选手分享

    前言 做产品的大都跳过一个坑:我有了一个很好的产品创意,只差一个程序员帮我实现编程了. 事实上从产品创意到落地上线,中间需要经过非常复杂的过程,细节的逻辑流程才是难点,创意不能落地,并不值钱. 本文作 ...

  4. vmware workstation 版本合集

    各版本序列号 10.x:1Z0G9-67285-FZG78-ZL3Q2-234JG 11.x:YG74R-86G1M-M8DLP-XEQNT-XAHW2 12.x:ZC3TK-63GE6-481JY- ...

  5. springboot--配置格式文件

    修改端口号的三种方法 1.server.port = 80 2.新建application.yml文件. 3.新建application.yaml文件. 配置文件加载顺序: 当三个文件都存在时prop ...

  6. 4种API性能恶化根因分析

    摘要:服务发生性能恶化时,需要投入大量人力分析性能异常根因,分析成本高,耗时长.我们提出了一种先在异常调用链内部分析候选根因,再在全局拓扑环境下对候选根因进行汇聚的二级分析方法,克服了调用链之间异常相 ...

  7. Spring 事务——源码分析

    [事务环境搭建工作]:链接注解 @EnableTransactionManagement:在配置类中添加注解@EnableTransactionManagement,便开启了事务功能.此注解也是了解S ...

  8. Spring Data Redis 框架

    系统性学习,移步IT-BLOG 一.简介 对于类似于首页这种每天都有大量的人访问,对数据库造成很大的压力,严重时可能导致瘫痪.解决方法:一种是数据缓存.一种是网页静态化.今天就讨论数据缓存的实现 Re ...

  9. Linux理论知识

    Linux理论知识   理论知识 1.1文件名后缀 1 作用是说明和注释一个文件的性质. 2 与文件类型无关. 1.2常见的压缩文件后缀名 1.gz 2.bz2 3.xz 4.zip 5.tar 6. ...

  10. DataLeap 数据资产实战:如何实现存储优化?

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 背景 DataLeap 作为一站式数据中台套件,汇集了字节内部多年积累的数据集成.开发.运维.治理.资产.安全等全 ...