【算法刷题 | 回溯思想 01】4.11(回溯算法理论、组合、组合总和 ||| )

在这里插入图片描述

文章目录

  • 回溯
  • 1.回溯算法理论基础
    • 1.1什么是回溯法?
    • 1.2回溯法的效率
    • 1.3回溯法解决的问题
    • 1.4如何理解回溯法?
    • 1.5回溯法模板
  • 2.组合
    • 2.1问题
    • 2.2解法一:暴力解法(循环次数不确定)
    • 2.3解法二:回溯
      • 2.3.1回溯思路
        • (1)回溯函数模板返回值以及参数
        • (2)回溯函数终止条件
        • (3)回溯搜索的遍历过程
      • 2.3.2代码实现
      • 2.3.3剪枝操作
  • 3.组合总和 |||
    • 3.1问题
    • 3.2解法:回溯
      • 3.2.1回溯思路
        • (1)函数返回值以及参数
        • (2)终止条件
        • (3)遍历过程
      • 3.2.2代码实现
      • 3.2.3剪枝操作

回溯

1.回溯算法理论基础

1.1什么是回溯法?

  1. 回溯法也可以叫做回溯搜索法,它是一种搜索的方式。
  2. 回溯是递归的副产品,只要有递归就会有回溯。

1.2回溯法的效率

  1. 虽然回溯法很难,很不好理解,但是回溯法并不是什么高效的算法
  2. 因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。

1.3回溯法解决的问题

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

补充:组合是不强调元素顺序的,排列是强调元素顺序

例如:{1, 2} 和 {2, 1} 在组合上,就是一个集合,因为不强调顺序,而要是排列的话,{1, 2} 和 {2, 1} 就是两个集合了。

1.4如何理解回溯法?

  1. 回溯法解决的问题都可以抽象为树形结构
  2. 因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成了树的深度
  3. 递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

1.5回溯法模板

  • 回溯三部曲:

    • 回溯函数模板返回值以及参数(回溯算法中函数返回值一般为void)

    • 回溯函数终止条件:(搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归。)

      if (终止条件) {存放结果;return;
      }
      
    • 回溯搜索的遍历过程(回溯法一般是在集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成的树的深度)

      for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果
      }
      
      • for循环就是遍历集合区间,可以理解一个节点有多少个孩子,这个for循环就执行多少次。
      • 大家可以从图中看出for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。
  • 回溯算法模板框架:

    void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}
    }
    

2.组合

2.1问题

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

  • 示例一:
输入:n = 4, k = 2
输出:
[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],
]
  • 示例二:
输入:n = 1, k = 1
输出:[[1]]

2.2解法一:暴力解法(循环次数不确定)

  • 使用for循环,例如示例中k为2,很容易想到 用两个for循环,这样就可以输出 和示例中一样的结果。

    for (int i = 1; i <= n; i++) {for (int j = i + 1; j <= n; j++) {cout << i << " " << j << endl;}
    }
    
  • 如果n为100,k为50呢,那就50层for循环,循环写不出来

2.3解法二:回溯

2.3.1回溯思路

  • 分解成一层一层的树形结构:

77.组合

  • 使用res存放全部合适的结果;
  • 使用paths存放当前的路径;
(1)回溯函数模板返回值以及参数
  • 回溯函数返回值一般为void;
  • 参数:
    • 题目要求 求范围[1,n]中所有可能的k个数的组合;
    • 参数有 n、k
    • 还要有一个startIndex,代表每次循环从数组第几个数开始遍历
private void backtracking(int n,int k,int startIndex)
(2)回溯函数终止条件
  • 当当前路径 path 的个数达到k时,添加到res中
if(paths.size()==k){res.add(paths);return;	
}
(3)回溯搜索的遍历过程
  • 从startIndex遍历该层的元素
for(int i=startIndex;i<=n;i++){paths.add(i);//递归backtracking(n,k,i+1);//回溯paths.remove(paths.size()-1);
}

2.3.2代码实现

	List<List<Integer>> res=new ArrayList<>();List<Integer> paths=new ArrayList<>();public List<List<Integer>> combine(int n, int k) {backtracking(n,k,1);return res;}private void backtracking(int n,int k,int startIndex){if(paths.size()==k){res.add(new ArrayList<>(paths));return;	}for(int i=startIndex;i<=n;i++){paths.add(i);//递归backtracking(n,k,i+1);//回溯paths.remove(paths.size()-1);}}

2.3.3剪枝操作

  • 回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的

  • 遍历代码如下:

    for(int i=startIndex;i<=n;i++){paths.add(i);//递归backtracking(n,k,i+1);//回溯paths.remove(paths.size()-1);
    }
    
  • 这个遍历的范围是可以剪枝优化的,怎么优化呢?

    • 来举一个例子,n = 4,k = 4 的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。 在第二层for循环,从元素3开始的遍历都没有意义了。

      77.组合4

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

  • 优化过程如下:

    • 已经选择的元素个数:path.size();
    • 还需要的元素个数为: k - path.size();
    • 在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历
  • 为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。

  • 举个例子,n = 4,k = 3, 目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2

  • 从2开始搜索都是合理的,可以是组合[2, 3, 4]。

for(int i=startIndex;i<= n - (k - paths.size()) + 1;i++){paths.add(i);//递归backtracking(n,k,i+1);//回溯paths.remove(paths.size()-1);
}

3.组合总和 |||

3.1问题

找出所有相加之和为 nk 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

  • 示例一:
输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。

3.2解法:回溯

3.2.1回溯思路

(1)函数返回值以及参数
  • 无返回值
  • 参数:
    • k:总共需要k个数
    • n:总和为n
    • startIndex:从startIndex开始遍历
    • count:当前路径总和
private void backtracking(int k,int n,int startIndex,int count)
(2)终止条件
  • 判断路径个数是否为k,路径总和是否为n,满足则添加到res中并返回
if( paths.size()==k ){if(count==n){res.add(new ArrayList<>(paths));   }return;	
}
(3)遍历过程
  • 从startIndex开始递归(paths加上该节点、count总和加上)
  • 递归后回溯(paths移除最后一个节点、count总和减去该节点值)
for(int i=startIndex;i<=9;i++){paths.add(i);//递归backtracking(k,n,i+1,count+=i);//回溯paths.remove(paths.size()-1);count-=i;
}

3.2.2代码实现

	List<List<Integer>> res=new ArrayList<>();List<Integer> paths=new ArrayList<>();public List<List<Integer>> combinationSum3(int k, int n) {backtracking(k,n,1,0);return res;}private void backtracking(int k,int n,int startIndex,int count){if( paths.size()==k ){if(count==n){res.add(new ArrayList<>(paths));   }return;	}for(int i=startIndex;i<=9;i++){paths.add(i);//递归backtracking(k,n,i+1,count+=i);//回溯paths.remove(paths.size()-1);count-=i;}}

3.2.3剪枝操作

		for(int i=startIndex;i<= 9-(k-paths.size())+1 ;i++){paths.add(i);//递归backtracking(k,n,i+1,count+=i);//回溯paths.remove(paths.size()-1);count-=i;}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/818026.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity Shader之数学篇

一、坐标系 1、二维笛卡尔坐标系 屏幕坐标系是二维笛卡尔坐标系&#xff0c;OpenGL的屏幕坐标系原点在左下角&#xff0c;DirectX的屏幕坐标系原点在左上角。 2、三维笛卡尔坐标系 三维笛卡尔坐标系要区分是左手坐标系还是右手坐标系。 左手坐标系&#xff1a;举起你的左手…

linnux文件服务

1.FTP:文件传输协议。 基础:控制端口(身份验证) command 21/tcp 数据端口: data 20/tcp FTP Server默认配置:yum -y install vsftpd (安装vsftpd&#xff09; touch /var/ftp/abc.txt(创建文件) systemctl start vsftpd(启动文件&#xff09; systemctl …

Word文档如何更改页面背景颜色?

在Microsoft Word中&#xff0c;设置页面颜色的方法有多种&#xff0c;以下为其中几种常用的方法&#xff1a;&#xff08;为office2016版本操作&#xff09; 方法一&#xff1a;使用主题颜色 1. 打开Word文档&#xff0c;在菜单栏中选择“设计”。 2. 在“设计”选项卡中&a…

泰山众筹:低门槛高回报的电商营销新模式

大家好&#xff0c;我是吴军&#xff0c;来自一家专注于软件开发的公司&#xff0c;担任产品经理一职。今天&#xff0c;我想与大家分享一种备受瞩目的商业模式——泰山众筹。 泰山众筹之所以能够在市场上迅速走红&#xff0c;其背后的原因值得我们深入探讨&#xff1a; 首先&…

idm线程越多越好吗 idm线程数多少合适

IDM&#xff08;Internet Download Manager&#xff09;是一款流行的下载管理软件&#xff0c;它支持多线程下载&#xff0c;这意味着它可以同时建立多个连接来下载文件的不同部分&#xff0c;从而提高下载速度。我们在使用IDM的时候总是有很多疑问&#xff0c;今天我们学习IDM…

游戏开发者必看:Perforce Helix Core 的功能特点及游戏开发中的常用工具、典型用例介绍

「不出海&#xff0c;即出局」随着全球化的加速发展&#xff0c;企业出海已成燎原之势。日前&#xff0c;2024 亚马逊云科技出海全球化论坛在深圳成功举办。龙智携手 Perforce 亮相游戏行业展区&#xff0c;展示了Perforce Helix Core如何与主流游戏开发引擎高效集成&#xff0…

Pytest精通指南(12)Parametrize源码拆解

文章目录 前言Parametrize 参数化Parametrize 源码分析Parametrize 使用说明一个参数的参数化多个参数的参数化验证类中有多个测试函数验证变量或函数传递参数化验证笛卡尔积拓展用法 前言 在 pytest 中&#xff0c;有两种常见的参数化方法&#xff1a; pytest.mark.parametriz…

哈希密码破解方法汇总

案例: 如何破译 254aa248acb47dd654ca3ea53f48c2c26 e93a1ec56258df7674c4 258df7674c4 该hash加密串的原文信息 步骤: 1)通过Hash Analyzer - TunnelsUP站点了解该hash加密串所使用的哈希加密算法类型。 可知,使用了 sha2-256 加密算法。 2) 访问example_hashes [hash…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十一 简单给视频添加水印图片效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十一 简单给视频添加水印图片效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十一 简单给视频添加水印图片效果 一、简单介绍 二、简单给视频添加水印图片效果实现…

【Linux学习】初识Linux指令(二)

文章标题 1.rm 指令2.man指令3.nano指令4.cp指令5.mv指令6.alias指令7. cat与8.echo指令 ⚶文章简介 ⚶本篇文章继上篇文章Linux指令讲解&#xff0c;本篇文章主要会涉及到的指令会有&#xff1a;rm指令与 *&#xff08;通配符&#xff09;的搭配使用&#xff0c;man指令&…

专业SEO优化指南:设置网站关键词的详细步骤

在网站SEO优化的过程中&#xff0c;关键词的设置是提升网站排名的关键步骤之一。那么&#xff0c;作为一名专业的SEO人员&#xff0c;如何有效地进行关键词设置呢&#xff1f;以下是一些详细的步骤&#xff1a; 1. 确定网站的核心关键词。 这需要深入理解网站的主题或产品。通…

整体性学习

整体性学习的顺序&#xff1a; 1.获取 2.理解&#xff08;明白&#xff09;3.拓展&#xff08;探究&#xff09;4.纠错&#xff08;调试&#xff09;5.应用 测试伴随每一个过程 例如&#xff1a; 吃饭&#xff08;去学习&#xff09;–>点菜&#xff08;学什么&#xff0c…

实时数据同步之Maxwell和Canal

文章目录 一、概述1、实时同步工具概述1.1 Maxwell 概述1.2 Canal概述 2、数据同步工作原理2.1 MySQL 主从复制过程2.2 两种工具工作原理 3、MySQL 的 binlog详解3.1 什么是 binlog3.2 binlog 的开启3.3 binlog 的分类设置 4、Maxwell和Canal对比5、环境安装 二、Maxwell 使用1…

日本极致产品力|一个战略符号打造年销售超4亿份的冰淇淋大单品

日本赤城乳业有一款冰棍——ガリガリ君(GariGarikun)&#xff0c;凭借着自己的“纯粹”打入市场&#xff0c;几十年来它成为许多日本人的夏日必备。他让人记忆最深刻的是战略符号——ガリガリ君&#xff0c;让赤城乳业打造出年销售4亿份的冰淇淋大单品。它是如何做到的呢? 石油…

Day55 动态规划 part15

Day55 动态规划 part15 392.判断子序列 我的思路&#xff1a; 自己还是只能想到双指针法 解答: class Solution {public boolean isSubsequence(String s, String t) {if(s.length() 0) {return true;}if(s.length() > t.length() || t.length() 0) {return false;}ch…

性能再升级!UNet+注意力机制,新SOTA分割准确率高达99%

UNet结合注意力机制能够有效提升图像分割任务的性能。 具体来说&#xff0c;通过将注意力模块集成到UNet的架构中&#xff0c;动态地重新分配网络的焦点&#xff0c;让其更集中在图像中对于分割任务关键的部分。这样UNet可以更有效地利用其跳跃连接特性&#xff0c;以精细的局…

VMware安装Linux虚拟机(rocky9)

软件准备&#xff1a; VMware虚拟机ISO系统镜像文件 选择创建虚拟机→典型→下一步→点击稍后安装操作系统 选择Linux系统和对应版本 输入虚拟机名称和选择保存位置 设置磁盘大小 根据需要自定义硬件配置→完成 然后点击编辑虚拟机设置→CD/DVD→选择ISO镜像 然后开启虚拟机→…

动态规划|343.整数拆分

力扣题目链接 class Solution { public:int integerBreak(int n) {vector<int> dp(n 1);dp[2] 1;for (int i 3; i < n ; i) {for (int j 1; j < i / 2; j) {dp[i] max(dp[i], max((i - j) * j, dp[i - j] * j));}}return dp[n];} }; 思路 看到这道题目&…

【GD32】 2.39 FR1002人脸识别模块

2.39 FR1002人脸识别模块 FR1002人脸识别模组解决方案以高性能应用处理器为硬件平台&#xff0c;配合双目传感器进行活体检测&#xff0c;具有启动速度快、金融级的识别能力、超低使用功耗等特点。凭借超低功耗、强大的运算速度&#xff0c;在多种应用领域中&#xff0c;为各行…

关于《CS创世 SD NAND》的技术学习分享

最近发现一个好玩的东西《CS创世 SD NAND》&#xff0c;带大家一起体验一下。 本文引用了部分厂家产品资料及图像&#xff0c;如有侵权&#xff0c;请及时联系我删除&#xff0c;谢谢。 《CS创世 SD NAND》官方网站&#xff1a;http://www.longsto.com/ 什么是CS创世 SD NAND呢…