回溯法解决排列/组合/子集问题

Java实现回溯算法入门(排列+组合+子集) 回溯是递归的副产品,只要有递归就会有回溯,所以回溯法也经常和二叉树遍历,深度优先搜索混在一起,因为这两种方式都是用了递归。 回溯法 采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况: 找到一个可能存在的正确的答案; 在尝试了所有可能的分步方法后宣告该问题没有答案。 回 阅读详情

回溯法

代码方面,回溯算法的框架:

result = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return

    for 选择 in 选择列表:
        [if 其他选择:行为]
        做选择
        backtrack(路径, 选择列表)
        撤销选择
排列问题

问题描述:输入一个不包含重复数字的数组 nums,返回这些数字的全部排列。

这里根据公式
A n m = A n n = n ( n − 1 ) A^nm = A ^n n=n(n-1) Anm=Ann=n(n−1)
可以算出有n(n-1)种可能。

在这里插入图片描述

package BackTrace;

import java.util.ArrayList;
import java.util.List;

/**
 * @author junfeng.lin
 * @date 2021/3/31 17:07
 */
public class AllRank {
    //结果集合
    public static List<List<Integer>> lists = new ArrayList<>();
    //使用数组来判断元素是否被访问过
    public static boolean[] isVisit;
    public static void getResult(int[] nums) {
        isVisit = new boolean[nums.length];
        dfs(nums ,new ArrayList<>());
    }

    public static void dfs(int[] nums ,List<Integer> cur) {
        if (cur.size() == nums.length) {
            //此处要新建集合,cur的值会在后续被改变,结果也被改变了
            lists.add(new ArrayList<>(cur));
            return;
        }
        //每次都从0开始遍历
        for (int i = 0;i < nums.length;i++) {
            if (isVisit[i]) continue;
            isVisit[i] = true;
            cur.add(nums[i]);
            dfs(nums ,cur);
            cur.remove(cur.size() - 1);
            isVisit[i] = false;
        }
    }

    public static void main(String[] args) {
        getResult(new int[]{1,2,3});
        System.out.println(lists);
    }
}

输出:

[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
子集问题

问题描述:输入一个不包含重复数字的数组nums,返回这些数字的所有子集

在这里插入图片描述

package BackTrace;

import java.util.ArrayList;
import java.util.List;

/**
 * @author junfeng.lin
 * @date 2021/3/31 19:54
 */
public class PowerSet {
    //结果集合
    public static List<List<Integer>> lists;
    //使用数组来判断元素是否被访问过
    public static boolean[] isVisit;
    public static void getPowerSet(int[] nums) {
        lists = new ArrayList<>();
        isVisit = new boolean[nums.length];
        dfs(nums ,new ArrayList<>() ,0);
    }

    /**
     * 回溯法
     * @param nums
     * @param cur
     * @param index
     */
    public static void dfs(int[] nums ,List<Integer> cur ,int index) {
        //走到了叶子结点,添加到结果中
        if (index == nums.length) {
            lists.add(new ArrayList<>(cur));
            return;
        }
        for (int i = index;i < nums.length;i++) {
            if (isVisit[i]) continue;

            //不加入这个数
            isVisit[i] = true;
            dfs(nums ,cur ,index + 1);
            isVisit[i] = false;

            //不加入这个数
            isVisit[i] = true;
            cur.add(nums[i]);
            dfs(nums ,cur ,index + 1);
            cur.remove(cur.size() - 1);
            isVisit[i] = false;
        }
    }

    public static void main(String[] args) {
        int[] nums = new int[]{1,2,3};
        getPowerSet(nums);
        System.out.println(lists);
    }
}

输出:

[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]
组合问题

问题描述:从m个球里(编号为1,2,3…,m)一次取n个球,其中m>n,记录取出球的编号,枚举所有的可能性。

假设n为4,k为2,则根据公式
C n m = C 2 4 = 6 C^nm = C ^2 4=6 Cnm=C24=6
可以算出有6种可能。

在这里插入图片描述

package BackTrace;

import java.util.ArrayList;
import java.util.List;

/**
 * @author junfeng.lin
 * @date 2021/3/31 22:12
 */
public class Combination {
    public static List<List<Integer>> lists;
    //使用数组来判断元素是否被访问过
    public static boolean[] isVisit;
    public static void getCombination(int n ,int k) {
        lists = new ArrayList<>();
        isVisit = new boolean[n + 1];
        dfs(n ,k ,new ArrayList<>() ,1);
    }

    public static void dfs(int n ,int k ,List<Integer> cur ,int start) {
        //当集合中有k个元素时,说明出现了一种情况
        if (k == cur.size()) {
            lists.add(new ArrayList<>(cur));
            return;
        }
        for (int i = start;i <= n;i++) {
            cur.add(i);
            //注意从i + 1 开始,而不是从start开始向下递归
            dfs(n ,k ,cur ,i + 1);
            cur.remove(cur.size() - 1);
        }
    }

    public static void main(String[] args) {
        getCombination(4 ,2);
        System.out.println(lists);
    }
}

输出:

[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
【回溯方法(解决子集、组合、排列问题)】 回溯算法就是纯暴力算法,有些问题纯暴力写不出来就得用回溯方法,比如:要你在100个数中,挑50个数,如果用暴力写得用50层for循环,显然是不现实的,所以引进了回溯方法,暴力解法中的嵌套的for相当于回溯方法中的递归,可以理解为进入下一层决策树,在进入下一层决策树之前要做出选择,之后要撤销选择。抽象地说,解决一个回溯问题,实际上就是遍历一棵决策树的过程,树的每个叶子节点存放着一个合法答案。你把整棵树遍历一遍,把叶子节点上的答案都收集起来,就能得到所有的合法答案。 阅读详情

相关推荐

算法和数据结构(Python)——回溯法求排列组合

适用情况 需要找数组中数字的组合或排列 例一 子集 leetcode 78 (medium)给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 示例: Input: [1, 5, 3] Output: [], [1], [5], [3], [1,5], [1,3], [5,3], [1,5,3] 解题思路: 迭代,从空元素开始,循环每加入一个数组中的数值都相当于在上一个...

goldgirly的博客 1794

【回溯法算法框架】

回溯法在组合问题、排列问题、分割问题等领域表现出色。它的核心思想基于“试错”——通过尝试分步去解决一个问题,在解决过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解时,它将取消上一步甚至是几步的计算,再通过其他的可能的分步解再次尝试找到问题的答案。解空间可以被理解为包含了问题所有可能解的集合。在回溯法中,解空间通常被组织成为一个决策树,也被称为状态空间树。决策树的每个节点代表一个可能的状态,从根节点到叶节点的路径代表了一个完整的解决方案。子集树表示的是所有子集的集合,常用于解决组合问题。

武帝为此的博客 3175

一文搞懂全排列、组合、子集问题

微信搜一搜:【bigsai】 获取更多肝货知识 春风十里,感谢有你 前言 Hello,大家好,我是bigsai,long time no see!在刷题和面试过程中,我们经常遇到一些排列组合类的问题,而全排列、组合、子集等问题更是非常经典问题。本篇文章就带你彻底搞懂全排列! 求全排列? 全排列即:n个元素取n个元素(所有元素)的所有排列组合情况。 求组合? 组合即:n个元素取m个元素的所有组合情况(非排列)。 求子集? 子集即:n个元素的所有子集(所有可能的组合情况)。 总的来说全排列数值个数是所有元素.

bigsai 4416

【PTA】7-3 子集和问题 (30 分) 回溯法

输入: 5 10 2 2 6 5 4 输出: 2 2 6 代码1:dfs,d就完事了。 #include<bits/stdc++.h> using namespace std; #define pb push_back int n; int c; int a[20000]; vector<int>ans; int flag=0; void dfs(int u,int rest,int sumrest)//当前第几个 离目标差几 还剩的机会 { if(rest==0) {.

karshey的博客 2876

【JavaScript 算法】回溯法:解决组合与排列问题

回溯法是一种通过尝试所有可能的解来解决问题的算法策略。它在组合和排列问题中尤为有效,通过递归地构建解空间树并在必要时进行回退(即“回溯”),从而找到所有满足条件的解。

Allen- 1777

子集和数问题(回溯法)

给定N个数,和一个整数M,判定是否可以从N个数中取出若干个数,使它们的和等于M。输出:YES或者NO。把N个数看成一个集合,问题就是从这个集合中选出一个子集,使这个子集满足和是M

子集和问题——回溯法

任务描述 设集合S={x1,x2,…,xn}是一个正整数集合,c是一个正整数,子集和问题判定是否存在S的一个子集S1,使S1中的元素之和为c。试设计一个解子集和问题的回溯法 输入格式 输入数据第1行有2个正整数n和c,n表示S的大小,c是子集和的目标值 接下来的1行中,有n个正整数,表示集合S中的元素 n<10,c<100 输出格式 输出所有满足条件的集合,当问题无解时,输出“No Solution!”。 注意:末尾不输出多余空格 按照输入顺序输出,比如第一个满足条件的子集合是[2 2 6],那

m0_47135938的博客 5865

CoDeSys系列-3、Windows运行时软PLC主站和p-net从站IO设备组网测试

前面CODESY下载安装并熟悉了,p-net搭建从站也已经跑在虚拟机树莓派上了,我们只需要快速搭建一个profinet主站来和从站进行交互即可,这里我们直接用Windows下带的软PLC搭建profinet主站并和p-net的demo从站程序进行IO交互。评估是否进行Windows下的运行时PLC前先看一下注意事项,Windows下安装配置会需要修改boot及防火墙等,可能会影响Windows电脑的正常使用,所以创建项目时的设备可以选择非RTE的。

逍遥游的博客 7312

基于用户的协同过滤算法(JAVA实现)

基于用户的协同过滤算法(JAVA实现)协同过滤算法皮尔森(pearson)相关系数公式Java代码实现 协同过滤算法 协同过滤(简称CF)是推荐系统最重要的思想之一。在早期,协同过滤几乎等同于推荐系统。主要的功能是预测和推荐。算法通过对用户历史行为数据的挖掘发现用户的偏好,基于不同的偏好对用户进行群组划分并推荐品味相似的商品。协同过滤推荐算法分为两类,分别是:1、基于用户的协同过滤算法(user-based collaboratIve filtering)(相似的用户可能喜欢相同物品);2、基于物品的协同过

MiSiTeLin的博客 3万+

orangepi 5 plus ubuntu24.04上安装redroid

OrangePi 5 Plus运行reDroid云手机方案总结 在RK3588+Ubuntu 24.04上部署reDroid(Android容器化方案)的关键步骤: 内核要求:确保启用binderfs(无需ashmem,新版reDroid使用memfd替代); 安装流程: 安装Docker并配置代理加速镜像拉取; 拉取reDroid镜像(推荐Android 12/13 ARM64版本); 通过挂载binderfs启动容器,指定分辨率与DPI参数; 多实例管理: 脚本化创建多个容器(如8个实例),分配独立端口

babytiger的专栏 2291

零成本接入Gemini Pro:GCP+NewAPI+OpenCode全栈方案

AI编程助手在现代开发流程中扮演着越来越重要的角色,其核心原理是通过大语言模型理解开发者意图并生成代码。以Gemini Pro为代表的顶级模型虽然能力出众,但成本控制和接入复杂度成为主要痛点。通过Google Cloud Platform的免费额度与开源工具链组合,开发者可以构建零成本的AI辅助开发环境。该方案采用Vertex AI作为基础模型服务,通过New API实现协议转换,最终与OpenCode终端工具深度集成。这种架构特别适合需要长期稳定使用AI编程助手的开发者,既能享受Gemini Pro的百万

weixin_29051245的博客 428

数组/字符串不连续的满足某条件的最长/最短子集-回溯法-JAVA实现

题目描述 这一类题目包括了如下一堆题目: 1. 字符串、数组的全排列(leetcode 46 给定一个 没有重复 数字的序列,返回其所有可能的全排列) 2. 字符串、数组的去重的/不去重的全组合; 3. 数组的最短子集,该子集所有元素之和为给定的K的倍数 4. 数组的最长子集,该子集所有元素之和为给定的K的倍数 上述题目都用到了回溯法 解法 1. 字符串、数组的全排列 看力扣上的题解,思路是: 数组长度为N,遍历每一位元素,将第i(0=<i<N)个元素固定到首位,剩下的N-1个元素递归调用该函数

Jessie_YYY的博客 570

【BigWorld 游戏服务器引擎】Cell 架构设计介绍,及Java实现方案的探索

横向扩展(Scalability):通过动态增减CellApp和BaseApp的数量,可以轻松应对玩家人数的变化。世界可以做得非常大,只需增加更多的 Cell。负载分离(Load Separation):将不同性质的负载分离,避免了单一进程瓶颈。CPU 密集型的实时计算(CellApp)和 I/O 密集型的数据操作(BaseApp)互不影响。高效的视野管理(AOI):每个 Cell 只关心自己区域内和边界上的实体,大大降低了计算复杂度。容错性:某个CellApp。

代码时光 1205

回溯法算法实践(头哥平台)

测试输入: 0, 0, 0, 0 预期输出: 输入: [0, 0, 0, 0] [0, 0, 0, 0] [0, 0, 0, 1] [0, 0, 1, 0] [0, 0, 1, 1] [0, 1, 0, 0] [0, 1, 0, 1] [0, 1, 1, 0] [0, 1, 1, 1] [1, 0, 0, 0] [1, 0, 0, 1] [1, 0, 1, 0] [1, 0, 1, 1] [1, 1, 0, 0] [1, 1, 0, 1] [1, 1, 1, 0] [1, 1, 1, 1]

qq_60536984的博客 1491

YOLOv8优化:独家创新(SC_C_Detect)检测头结构创新,实现涨点 | 检测头新颖创新系列

独家创新(SC_C_Detect)检测头结构创新,适合科研创新度十足,强烈推荐

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 4871

算法与数据结构-回溯法

一个复杂问题的解决方案是由若干个小的决策步骤组成的决策序列,解决一个问题的所有可能的决策序列构成该问题的解空间。应用回溯法求解问题时,首先应该明确问题的解空间。解空间中满足约束条件的决策序列称为可行解。一般来说,解任何问题都有一个目标,在约束条件下使目标达到最优的可行解称为该问题的最优解。问题的解由一个不等长或等长的解向量X={x1,x2,…,xn}组成,其中分量xi表示第i步的操作。​ 所有满足约束条件的解向量组构成了问题的解空间。​ 问题的解空间一般用树形式来组织,也称为..

weixin_45982141的博客 2387

103.在 Vue 3 中使用 OpenLayers 控制图层来显示/隐藏地图

是一个强大的开源库,可以用于构建各种地理信息系统应用。在 Vue 3 中,我们可以结合。方法,可以直接控制某个图层是否可见,而不需要删除或重新创建图层。在开始之前,确保你已经搭建了 Vue 3 项目,并安装了。本文将详细介绍如何在 Vue 3 组合式 API (,并实现按钮控制地图的显示/隐藏功能。会导致 OSM 瓦片地图无法加载。方法控制地图图层的显示与隐藏。安装完成后,即可开始编写代码。在本教程中,我们介绍了如何在。来实现地图的显示/隐藏功能。来实现交互式地图,并通过。在 WebGIS 开发中,

小彭的博客 1560

【代码随想录训练营】【Day 31】【回溯-5】| Leetcode 491, 46, 47

【代码随想录训练营】【Day 31】【回溯-5】| Leetcode 491, 46, 47。

qq_44574200的博客 392

复现报告:《多回路人机控制系统仿真及II型PIO分析》方法复现与代码实现

本文复现了谭文倩硕士论文《多回路人机控制系统仿真及II型PIO分析》中的关键方法,重点实现了频域驾驶员模型辨识和参数灵敏度分析。通过数字化提取论文图表数据,构建了结构驾驶员模型传递函数,并验证了参数变化对系统特性的影响。采用MATLAB实现了描述函数计算、模型参数辨识和灵敏度分析算法,为后续神经网络模型辨识和II型PIO研究奠定了基础。由于缺乏原始实验数据,部分结果通过数值模拟获得,但仍有效重现了论文的核心分析方法。~~~~~

huanghm88的专栏 175

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

深度优先搜索(DFS)与回溯法:从全排列到子集问题的决策树与剪枝优化

深度优先搜索(DFS)和回溯法是解决复杂问题中不可或缺的算法工具,尤其在组合问题(如全排列、子集等)中,发挥着至关重要的作用。通过递归的方式,DFS 能够遍历问题的解空间,而回溯法则通过撤销不合法的选择,避免重复计算,提高效率。在解题过程中,剪枝是优化回溯法的重要手段,它通过提前排除无效路径,进一步减少了运算的复杂度。本文将深入探讨如何使用 DFS、回溯法及剪枝技术,构建解决全排列和子集问题的决策树,并优化算法的执行效率。题目要求求出数组中所有子集的异或和的总和。解法采用。

17的博客 1万+

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【LeetCode】﹝回溯法ி﹞ 全排列、子集、组合问题

一、全排列 1.1 无重复元素全排列 LeetCode全排列 给定一个没有重复数字的序列,返回其所有可能的全排列 //示例 输入[1, 2, 3] /*输出 [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] */ 1.1.1 从左向右交换 观察元组**[1, 2, 3],以元素1为第一位的元素排列有[1, 2, 3]和[1, 3, 2],此排列可以由初始排列和交换2和3后得到。以元素2为第一位的元素排列有

像写诗一样优雅地写代码~ 1万+

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Python与回溯法(回溯法理论基础、组合、分割、子集、排列问题、N皇后问题等)

讲解了回溯法原理、回溯法模板、组合、子集、切割、排列、N皇后问题等应用,并配合leetcode与python进行代码撰写。

Bala_lala的博客 1179

最全排列组合算法详解以及套路总结一文突破

1.排列组合问题 排列组合是经典的算法问题,相关的内容中学阶段就学习过。在讲算法实现之前,我们先简单复习一下排列组合的相关定义。 排列,英文名称为Permutation,简称P。假设有一个数组{1, 2, 3, 4, 5},我们需要将数组中的所有元素进行排序,那么第一个位置,我们可以选择五个数字的任何一个,共有5种选择。第二个位置,可以选择剩余四个数字的任何一个,共有4种选择。第三个位置,可以选择剩余三个数字中的任何一个,共有3种选择。第四个位置,可以选择剩余两个数字中的任何一个,共有2种选择。最后一个位置

bitcarmanlee的博客 2万+

【算法】回溯法解决排列、组合、子集问题套路总结

对于排列、组合、子集问题,我们可以根据题目的限制条件“元素是否重复”、“是否允许重复选择”,大致的将其分为三类: ①元素无重不可复选,即集合中的元素都是唯一的,每个元素最多只能被使用一次; ②元素可重不可复选,即集合中的元素可以存在重复,每个元素最多只能被使用一次; ③元素无重可复选,即集合中的元素都是唯一的,每个元素可以被使用若干次;

人生何事不浮云 1357

回溯算法解决子集、组合和排列问题

本文主要讲了通过回溯法如何解决排列、组合、子集这三类问题的基本思路: 组合问题关键点在于用一个start来保证每次选择的元素是之前未被选择过的 排列问题关键点在于通过contains()来保证每次选择的元素都未被包含在trace中 这两类问题回溯结束的时机都是搜索到的元素达到了预定的长度,即我们可以判断trace中元素的长度来判断是否终止此次回溯。 而子集问题则不然,因为它的长度是变长的,所以每次进入搜索的第一件事情就是将结果加入到结果集中。

Startapi的博客 922
上一篇: 为什么使用WebSocket?
下一篇: 浅析B+索引以及使用
jf-lin
博客等级 码龄7年 37粉丝 49原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值