打印不重复的字符串全排列(递归)

简介: 本文将详细解析在生成不重复的字符串全排列时使用的Java代码。首先,我们将展示一个常规的全排列生成方法,然后介绍如何通过使用HashSet来跳过已经尝试过的字符,从而避免生成重复的全排列。最后,我们提供了一道相关的编程题目以供练习。

      什么是不重复的字符串全排列?对于序列acc,它的全排列为accacccacccaccacac,其中acccca各出现两次。为了解决这个问题,我们需要找到一种方法,能够在生成全排列的过程中,避免产生重复的排列。


如果是普通字符串全排列,那么


输入:


acc


输出:


acc

acc

cac

cca

cca

cac


要求写出的去重的,也就是会输出:


acc

cac

cca


上代码进行比较吧,后面给出练习例题。


      首先,我们有一个方法用于生成序列的全排列。然后,我们有一个方法用于交换序列中的两个元素。我们将使用这两个方法来生成序列的全排列,并通过适当的方式避免产生重复的结果。

importjava.io.BufferedInputStream;
importjava.util.HashSet;
importjava.util.Scanner;
importjava.util.Set;
publicclasstest {
publicstaticvoidarrange1(char[] str, inti) {
if (i==str.length) {
System.out.println(str);
        } else {
for (intj=i; j<str.length; ++j) {
swap(str, i, j);
arrange1(str, i+1);
swap(str, i, j);
            }
        }
    }
publicstaticvoidarrange2(char[] str, inti) {
if (i==str.length) {
System.out.println(str);
        } else {
Set<Character>set=newHashSet<Character>(); // 每一层对应一个setfor (intj=i ; j<str.length; ++j) {
if (!set.contains(str[j])) { // 最上面一层的串是起始串,根据起始串思考set.add(str[j]);
swap(str, i, j);
arrange2(str, i+1);
swap(str, i, j);
                }
            }
        }
    }
publicstaticvoidswap(char[] str, inti, intj) {
charc=str[i];
str[i] =str[j];
str[j] =c;
    }
publicstaticvoidmain(String[] args) {
Scannercin=newScanner(newBufferedInputStream(System.in));
Stringstr=cin.next();
arrange1(str.toCharArray(), 0);
System.out.println("======================");
arrange2(str.toCharArray(), 0);
cin.close();
    }
}

image.gif

      对于方法arrange1,它是一个普通的全排列生成方法,不会避免产生重复的结果。而方法arrange2则使用了一种新的方式,来避免产生重复的结果。在arrange2中,我们使用了一个HashSet来存储已经尝试过的字符。这样,如果我们碰到一个已经尝试过的字符,我们就可以直接跳过,而不需要再次生成以这个字符开始的全排列。这样,我们就可以避免产生重复的全排列。


相关题目:

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。


输入描述:

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

题目链接:字符串的排列_牛客题霸_牛客网

测试用例会有空串"",此时不添加进集合,还会有"aa"


分析思路(盗图一张):


image.gif


AC代码:

importjava.util.ArrayList;
importjava.util.Set;
importjava.util.HashSet;
importjava.util.Collections;
importjava.util.Comparator;
publicclassSolution {
ArrayList<String>list=newArrayList<String>();
publicArrayList<String>Permutation(Stringstr) {
if (str.length() !=0) {
Arrange(str.toCharArray(), 0);
// 升序可以不用第二个参数,这里cab测试用例在cba前面,说明得排序,我个人觉得是题目有问题,排序偏离了出题人的意图Collections.sort(list, newComparator<String>(){
publicintcompare(Strings1, Strings2) {
returns1.compareTo(s2);
                }
            });
        }
returnlist;
    }
privatevoidArrange(char[] arr, inti) {
if (i==arr.length) {
list.add(newString(arr));
        } else {
Set<Character>set=newHashSet<Character>();
for (intj=i; j<arr.length; ++j) {
if (!set.contains(arr[j])) {
set.add(arr[j]);
if (i!=j) {
swap(arr, i, j);
                    }
Arrange(arr, i+1);
if (i!=j) {
swap(arr, i, j);
                    }
                }
            }
        }
    }
privatevoidswap(char[] arr, inti, intj) {
chartemp=arr[i];
arr[i] =arr[j];
arr[j] =temp;
    }
}

image.gif

======================Talk is cheap, show me the code=========================

目录
相关文章
|
算法 C++ 索引
【算法】——全排列算法讲解
【算法】——全排列算法讲解
1273 0
|
NoSQL Java 关系型数据库
秒杀场景下如何保证数据一致性?就这个问题我给出了最详细的方案
本文主要讨论秒杀场景的解决方案。 什么是秒杀? 从字面意思理解,所谓秒杀,就是在极短时间内,大量的请求涌入,处理不当时容易出现服务崩溃或数据不一致等问题的高并发场景。 常见的秒杀场景有淘宝双十一、网约车司机抢单、12306抢票等等。
|
11月前
|
SQL 关系型数据库 MySQL
MySQL锁机制:并发控制与事务隔离
本文深入解析了MySQL的锁机制与事务隔离级别,涵盖锁类型、兼容性、死锁处理及性能优化策略,助你掌握高并发场景下的数据库并发控制核心技巧。
|
网络协议 算法 安全
TCP协议(三次握手、流量控制、拥塞控制)
TCP协议是一种可靠的传输层通信协议,通过三次握手建立连接,确保数据安全传输。流量控制通过接收窗口避免接收方缓冲区溢出,拥塞控制则利用拥塞窗口调节网络传输速度,防止网络拥堵。三者协同工作,保障TCP在复杂网络环境中实现高效、可靠的数据传输。
3838 11
|
前端开发 Java 容器
Java一分钟之-JavaFX控件:Button, TextField, Label等
JavaFX教程概述了构建UI的基本控件:Button用于用户操作,TextField提供文本输入,Label显示静态文本。文章讨论了样式、事件处理和布局管理常见问题及其解决方案,并提供了一个使用这些控件创建简单应用的代码示例,强调实践中提升GUI开发技能的重要性。
692 1
|
JavaScript 前端开发 API
管理数据必备;侦听器watch用法详解,vue2与vue3中watch的变化与差异
一篇文章同时搞定Vue2和Vue3的侦听器,是不是很棒?不要忘了Vue3中多了一个可选项watchEffect噢。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
|
网络协议 算法 Linux
TCP是如何进行拥塞控制的?
TCP是如何进行拥塞控制的?
1462 1
|
Java 数据处理 API
Java 函数式编程:概念、优势与实战示例
【4月更文挑战第27天】函数式编程(Functional Programming,简称 FP)是一种编程范式,它将计算视为数学函数的求值并避免使用程序状态以及可变数据。
531 1