求下一排列问题和全排列问题

news/2025/3/9 22:11:21/文章来源:https://www.cnblogs.com/ofnoname/p/18751783

排列,字典序与下一排列

假设你有一个数组或序列,下一个排列是指在字典序上比当前排列更大的排列。如果当前排列已经是最大的排列,那么下一个排列是最小的排列。

例如,给定一个数组 [1, 2, 3],它的下一个排列是 [1, 3, 2];再下一个是[2, 1, 3];而对于 [3, 2, 1],它已经是最大排列;一般规定下一个排列又循环到最小排列,即 [1, 2, 3]

求下一排列的关键是从当前排列出发,利用字典序的性质来找到下一个更大的排列。这个算法的核心步骤如下:

  1. 从右向左扫描数组,找到第一个下降的位置。即找到一个元素 nums[i],使得 nums[i] < nums[i + 1]。这个位置的存在意味着当前排列还可以变大。如果没有找到这样的 i,说明当前排列已经是最大的排列。

  2. 找到比 nums[i] 大的最小元素:找到 i 以右比他大的最小元素(由于 i 以后都是递减的,即最后一个)。

  3. 交换元素:交换 nums[i]nums[j],这一步会确保新的排列更大。

  4. 反转后部分:原来 i 处的元素已被替换为更大的元素;为了确保排列的字典序最小,反转 nums[i+1]nums[n-1] 的部分,使得这一部分由降序变成升序,变成最小的排列。

为什么这样做是对的?

这是由字典序的性质决定的。每个排列在字典序中是由从左到右的逐步交换构成的。

  • 首先,从后向前找到不降序的第一个元素,确定了“还能增加”的部分。
  • 他应和之后最小的元素交换,并把其他元素重新变成正序,确保增加的字典序最小。
void nextPermutation(vector<int>& nums) {int n = nums.size();int i = n - 2;while (i >= 0 && nums[i] >= nums[i + 1]) i--;if (i >= 0) swap(nums[i], nums[n - 1]);reverse(nums.begin() + i + 1, nums.end());
}

很多语言(也包括 C++)自带了此函数,复杂度显然是 \(O(n)\)

全排列问题

全排列问题给定一个长度为 n 的数组,要求返回该数组的所有排列。比如,给定数组 [1, 2, 3],我们要找出 [1, 2, 3][1, 3, 2][2, 1, 3][2, 3, 1][3, 1, 2][3, 2, 1] 这六个排列。

全排列的一个特点是,它会生成所有可能的排列组合,并且每个排列都包含数组中所有元素的不同顺序。全排列一共有 \(n!\) 个,你可以直接用上面的下一排列法枚举,运算量为 \(n! * n\)

另一个方案回溯法,通过递归的方式逐步填充排列中的每一个位置,并在每一步选择不同的元素,最后输出所有可能的排列。

  1. 初始化:从空的排列开始,递归地填充每个位置。
  2. 递归填充排列:每次递归时,我们按顺序在剩余未使用的数字中选择一个,并将其放入当前排列中,递归生成剩余的部分。
  3. 回溯:当递归到达底部(即生成了一个排列),我们回到上一层,尝试其他选择。
  4. 终止条件:当排列的长度等于数组的长度时,表示一个排列已完全生成,加入结果。
void permute(vector<int>& nums, vector<int>& path, vector<vector<int>>& result, vector<bool>& visited) {if (path.size() == nums.size()) {result.push_back(path);return;}for (int i = 0; i < nums.size(); i++) {if (visited[i]) continue;visited[i] = true;path.push_back(nums[i]); permute(nums, path, result, visited);path.pop_back();visited[i] = false;}
}
  • 时间复杂度:全排列问题的时间复杂度为 O(n!),因为生成所有排列需要 n! 个排列,而每生成一个排列需要 O(n) 时间来复制和保存。
  • 空间复杂度:空间复杂度为 O(n),递归深度。

拓展知识

排列顺序源于字典序,所以这种方法不仅适用于整数数组,也可以扩展到其他类型的数组(如字符串、字符等)。也并不要求数字是连续的 1 ~ n

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

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

相关文章

Day08_cmd命令

Java cmd命令 盘符切换查看当前目录下的所有文件:dir 切换目录:cd(例如:cd .. 返回上级目录)系统操作清理屏幕:cls 退出终端:exit 查看电脑IP:ipconfig打开应用程序计算器:calc 画图工具:mspaint 记事本:notepad网络命令测试网络连接:ping www.baidu.com文件与目录…

react虚拟dom是什么?是如何提升性能的

虚拟dom是react的核心概念,它使用js对象来反应真实dom的结构。 当组件的状态变更后,react会计算出新的虚拟dom树,并跟前一次的虚拟dom树进行对比,找出差异(也就是需要更新的部分),最后仅将这些差异应用到真实 DOM 中。通过这种方式,React 避免了对真实 DOM 的频繁操作,…

021 Vue加载Element-plus的字体图标

Element-plus不仅是提供了各种组件,同时还提供了一整套的字体图标方便开发者使用 安装icons字体图标 npm install @element-plus/icons-vue 全局注册 在项目目录下,创建plugins文件夹,在文件夹下创建文件icons.js文件plugins 代表插件的意思import * as components from &q…

借助Deepseek写一个python代码来绘画一个五星红旗

第一次我输入“写一个绘制五星红旗的代码”获得了代码如下,但是它并不能进行正常运行,出现了“AttributeError: Screen object has no attribute title on line 6”这样的错误。 点击查看代码 import turtle# 设置屏幕 screen = turtle.Screen() screen.bgcolor("white&…

【程设の旅】第一次上机卡题复盘

别急,先来张美图不开玩笑了 总结一下,就是感觉目前的思维方式还没有完全形成 有点靠惯性做题,虽然出来了九道,但是还是有点打野拳的感觉 第一卡的是4 04:编程填空:两种计数 描述 填写代码,使输出结果为 0 2 1 11 7 11 4 3 #include <iostream> using namespace std…

Vue3创建

1.创建2.导入idea修改调试 (修剪)(修改)HomeView.vue点击查看代码 <template><div>Hollow World</div> </template><!--setup 代表可以使用Vue3的语法特性--> <script setup></script>(精简路由)index.js点击查看代码import { c…

使用vim编辑器和nmcli的方法配置静态网络

目录使用vim编辑器修改网络配置使用nmcli命令配置网络 使用vim编辑器修改网络配置关于vim编辑器的使用方法注意:以下配置都是在NAT网络模式下进行操作的第一步 确定好虚拟机IP网段并确定网关:vim /etc/sysconfig/network-scripts/ifcfg-ens160 #注意上面的ens160可能与你的电…

C++实验

实验1#include<stdio.h> int main() {int x,y,i;i=0;printf("打印次数:");scanf("%i",&x);printf("打印方向(0为竖,1为横向):");scanf("%i",&y);if(y==0) {while(i<x){printf(" o \n");printf("…

印度股票行情数据API接口教程 StockTV

印度股票实时行情数据接口 印度股票实时行情API数据接口原创 印度交易所股票行情数据API接口 获取数据源测试Key: StockTV API 📚 功能列表模块 功能描述 示例方法股票 市场列表、指数、K线、IPO日历等 get_indices(), get_kline()外汇 实时汇率、交叉汇率、K线图表 get_real…

Oracle VM VirtualBox Ubuntu 桥接模式下 固定虚拟机的 ip

Ubuntu版本: Ubuntu server:22.04.5 LTS 注意:网上找了很多版本,都是相似的去编辑 /etc/netplan/ 下的 xx-cloud-init.yaml 文件,但是配置文件中,有一段提示需要注意此文件是自动生成的,每次开机都会重新生成,所以直接编辑,将不起作用,需要按提示 添加 /etc/cloud/cl…

AtCoder Beginner Contest 396-G - Flip Row or Col

https://atcoder.jp/contests/abc396/tasks/abc396_g 下面给出题目的中文思路、详细解释以及带中文注释的 C++ 实现代码。代码实现 下面给出带中文注释的 C++ 代码: #include <bits/stdc++.h> using namespace std;typedef long long ll;// 快速Walsh-Hadamard变换(FWH…