回溯算法练习day.5

news2024/10/5 18:32:38

491.非递减子序列

链接:. - 力扣(LeetCode)

题目描述:

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例 1:

输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

示例 2:

输入:nums = [4,4,3,2,1]
输出:[[4,4]]

提示:

  • 1 <= nums.length <= 15
  • -100 <= nums[i] <= 100

思路:

因为是求组合问题,因此使用回溯算法,就可以抽象出树形结构,如下所示

由这个树形结构可以看出,对于我们同一层的排列,是不能取数值相同的元素的,即图中绿色标出的部分,否则会导致重复,而对于同一个向下的支路,因为他们是不会导致重复,因此可以取得值相同的元素,根据题目给出的例子,我们可以知道,不能先对例子进行排列,否则输出的结果不准确,并且在这题中,也是在节点收集结果,而不仅仅是叶子节点,我们只是要求节点中元素个数大于二且非递减

回溯实现:

1.确定参数和返回值,参数就是题目的集合已经每次开始遍历的位置

2.确定函数终止条件,当遍历到集合末尾时,退出

3.确定单层递归逻辑,使用一个辅助数组来标记每一层的循环中出现过的元素,如果递归中不是非递减的或者重复出现,则继续访问另外的支路,否则收集结果,递归,回溯

代码实现:

int* path; // 定义路径数组指针
int pathTop; // 定义路径数组的顶部指针
int** ans; // 定义结果数组的指针
int ansTop; // 定义结果数组的顶部指针
int* length; // 定义长度数组指针,用于存储每个子序列的长度

// 将当前路径内容复制到结果数组中
void copy() {
    int* tempPath = (int*)malloc(sizeof(int) * pathTop); // 分配临时数组以存储路径内容
    memcpy(tempPath, path, pathTop * sizeof(int)); // 将路径内容复制到临时数组中
    length[ansTop] = pathTop; // 存储当前路径的长度到长度数组中
    ans[ansTop++] = tempPath; // 将临时数组添加到结果数组中,并更新结果数组的顶部指针
}

// 在给定数组中查找是否存在特定值
int find(int* uset, int usetSize, int key) {
    int i;
    for(i = 0; i < usetSize; i++) {
        if(uset[i] == key) // 如果找到目标值
            return 1; // 返回1表示找到
    }
    return 0; // 否则返回0表示未找到
}

// 回溯算法的实现
void backTracking(int* nums, int numsSize, int startIndex) {
    // 当路径中的元素个数大于1时,将当前路径复制到结果数组中
    if(pathTop > 1) {
        copy();
    }
    int* uset = (int*)malloc(sizeof(int) * numsSize); // 分配临时数组用于存储已经访问过的元素
    int usetTop = 0; // 初始化临时数组的顶部指针为0
    int i;
    for(i = startIndex; i < numsSize; i++) {
        // 如果当前元素小于路径中的最后一个元素,或者在同一层次的树中找到相同的元素,则跳过当前元素
        if((pathTop > 0 && nums[i] < path[pathTop - 1]) || find(uset, usetTop, nums[i]))
            continue;
        // 将当前元素添加到临时数组中
        uset[usetTop++] = nums[i];
        // 将当前元素添加到路径中
        path[pathTop++] = nums[i];
        backTracking(nums, numsSize, i + 1); // 递归调用,继续向下探索
        // 回溯操作,将路径顶部指针减1,恢复到上一层状态
        pathTop--;
    }
}

// 寻找数组的所有递增子序列
int** findSubsequences(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    // 初始化路径数组、结果数组、长度数组以及相关指针
    path = (int*)malloc(sizeof(int) * numsSize);
    ans = (int**)malloc(sizeof(int*) * 33000);
    length = (int*)malloc(sizeof(int) * 33000);
    pathTop = ansTop = 0;

    backTracking(nums, numsSize, 0); // 调用回溯算法寻找递增子序列

    // 设置返回的结果数组的大小以及每个一维数组的长度
    *returnSize = ansTop;
    *returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
    int i;
    for(i = 0; i < ansTop; i++) {
        (*returnColumnSizes)[i] = length[i]; // 将长度数组的值赋给返回的一维数组长度
    }
    return ans; // 返回结果数组
}

46.全排列

链接:. - 力扣(LeetCode)

题目描述:

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]

示例 3:

输入:nums = [1]
输出:[[1]]

提示:

  • 1 <= nums.length <= 6
  • -10 <= nums[i] <= 10
  • nums 中的所有整数 互不相同

思路:

因为是排列问题,因此使用回溯算法来进行解决,我们可以将其抽象为一颗树形结构,并使用一个辅助数组来标记我们每一条支路中使用过的元素

根据树形结构,我们就可以知道每个叶子节点就是我们需要的结果,因为这里求的是排列而不是组合,因此,在不同的大支路中是可以取到前面使用过的元素的,例如第一条支路取了1,第二条支路取2时,在它的分支下还是取到1,因此可以根据树形结构写出实现思路

回溯实现

1.确定函数参数和返回值,参数为题目的集合已经使用的标记数组

2.确定终止条件,到达叶子节点则进行收集,即单个结果集的大小与题目给的集合大小一样时,进行结果的收集

3.确定单层递归逻辑,判断元素是否被收集,如果有则进行下一个判断,如果没有则进行收集,递归,回溯

代码实现:

/**
 * 返回一个大小为*returnSize的数组的数组。
 * 数组的大小作为*returnColumnSizes数组返回。
 * 注意:返回的数组和*columnSizes数组必须分配内存,假设调用者会调用free()释放内存。
 */

int *path; // 声明一个路径数组,用于存储当前遍历的路径
int pathtop; // 记录路径数组中元素的个数

int **result; // 声明一个结果数组的数组,用于存储所有的排列组合
int resulttop; // 记录结果数组中的数组个数

// 设置数组中所有元素为0
void set_0(int *used, int usedtop)
{
    for(int i = 0; i < usedtop; i++)
        used[i] = 0;
}

// 复制当前路径到结果数组中
void copy()
{
    int *temp = (int *)malloc(sizeof(int ) * pathtop);
    for(int i = 0; i < pathtop ; i++)
        temp[i] = path[i];
    result[resulttop++] = temp;
}

// 回溯法求解排列组合
void backtacking(int *nums, int numsSize, int *used)
{
    if(pathtop == numsSize) // 如果路径长度等于数组大小,将当前路径复制到结果数组中
        copy();
    
    for(int i = 0; i < numsSize; i++)
    {
        if(used[i]) // 如果当前元素已经被使用过,则跳过
            continue;
        used[i] = 1; // 标记当前元素为已使用
        path[pathtop++] = nums[i]; // 将当前元素添加到路径中
        backtacking(nums,numsSize,used); // 递归求解下一个元素的排列组合

        pathtop--; // 回溯,恢复到上一个状态
        used[i] = 0; // 取消当前元素的使用标记
    }
}

// 求解排列组合的入口函数
int** permute(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
     path = (int*)malloc(sizeof(int) * numsSize); // 为路径数组分配内存空间
     result = (int**)malloc(sizeof(int*) * 1000); // 为结果数组的数组分配内存空间,初始大小设置为1000
    int* used = (int*)malloc(sizeof(int) * numsSize); // 为标记数组分配内存空间

    set_0(used,numsSize); // 将标记数组中的所有元素设置为0
    resulttop = pathtop = 0; // 初始化结果数组中数组个数和路径数组长度

    backtacking(nums, numsSize,used); // 调用回溯函数求解排列组合
    *returnSize = resulttop; // 将结果数组中数组的个数返回

    *returnColumnSizes = (int*)malloc(sizeof(int) * resulttop); // 为返回的列大小数组分配内存空间
    int i;
    for(i = 0; i < resulttop; i++) {
        (*returnColumnSizes)[i] = numsSize; // 设置每个列的大小为数组的大小
    }
    return result; // 返回排列组合的结果数组
}

47.全排列II

链接:. - 力扣(LeetCode)

题目描述:

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

思路:

这题与上题一样都是全排列问题,但是题目给的是包含重复数字的序列 ,因为我们要进行去重操作,按照例子112来说,如果不进行去重,我们得出的结果就会包含两个112,这就导致输出的结果不准确,去重操作之前要进行排序操作,便于我们判断元素是否被使用,实现的思路与上题一样

代码实现:

int *path; // 定义一个数组指针path,用于存储当前的路径
int pathtop; // 记录当前路径的长度
int **result; // 定义一个指向指针的指针result,用于存储所有的排列结果
int resulttop; // 记录当前已生成排列的个数

int *used; // 定义一个数组指针used,用于标记元素是否被使用过

void copy()
{
    int *temp = (int *)malloc(sizeof(int) * pathtop); // 分配内存以存储当前路径
    for(int i = 0; i < pathtop; i++) // 复制当前路径到temp中
        temp[i] = path[i];
    result[resulttop++] = temp; // 将temp添加到result中,并更新resulttop
}

int cmp(const void *a, const void *b)
{
    return *((int *)a) - *((int *)b); // 比较两个整数的大小,用于qsort排序
}

void backtracking(int *nums, int numsSize, int *used)
{
    if(pathtop == numsSize) // 如果当前路径长度等于数组大小,说明已经生成一个排列
    {
        copy(); // 将当前路径复制到结果中
        return; // 返回
    }
    
    for(int i = 0; i < numsSize ; i++) // 遍历数组元素
    {
        if(used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) // 如果元素已经被使用过,或者当前元素与前一个相同且前一个未被使用过
            continue; // 跳过当前元素
        
        path[pathtop++] = nums[i]; // 将当前元素添加到路径中,并更新路径长度
        used[i] = 1; // 标记当前元素为已使用
        backtracking(nums, numsSize, used); // 递归调用backtracking函数
        pathtop--; // 回溯,恢复路径长度
        used[i] = 0; // 恢复当前元素的使用状态
    }
}

int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    qsort(nums, numsSize, sizeof(int), cmp); // 对数组进行排序,以便处理重复元素的情况

    path = (int *)malloc(sizeof(int) * numsSize); // 分配内存以存储路径
    result = (int **)malloc(sizeof(int*) * 1000); // 分配内存以存储结果
    used = (int *)malloc(sizeof(int ) * numsSize); // 分配内存以存储元素使用情况

    pathtop = resulttop = 0; // 初始化路径长度和结果计数器
    for(int i = 0; i < numsSize ;i++)
        used[i] = 0; // 初始化元素使用情况
    backtracking(nums, numsSize, used); // 调用backtracking函数生成排列
    *returnSize = resulttop; // 返回结果的总数
    *returnColumnSizes = (int *)malloc(sizeof(int) * resulttop); // 分配内存以存储每个排列的长度
    for(int i = 0; i < resulttop; i++)
        (*returnColumnSizes)[i] = numsSize; // 设置每个排列的长度为数组大小
    return result; // 返回结果数组
}

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

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

相关文章

2024全国大学生高新技术竞赛——算法智星挑战赛 解题报告(流水账版) | 珂学家

前言 评价 因为第一届的缘故吧&#xff0c;导致这场比赛异常的简单。所以不太好评价这块。 怎么说呢&#xff1f; 体验有点差 题目难度没有区分度有两题还存在SPJ判定问题&#xff0c;导致赛时没一人过。 题目分布&#xff0c;简单题占大部分&#xff0c;中等级占一小部分&…

【Linux】HTTP协议1

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;题目解析 目录 &#x1f449;&#x1f3fb;http概念初识http协议格式 &#x1f449;&#x1f3fb;URL&#x1f449;&#x1f3fb;简单实现http协议&#xff…

5G前传光纤传输的25G光模块晶振SG2016CAN

一款适用于5G前传光纤传输网络中的25G光模块的5G晶振SG2016CAN。随着5G时代的到来&#xff0c;5G晶振的重要性也不言而喻&#xff0c;小体积宽温晶振SG2016CAN可以用于5G前传的25G光模块&#xff0c;具有高稳定性、小体积、宽温等优势。在5G前传光纤传输网络中&#xff0c;25G光…

java.sql.SQLDataException: Cannot determine value type from string 报错

报错 "org.springframework.dao.DataIntegrityViolationException: Error attempting to get column title from result set. Cause: java.sql.SQLDataException: Cannot determine value type from string 标题\n; Cannot determine value type from string 标题; neste…

ssm089理发店会员管理系统的设计和实现+vue

理发店会员管理系统的设计与实现 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和…

Redis入门到通关之数据结构解析-SkipList

文章目录 ☃️概述☃️总结 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博客 关于博主&#xff1a; 我是 请回答1024&#xff0c;一个追求数学与计算的边界、时间与空间的平衡&#xff0c;0与1的延伸的后端开发者。 博客特色&…

Python_AI库 Pandas在商业环境中的实际用途

Python_AI库 Pandas在商业环境中的实际用途 在前文中我们介绍了Pandas的各种常见操作&#xff0c;由于Pandas提供了高效、灵活且易于使用的数据结构&#xff0c;使得数据处理、清洗、分析和可视化变得更为简单&#xff0c;因此它广泛应用于各种商业应用中。 我们学习一个工具…

如何在Windows 10上刷新DNS?这里提供详细步骤

电脑的DNS缓存出现问题可能会导致连接到互联网时出现问题。如果你尝试过清除浏览器缓存和cookie等常见技巧&#xff0c;刷新Windows 10的DNS可能会解决你的问题。 DNS缓存的作用是什么 域网络系统&#xff08;DNS&#xff09;服务器将熟悉的域名转换为计算机用来相互连接的IP…

Stable Diffusion中的embedding

Stable Diffusion中的embedding 嵌入&#xff0c;也称为文本反转&#xff0c;是在 Stable Diffusion 中控制图像样式的另一种方法。在这篇文章中&#xff0c;我们将学习什么是嵌入&#xff0c;在哪里可以找到它们&#xff0c;以及如何使用它们。 什么是嵌入embedding&#xf…

linux的压缩与备份

一、打包 格式&#xff1a;tar -参数 <打包文件名> <打包的目标> 作用&#xff1a;将文件或者目录打包 重要参数&#xff1a;-f 使用归档文件&#xff0c;一定要加上这个参数 -c 新建打包文件 -x 解包文件 -t 可以不用解包就能查看包文件内容 -v 打包和解包时显…

远程桌面连接不上个别服务器的问题分析与解决方案

在日常的IT运维工作中&#xff0c;远程桌面连接&#xff08;RDP&#xff0c;Remote Desktop Protocol&#xff09;是我们经常使用的工具之一&#xff0c;用于管理和维护远程服务器。然而&#xff0c;有时我们可能会遇到无法连接到个别服务器的情况。针对这一问题&#xff0c;我…

TCP-模拟BS架构通信

简介 bs是通过浏览器进行访问的每次访问都会开启一个短期的socket用来访问服务器的资源 响应报文的格式 服务端 bs架构中的b是浏览器&#xff0c;不需要我们书写&#xff0c;我们只需要书写服务端即可 服务端 public class Server {public static void main(String[] args) {S…

Centos7 RPM包离线安装Nginx

查看是否安装nginx #使用命令 rpm -qa|grep 列出需要卸载的软件包 rpm -qa | grep nginx 卸载nginx #使用rpm -e 加包名删除 rpm -e nginx-release-centos-7-0.el7.ngx.noarch nginx-1.14.1-1.el7_4.ngx.x86_64 rpm -e nginx 安装nginx 其他版本步骤一样 下载rpm包In…

stm32的GPIO基本结构

1.带FT标号的引脚能容忍5V 2.GPIO系统架构 stm32的所有GPIO都是挂载在APB2总线上的 3.GPIO的基本结构 在上图中&#xff0c;左边就是寄存器&#xff0c;右边就是驱动器了 保护二极管的作用&#xff1a;VDD表示3.3V&#xff0c;如果输入的电压的值大于3.3V&#xff0c;那么这个…

融入本土文化:Kompas.ai助力跨境品牌本地化营销

在全球化的商业环境中&#xff0c;跨境品牌面临着将其产品和服务适应不同文化和市场的挑战。本地化营销是品牌国际化战略的关键组成部分&#xff0c;它要求品牌不仅要传递其核心价值&#xff0c;还要尊重并融入目标市场的文化特色。本文将深入探讨跨境品牌在本地化营销中面临的…

知网怎么查重 知网查重的详细步骤

知网查重八个步骤&#xff1a;1. 访问官网&#xff0c;注册账号。2. 上传待查文档。3. 选择查重规则。4. 选择相似来源库。5. 提交查重任务。6. 等待查重结果。7. 获取查重报告。8. 下载查重报告。 知网查重的详细步骤 第一步&#xff1a;进入知网查重系统 打开浏览器&#x…

数据污染对大型语言模型的潜在影响

大型语言模型&#xff08;LLMs&#xff09;中存在的数据污染是一个重要问题&#xff0c;可能会影响它们在各种任务中的表现。这指的是LLMs的训练数据中包含了来自下游任务的测试数据。解决数据污染问题至关重要&#xff0c;因为它可能导致结果偏倚&#xff0c;并影响LLMs在其他…

【EI会议|投稿优惠】2024年机械应用与能源动力国际会议(ICMAEP 2024)

2024 International Conference on Mechanical Applications and Energy Power 一、大会信息 会议名称&#xff1a;2024年机械应用与能源动力国际会议 会议简称&#xff1a;ICMAEP 2024 收录检索&#xff1a;提交Ei Compendex,CPCI,CNKI,Google Scholar等 会议官网&#xff1a;…

应用实战 | 别踩白块小游戏,邀请大家来PK挑战~

“踩白块会输”是一个简单的微信小程序游戏&#xff0c;灵感来自当年火热的别踩白块游戏&#xff0c;程序内分成三个模块&#xff1a;手残模式、经典模式和极速模式&#xff0c;分别对应由易到难的三种玩法&#xff0c;可以查看游戏排名。动画效果采用JS实现&#xff0c;小程序…

CDP客户数据平台:构建S2B2C智能名片商城的核心引擎

在数字化浪潮席卷之下&#xff0c;企业对于客户数据的整合与利用已不再是单纯的竞争优势&#xff0c;而是关乎生存与发展的必要条件。CDP&#xff08;Customer Data Platform&#xff09;客户数据平台&#xff0c;以其统一且持续可访问的特性&#xff0c;正成为S2B2C AI智能名片…