【代码随想录】【算法训练营】【第29天】 [491]非递减子序列 [46]全排列 [47]全排列II

news2025/1/16 3:36:18

前言

思路及算法思维,指路 代码随想录。
题目来自 LeetCode。

day 29,周三,坚持坚持~

题目详情

[491] 非递减子序列

题目描述

491 非递减子序列
491 非递减子序列

解题思路

前提:组合子集问题,可能有重复元素,收集条件为递增,至少两个元素
思路:回溯,使用used数组标识同一树层不选取重复元素,输出符合要求结点路径。
重点:不能对数组进行排序,因为要选取的是递增序列,无法改变元素的相对位置;used数组在同一树层有效,并且需要回溯。

代码实现

C语言
used数组记录同层元素是否已使用过
/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

#define MAX_NUMS_SIZE 210
#define OFFSET_NUM 100

int **ans;
int ansSize;
int *length;
int *path;
int pathSize;

void collect()
{
    ans[ansSize] = (int *)malloc(sizeof(int) * pathSize);
    for (int i = 0; i < pathSize; i++) {
        ans[ansSize][i] = path[i];
    }
    length[ansSize] = pathSize;
    ansSize++;
    return ;
}

void backtracking(int *nums, int numsSize, int startIdx)
{
    // 收集条件
    if (pathSize > 1) {
        collect();
    }
    // 退出条件
    if (startIdx >= numsSize) {
        return ;
    }
    // 递归
    // 同一树层used
    bool used[MAX_NUMS_SIZE];
    for (int j = 0; j < MAX_NUMS_SIZE; j++) {
        used[j] = false;
    }
    for (int idx = startIdx; idx < numsSize; idx++) {
        // 去重: 重复元素,递减元素
        if ((used[nums[idx] + OFFSET_NUM] == true) || ((pathSize > 0) && (nums[idx] < path[pathSize - 1])))
        {
            continue;
        }
        // 记录
        path[pathSize] = nums[idx];
        pathSize++;
        used[nums[idx] + OFFSET_NUM] = true;
        backtracking(nums, numsSize, idx + 1);
        // 回溯
        pathSize--;
        // used数组不需要回溯
    }
    return ;
}

int** findSubsequences(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    // 初始化
    ans = (int **)malloc(sizeof(int *) * 50000);
    ansSize = 0;
    length = (int *)malloc(sizeof(int) * 50000);
    path = (int *)malloc(sizeof(int) * numsSize);
    pathSize = 0;
    *returnSize = 0;
    
    backtracking(nums, numsSize, 0);

    *returnSize = ansSize;
    *returnColumnSizes = length;
    return ans;
}

[46] 全排列

题目描述

46 全排列
46 全排列

解题思路

前提:排列问题,元素位置不同视为不同排列结果
思路:回溯,输出叶子结点的路径
重点:不含重复数字时,used数组标记元素值是否使用。

代码实现

C语言
used数组标记元素值是否使用
/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

#define MAX_NUMS  21
#define NUM_OFFSET 10

int **ans;
int ansSize;
int *length;
int *path;
int pathSize;
bool *used;

void collect()
{
    ans[ansSize] = (int *)malloc(sizeof(int) * pathSize);
    for (int i = 0; i < pathSize; i++) {
        ans[ansSize][i] = path[i];
    }
    length[ansSize] = pathSize;
    ansSize++;
    return ;
}

void backtracking(int *nums, int numsSize)
{
    // 收集条件
    if (pathSize == numsSize) {
        collect();
        return ;
    }
    // 递归
    for (int idx = 0; idx < numsSize; idx++) {
        if (used[nums[idx] + NUM_OFFSET] == true) {
            continue;
        }
        // 保存该元素
        path[pathSize++] = nums[idx];
        used[nums[idx] + NUM_OFFSET] = true;
        backtracking(nums, numsSize);
        // 回溯
        pathSize--;
        used[nums[idx] + NUM_OFFSET] = false;
    }
    return ;
}

int** permute(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    ans = (int **)malloc(sizeof(int *) * 10000);
    ansSize = 0;
    length = (int *)malloc(sizeof(int) * 10000);
    path = (int *)malloc(sizeof(int) * numsSize);
    pathSize = 0;
    used = (int *)malloc(sizeof(bool) * MAX_NUMS);
    for (int j = 0; j < MAX_NUMS; j++) {
        used[j] = false;
    }

    backtracking(nums, numsSize);

    *returnSize = ansSize;
    *returnColumnSizes = length;
    return ans;
}

[47] 全排列II

题目描述

47 全排列II
47 全排列II

解题思路

前提:排列问题,元素位置不同视为不同排列结果
思路:回溯,输出叶子结点的路径
重点:重复数字时,used数组标记元素值是否使用完,usedLoc数组标识同一树层元素是否重复选取。

代码实现

C语言

以下3中实现方式,均为去重条件的不同,也可以视为used数组含义不同。

两个used数组分别标识元素是否使用及同一树层元素是否重复使用
/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

#define MAX_NUMS 21
#define NUM_OFFSET 10

int **ans;
int ansSize;
int *length;
int *path;
int pathSize;
int *used;

int cmp(int *p1, int *p2)
{
    return *p1 > *p2;
}

void initUsed(int *nums, int numsSize)
{
    used = (int *)malloc(sizeof(int) * MAX_NUMS);
    // 初始化
    for (int k = 0; k < MAX_NUMS; k++) {
        used[k] = 0;
    }
    // 统计元素数量
    for (int n = 0; n < numsSize; n++) {
        (used[nums[n] + NUM_OFFSET])++;
    }
    return ;
}

void collect()
{
    ans[ansSize] = (int *)malloc(sizeof(int) * pathSize);
    for (int i = 0; i < pathSize; i++) {
        ans[ansSize][i] = path[i];
    }
    length[ansSize] = pathSize;
    ansSize++;
    return ;
}

void backtracking(int *nums, int numsSize)
{
    // 退出条件
    if (pathSize == numsSize) {
        collect();
        return ;
    }
    // 递归
    // 标识同一树层元素是否使用
    bool usedLoc[numsSize];
    for (int u = 0; u < numsSize; u++) {
        usedLoc[u] = false;
    }
    for (int idx = 0; idx < numsSize; idx++) {
        // 去重
        if (((idx > 0) && (nums[idx] == nums[idx - 1]) && (usedLoc[idx - 1] == false)) || (used[nums[idx] + NUM_OFFSET] == 0)) {
            continue;
        }
        path[pathSize++] = nums[idx];
        (used[nums[idx] + NUM_OFFSET])--;
        usedLoc[idx] = true;
        backtracking(nums, numsSize);
        // 回溯
        pathSize--;
        usedLoc[idx] = false;
        (used[nums[idx] + NUM_OFFSET])++;
    }
    return ;
}

int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    // 初始化
    ans = (int *)malloc(sizeof(int *) * 10000);
    ansSize = 0;
    length = (int *)malloc(sizeof(int) * 10000);
    path = (int *)malloc(sizeof(int) * numsSize);
    pathSize = 0;
    initUsed(nums, numsSize);

    // 排序
    qsort(nums, numsSize, sizeof(int), cmp);
    backtracking(nums, numsSize);

    *returnSize = ansSize;
    *returnColumnSizes = length;
    return ans;
}
used数组标识元素值是否使用,同一树层元素去重
/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

#define MAX_NUMS 21
#define NUM_OFFSET 10

int **ans;
int ansSize;
int *length;
int *path;
int pathSize;
int *used;

int cmp(int *p1, int *p2)
{
    return *p1 > *p2;
}

void initUsed(int *nums, int numsSize)
{
    used = (int *)malloc(sizeof(int) * MAX_NUMS);
    // 初始化
    for (int k = 0; k < MAX_NUMS; k++) {
        used[k] = 0;
    }
    // 统计元素数量
    for (int n = 0; n < numsSize; n++) {
        (used[nums[n] + NUM_OFFSET])++;
    }
    return ;
}

void collect()
{
    ans[ansSize] = (int *)malloc(sizeof(int) * pathSize);
    for (int i = 0; i < pathSize; i++) {
        ans[ansSize][i] = path[i];
    }
    length[ansSize] = pathSize;
    ansSize++;
    return ;
}

void backtracking(int *nums, int numsSize)
{
    // 退出条件
    if (pathSize == numsSize) {
        collect();
        return ;
    }
    // 递归
    // 标识同一树层元素是否使用
    for (int idx = 0; idx < numsSize; idx++) {
        // 去重
        if (((idx > 0) && (nums[idx] == nums[idx - 1])) || (used[nums[idx] + NUM_OFFSET] == 0)) {
            continue;
        }
        path[pathSize++] = nums[idx];
        (used[nums[idx] + NUM_OFFSET])--;
        backtracking(nums, numsSize);
        // 回溯
        pathSize--;
        (used[nums[idx] + NUM_OFFSET])++;
    }
    return ;
}

int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    // 初始化
    ans = (int *)malloc(sizeof(int *) * 10000);
    ansSize = 0;
    length = (int *)malloc(sizeof(int) * 10000);
    path = (int *)malloc(sizeof(int) * numsSize);
    pathSize = 0;
    initUsed(nums, numsSize);

    // 排序
    qsort(nums, numsSize, sizeof(int), cmp);
    backtracking(nums, numsSize);

    *returnSize = ansSize;
    *returnColumnSizes = length;
    return ans;
}
used数组标识是否使用,同一树层是否已有重复元素,或该元素是否已经选取过
/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

#define MAX_NUMS 21
#define NUM_OFFSET 10

int **ans;
int ansSize;
int *length;
int *path;
int pathSize;
bool *used;

int cmp(int *p1, int *p2)
{
    return *p1 > *p2;
}

void collect()
{
    ans[ansSize] = (int *)malloc(sizeof(int) * pathSize);
    for (int i = 0; i < pathSize; i++) {
        ans[ansSize][i] = path[i];
    }
    length[ansSize] = pathSize;
    ansSize++;
    return ;
}

void backtracking(int *nums, int numsSize)
{
    // 退出条件
    if (pathSize == numsSize) {
        collect();
        return ;
    }
    // 递归
    for (int idx = 0; idx < numsSize; idx++) {
        // 去重: 该元素已使用,或 同一树层已有重复元素
        if (((idx > 0) && (nums[idx] == nums[idx - 1]) && (used[idx - 1] == false)) || (used[idx] == true)) {
            continue;
        }
        path[pathSize++] = nums[idx];
        used[idx] = true;
        backtracking(nums, numsSize);
        // 回溯
        pathSize--;
        used[idx] = false;
    }
    return ;
}

int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    // 初始化
    ans = (int *)malloc(sizeof(int *) * 10000);
    ansSize = 0;
    length = (int *)malloc(sizeof(int) * 10000);
    path = (int *)malloc(sizeof(int) * numsSize);
    pathSize = 0;
    used = (bool *)malloc(sizeof(bool) * numsSize);
    // 初始化
    for (int k = 0; k < numsSize; k++) {
        used[k] = false;
    }

    // 排序
    qsort(nums, numsSize, sizeof(int), cmp);
    backtracking(nums, numsSize);

    *returnSize = ansSize;
    *returnColumnSizes = length;
    return ans;
}

今日收获

  1. 组合子集问题:书上所有结点,输出路径,可能会用到used数组去重元素;
  2. 组合排列问题:叶子结点,输出路径,used数组去重元素或元素值。

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

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

相关文章

web刷题记录(3)

[NISACTF 2022]checkin 简单的get传参,好久没做过这么简单的题了 王德发&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff01;&#xff0c;看了源代码以后&#xff0c;本来以为是js脚本的问题&#xff0c;但是禁用js脚本没用&#xff0c;看了大佬的wp以后…

鸿蒙轻内核M核源码分析系列六 任务及任务调度(3)任务调度模块

调度&#xff0c;Schedule也称为Dispatch&#xff0c;是操作系统的一个重要模块&#xff0c;它负责选择系统要处理的下一个任务。调度模块需要协调处于就绪状态的任务对资源的竞争&#xff0c;按优先级策略从就绪队列中获取高优先级的任务&#xff0c;给予资源使用权。本文我们…

面试题------>MySQL!!!

一、连接查询 ①&#xff1a;左连接left join &#xff08;小表在左&#xff0c;大表在右&#xff09; ②&#xff1a;右连接right join&#xff08;小表在右&#xff0c;大表在左&#xff09; 二、聚合函数 SQL 中提供的聚合函数可以用来统计、求和、求最值等等 COUNT&…

Qt 的 d_ptr (d-pointer) 和 q_ptr (q-pointer)解析;Q_D和Q_Q指针

篇一&#xff1a; Qt之q指针&#xff08;Q_Q&#xff09;d指针&#xff08;Q_D&#xff09;源码剖析---源码面前了无秘密_qtq指针-CSDN博客 通常情况下&#xff0c;与一个类密切相关的数据会被作为数据成员直接定义在该类中。然而&#xff0c;在某些场合下&#xff0c;我们会…

【深入学习Redis丨第二篇】Redis集群部署详解

文章目录 Redis集群部署Redis4 Cluster部署 Redis集群部署 1 Redis各节点部署 使用源码安装各节点&#xff0c;不过与非cluster方式不同的是&#xff0c;配置文件中需启动cluster相关的配置。 因本次为伪分布式部署&#xff0c;生产环境部署时建议至少3台机器部署&#xff0…

公园【百度之星】/图论+dijkstra

公园 图论dijkstra #include<bits/stdc.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pii; vector<ll> v[40005]; //a、b、c分别是小度、度度熊、终点到各个点的最短距离 ll a[40005],b[40005],c[40005],dist[40005],st[40005]; void…

搭建基于Django的博客系统数据库迁移从Sqlite3到MySQL(四)

上一篇&#xff1a;搭建基于Django的博客系统增加广告轮播图&#xff08;三&#xff09; 下一篇&#xff1a;基于Django的博客系统之用HayStack连接elasticsearch增加搜索功能&#xff08;五&#xff09; Sqlite3数据库迁移到MySQL 数据库 迁移原因 Django 的内置数据库 SQL…

阿里云私有CA使用教程

点击免费生成 根CA详情 启用根CA -----BEGIN CERTIFICATE----- MIIDpzCCAogAwIBAgISBZ2QPcfDqvfI8fqoPkOq6AoMA0GCSqGSIb3DQEBCwUA MFwxCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdiZWlqaW5nMRAwDgYDVQQHDAdiZWlq aW5nMQ0wCwYDVQQKDARDU0REMQ0wCwYDVQQLDARDU0REMQswCQYDVQQDDAJDTjA…

CAM350如何快速删除Gerber文件上的东西?

文章目录 CAM350如何快速删除Gerber文件上的东西?CAM350如何快速保存已经修改的Gerber文件? CAM350如何快速删除Gerber文件上的东西? CAM如何导入Gerber文件见此篇 今天遇上了一个删除Gerber文件上部分字母的任务&#xff0c;CAM350只能一点点删除线的操作把我手指头差点按…

如何令谷歌浏览器搜索时,子页面使用新窗口,而不是迭代打开

1 问题描述 工作相关需要常用谷歌浏览器&#xff0c;但是现在设置就是每次搜索后&#xff0c;点击搜索结果进去之后&#xff0c;都会覆盖掉原来的父页面&#xff0c;也就是如果我看完了这个子页面的内容&#xff0c;关掉的话&#xff0c;我就需要重新google.com来一遍。。。很…

电路分析答疑 1

三要素法求解的时候&#xff0c; 电容先求U&#xff0c;再利用求导求I 电感先求I&#xff0c;再利用求导求U 若I的头上没有点点&#xff0c;那就是求有效值 叠加定理&#xff0c;不要忘记 若电流值或者电压值已经给出来了&#xff0c;那就说明这一定是直流电。 在画画圈的时候…

【Kubernetes】 emptyDir、nfs存储卷 和 PV、PVC

emptyDir存储卷 当pod被分配给节点 容器和容器之间进行共享存储 hostPath nfs共享存储卷 NAS 专业的存储设备&#xff1b;一般是与NFS 搭配&#xff0c;然后共享出去 GFS 自己搭&#xff1b;CEPH(至少要9台) 第三方&#xff1b;NAS 第三方&#xff1b; 云端 oss …

【多模态】34、LLaVA-v1.5 | 微软开源,用极简框架来实现高效的多模态 LMM 模型

文章目录 一、背景二、方法2.1 提升点2.2 训练样本 三、效果3.1 整体效果对比3.2 模型对于 zero-shot 形式的指令的结果生成能力3.3 模型对于 zero-shot 多语言的能力3.4 限制 四、训练4.1 数据4.2 超参 五、评测六、代码 论文&#xff1a;Improved Baselines with Visual Inst…

深入对比:Transformer与RNN的详细解析

在深度学习领域&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;循环神经网络&#xff08;RNN&#xff09;和Transformer模型都扮演着举足轻重的角色。然而&#xff0c;随着技术的不断发展&#xff0c;Transformer模型逐渐崭露头角&#xff0c;成为…

量子加速超级计算简介

本文转载自&#xff1a;量子加速超级计算简介(2024年 3月 13日) By Mark Wolf https://developer.nvidia.cn/zh-cn/blog/an-introduction-to-quantum-accelerated-supercomputing/ 文章目录 一、概述二、量子计算机的构建块&#xff1a;QPU 和量子位三、量子计算硬件和算法四、…

回炉重造java----JUC(第二天)

Monitor---监视器/管程 对象头&#xff1a; 操作系统提供的Monitor对象 Synchronized底层实现原理&#xff1a; ①锁对象在加了synchronized之后&#xff0c;对象头中的Mark Word中就存了一个Monitor的地址指针。 ②当一个线程获取到锁之后&#xff0c;Monitor中的Owner属性指…

跳跃游戏二

方法一&#xff1a;&#xff08;双指针法&#xff09;此题参考跳台阶问题&#xff0c;题目要求求到达最后一个点的最小跳跃次数&#xff0c;那么我们就可以从最后一个往前推&#xff0c;先看谁能离得最远&#xff0c;并且能跳到最后一个。假设i位置是离最后一个位置最远&#x…

python字符串的进阶

在上一篇文章的 密码破解器 中&#xff0c;我们回顾了循环专题的知识点。 while 循环和 for 循环是 Python 中的两大循环语句&#xff0c;它们都可以实现循环的功能&#xff0c;但在具体使用时略有差别。当循环次数不确定时&#xff0c;我们选用 while 循环&#xff1b;当循环…

Flutter Bloc之简单记录

目录 0.库安装 1.插件和自动生成 2.状态的配置 1.初始化中&#xff1a; 2.赋值完成后&#xff1a; 3.如果出错&#xff1a; 3.事件的配置 1.定义一个读取事件 2.定义一个更改事件 4.Bloc的设置 5.Bloc的使用 1.BlocProvider 2.内部调用 参考文章进行类的配置 0.库…

RPA实战演练UiBot6.0校园学生教评机器人

前言 校园学生教评机器人&#xff0c;也称为全自动校园教评RPA&#xff08;Robotic Process Automation&#xff0c;机器人流程自动化&#xff09;机器人&#xff0c;是一种利用软件机器人技术来模拟和执行学生教评流程中的各项任务和操作的智能化系统。以下是关于校园学生教评…