剑指offer-27、字符串的排列
题⽬描述
输⼊⼀个字符串,按字典序打印出该字符串中字符的所有排列。例如输⼊字符串 abc ,则按字典序打印出由字符 a , b , c 所能排列出来的所有字符串 abc , acb , bac , bca , cab 和 cba 。
输⼊描述:输⼊⼀个字符串,⻓度不超过9(可能有字符重复),字符只包括⼤⼩写字⺟
思路及解答
递归回溯(使用Set去重)
看到题目,应该就知道要使⽤回溯了。
通过 回溯算法 生成所有排列,配合 剪枝条件 实现去重和字典序输出。关键步骤包括:
- 固定位置法:逐个固定每个位置的字符
- 交换策略:通过交换字符位置生成不同排列
- 去重处理:使用集合(Set)或排序后跳过重复字符来避免重复排列
- 字典序排序:最后对结果进行排序
import java.util.ArrayList;
import java.util.Collections;
public class StringPermutation {
public ArrayList<String> permutation(String str) {
ArrayList<String> result = new ArrayList<>();
if (str == null || str.length() == 0) {
return result;
}
char[] chars = str.toCharArray();
permute(chars, 0, result);
Collections.sort(result); // 按字典序排序
return result;
}
private void permute(char[] chars, int begin, ArrayList<String> result) {
if (begin == chars.length - 1) {
result.add(new String(chars));
return;
}
for (int i = begin; i < chars.length; i++) {
// 跳过重复字符,避免重复排列
if (i != begin && chars[i] == chars[begin]) {
continue;
}
swap(chars, begin, i);
permute(chars, begin + 1, result);
swap(chars, i, begin); // 回溯,恢复原始状态
}
}
private void swap(char[] chars, int i, int j) {
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
}
- 时间复杂度:O(n*n!),n为字符串长度,n!是排列总数,每次排列需要O(n)时间
- 空间复杂度:O(n!),需要存储所有排列结果
回溯+剪枝法(优化去重)
上面方法主要是通过Set进行去重,也可以将字符数组排序来跳过重复字符:
- 先排序:将字符数组排序,使相同字符相邻
- 剪枝策略:在递归过程中跳过相同字符的重复分支
- 标记数组:使用boolean数组记录已使用字符
public class StringPermutation {
public ArrayList<String> permutation(String str) {
ArrayList<String> result = new ArrayList<>();
if (str == null || str.length() == 0) {
return result;
}
char[] chars = str.toCharArray();
Arrays.sort(chars); // 先排序便于去重
boolean[] used = new boolean[chars.length];
backtrack(chars, used, new StringBuilder(), result);
return result;
}
private void backtrack(char[] chars, boolean[] used,
StringBuilder path, ArrayList<String> result) {
if (path.length() == chars.length) {
result.add(path.toString());
return;
}
for (int i = 0; i < chars.length; i++) {
// 剪枝条件:跳过已使用字符或相同字符的重复分支
if (used[i] || (i > 0 && chars[i] == chars[i-1] && !used[i-1])) {
continue;
}
used[i] = true;
path.append(chars[i]);
backtrack(chars, used, path, result);
path.deleteCharAt(path.length() - 1); // 回溯
used[i] = false;
}
}
}
- 时间复杂度:O(n*n!),但剪枝减少了不必要的递归调用
- 空间复杂度:O(n!),结果存储空间
非递归
此方法算法理解难度较大,非标准解法
用字典序生成下一个排列的算法:
- 初始排序:将字符数组按字典序排序
- 找下一个排列:
- 从后向前找到第一个升序对
- 交换适当元素
- 反转后缀
- 循环生成:直到无法生成下一个排列
import java.util.ArrayList;
import java.util.Arrays;
public class StringPermutation {
public ArrayList<String> permutation(String str) {
ArrayList<String> result = new ArrayList<>();
if (str == null || str.length() == 0) {
return result;
}
char[] chars = str.toCharArray();
Arrays.sort(chars); // 初始排序
result.add(new String(chars));
while (true) {
int i = chars.length - 2;
// 从后向前找第一个升序对
while (i >= 0 && chars[i] >= chars[i + 1]) {
i--;
}
if (i < 0) break; // 已是最大排列
int j = chars.length - 1;
// 找到第一个大于chars[i]的字符
while (chars[j] <= chars[i]) {
j--;
}
swap(chars, i, j);
reverse(chars, i + 1, chars.length - 1);
result.add(new String(chars));
}
return result;
}
private void swap(char[] chars, int i, int j) {
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
private void reverse(char[] chars, int start, int end) {
while (start < end) {
swap(chars, start++, end--);
}
}
}
- 时间复杂度:O(n*n!),每次生成下一个排列需要O(n)时间
- 空间复杂度:O(n!),结果存储空间
剑指offer-27、字符串的排列的更多相关文章
- 剑指Offer 27. 字符串的排列 (字符串)
题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: 输 ...
- [剑指Offer] 27.字符串的排列
[思路]从第一位开始,判断每一位字符的所有可能性,依此递归. class Solution { public: void PermutationHelp(vector<string> &a ...
- 剑指 Offer 38. 字符串的排列 + 无重复元素的全排列
剑指 Offer 38. 字符串的排列 Offer_38 题目描述 解题思路 可以使用递归实现全排列,每次都确定一个数的位置,当所有位置的数都确定后即表示一个排列. 但是考虑到本题需要排除重复的排列, ...
- 剑指 Offer 38. 字符串的排列
剑指 Offer 38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" ...
- 【剑指Offer】字符串的排列 解题报告(Python)
[剑指Offer]字符串的排列 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://www.nowcoder.com/ta/coding-interviews 题 ...
- 【Java】 剑指offer(38) 字符串的排列
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 输入一个字符串,打印出该字符串中字符的所有排列.例如输入字符串ab ...
- Go语言实现:【剑指offer】字符串的排列
该题目来源于牛客网<剑指offer>专题. 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,b ...
- 《剑指offer》字符串的排列
本题来自<剑指offer> 反转链表 题目: 思路: C++ Code: Python Code: 总结:
- 剑指offer:字符串的排列
题目描述: 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: ...
- 剑指OFFER之字符串的排列(九度OJ1369)
题目描述: 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入: 每个 ...
随机推荐
- 基于混合检索与RRF融合的智能问答系统核心技术解析
引言 在当今信息爆炸的时代,如何快速.精准地从海量知识中定位用户所需信息,成为智能问答系统面临的核心挑战.GC-QA-RAG系统通过创新的向量检索技术和混合检索机制,实现了高效的知识点定位能力.本文将 ...
- s40破解证书
说明因为怀旧,淘了个诺基亚5130xm.打开jar软件(比如QQ音乐,Anyview)后发现个问题,老是频繁弹出"是否同意读取用户数据"的弹窗而这些软件可能没有证书,没有证书的话意 ...
- 前端开发系列082-Node篇之PRPL
本文主要介绍Node提供的交互式运行环境REPL,包括常见操作以及基础命令等内容. 一.REPL介绍 在Node.js中,提供了一个交互式的运行环境-REPL(Read-Eval-Print-Loop ...
- 前端开发系列069-JQuery篇之框架动画特效
一.jQuery动画特效说明 jQuery框架中为我们封装了众多的动画和特效方法,只需要调用对应的动画方法传递合适的参数,就能够方便的实现一些炫酷的效果,而且jQuery框架还支持自定义各种动画效果. ...
- 关于 python 人脸检测库 dlib 的 初识 2
简介 关于人脸检测算法python库的初步认识2 使用CNN的实现人脸检测 简单说明 The example loads a pretrained model and uses it to find ...
- 关于random 函数 在linux上可以执行,在windows 上执行不了的问题
简介 RT 解决方案 最终linux上的random函数,发现了这么一句英文 /* These are the functions that actually do things. The rando ...
- vue 不完美的多标签页解决方案
背景 多标签页多用在中后台管理系统,能够让用户同时打开多个标签页,而且不会丢失之前填写的内容,操作起来会比较方便.虽然部分开源项目有多标签页的功能,但就体验来看,算不上特别好. 目标 可以通过rout ...
- SciTech-Mathmatics-Probability+Statistics: Assumptions, $\large P-value$, $\large overall\ F-value$ and $\large Null\ and\ Alternative\ Hypothesis$ for $\large Linear\ Regression\ Model$
Null and Alternative Hypothesis for Linear Regression Linear regression is a technique we can use to ...
- SciTech-BigDataAIML-CV+CG-Digital Image/Signal Processing-
Links: Lectures: https://mandeel.github.io/lectures.html https://mandeel.github.io/ A Ph.D. in compu ...
- SciTech-Mathematics-Probability+Statistics-CDF vs. PDF: What’s the Difference? PDF:概率密度函数+CDF:累积分布函数-
https://www.statology.org/cdf-vs-pdf/ CDF vs. PDF: What's the Difference? This tutorial provides a s ...