《剑指offer》(二十七)--字符串的排序(java)

考点:字符串、动态规划、递归、(分解让复杂问题简单)

题目描述

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

输入描述:

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

代码格式

import java.util.ArrayList;
public class Solution {
    public ArrayList<String> Permutation(String str) {
       
    }
}

本题属于全排列的生成算法,定义: 对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。全排列的生成法通常有以下几种:字典序法、递增进位数制法、递减进位数制法、邻位交换法、n进位制法、递归类算法。

解题一-非递归方法(字典序法)

字典序法:按照字典序求下一个排列的算法。
例:字典序法中,对于数字1、2、3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列 12354和12345,排列12345在前,排列12354在后。按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是 54321。当当前的排列54321最大的时候,说明所有的排列都找完了。
于是可以有下面计算下一个排列的算法:
【例】 如何得到346987521的下一个
(1)从尾部往前找第一个P(i) < P(i+1)的位置
3 4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1
最终找到6是第一个变小的数字,记录下6的位置i
(2)从i位置往后找到最后一个大于6的数
3 4 6 -> 9 -> 8 -> 7 5 2 1
最终找到7的位置,记录位置为m
(3)交换位置i和m的值
3 4 7 9 8 6 5 2 1
(4)反转i位置后的所有数据
3 4 7 1 2 5 6 8 9
则 347125689 为 346987521 的下一个排列

1.思路
(1)从尾部往前找第一个正序对(array[i] < array[i+1],因为没有等号,所以可以完美去掉重复的排列)
(2)从i开始向右搜索,找到比array[i]大的字符中最小的那个,记为array[j]
(3)交换array[i]和array[j]
(4)反转i位置后的所有字符
2.代码

import java.util.*;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> result = new ArrayList<>();
        if(str==null || str.length()==0){
            return result;
        }
        //将字符串转为char数组来进行改变字符内容
        char[] array = str.toCharArray();
        //只需将char数组进行排序
        Arrays.sort(array);
        //把chars数组中元素强制转化为字符串类型,并放入result中
        result.add(String.valueOf(array));
        //定义长度
        int len = array.length;
        while(true){
            int i= len-1;
            int j;
            //for循环从尾部往前找第一个正序对
            /*for(int i = length-1;i>=1 && array[i-1]>=array[i]; i--);
            if(i == 0) return "finish";*/
            
            //(1)while循环从尾部往前(向左)找第一个正序对array[i-1]>=array[i]
            while(i>=1 && array[i-1]>=array[i]){
                i--;
            }
            if(i == 0)
                break;
            //(2)while循环从i开始向后(向右)搜索,找到比array[i-1]大的字符中最小的那个,记为array[j]
            j = i;
            while(j<len && array[j]>array[i-1]){
                j++;
            }
            //(3)交换array[i-1]和array[j-1]
            swap(array,i-1,j-1);
            //(4)反转i位置后的所有字符
            reverse(array,i);
 
            result.add(String.valueOf(array));
        }
 
        return result;
    }
    
    private void reverse(char[] chars,int k){
        if(chars==null || chars.length<=k)
            return;
        int len = chars.length;
        for(int i=0;i<(len-k)/2;i++){
            int m = k+i;
            int n = len-1-i;
            if(m<=n){
                swap(chars,m,n);
            }
        }
    }
    //不用方法,直接反转
    /*swap i,j
        for(int a=i+1, b=length-1; a<b;a++,b--){
            tmp = array[a];
            array[a] = array[b];
            array[b] = tmp;
        }
     */
    
   private void swap(char[] chars, int i, int j) {
        // TODO Auto-generated method stub
        if(i != j){
            char temp = chars[i];
            chars[i] = chars[j];
            chars[j] = temp;
        }
    }
}

解题二-递归方法

1.思路
固定第一个字符,递归取得首位后面的各种字符串组合;再将第一个字符与后面每一个字符交换,同样递归获得其字符串组合;每次递归都是到最后一位时结束,递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。


image.png

2.代码

import java.util.*;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> result = new ArrayList<>();
        if(str.length()==0 ||str == null){
            return result;
        }
        PermutationHelper(str.toCharArray(),0,result);
        Collections.sort(result);
        return result;
    }
    private void PermutationHelper(char[] chars,int i,ArrayList<String> result){
        //已经递归到了字符串最后一位,判断集合中有没有这个字符串,没有则加入
        if(i== chars.length-1){
            if(!result.contains(new String(chars))){
                result.add(new String(chars));
                return;
            }
        }else{
            //首次传进来的i为0,代表首位字符
            //依次处理i与i后面的每个字符(索引j)交换
            for(int j=i; j<chars.length; j++){
                swap(chars,i,j);//交换
                PermutationHelper(chars,i+1,result);//继续递归交换后的子串
                swap(chars,i,j);//还原
            }
        }
    }
    private void swap(char[] chars,int i,int j){
        if(i != j){
            char temp = chars[i];
            chars[i] = chars[j];
            chars[j] = temp;
        }
    }
}

解题三-基于回溯法

1.思路


image.png

2.代码

import java.util.List;
import java.util.Collections;
import java.util.ArrayList;
 
public class Solution {
    public static void main(String[] args) {
        Solution p = new Solution();
        System.out.println(p.Permutation("abc").toString());
    }
 
    public ArrayList<String> Permutation(String str) {
        List<String> res = new ArrayList<>();
        if (str != null && str.length() > 0) {
            PermutationHelper(str.toCharArray(), 0, res);
            Collections.sort(res);
        }
        return (ArrayList)res;
    }
 
    public void PermutationHelper(char[] cs, int i, List<String> list) {
        if (i == cs.length - 1) {
            String val = String.valueOf(cs);
            if (!list.contains(val))
                list.add(val);
        } else {
            for (int j = i; j < cs.length; j++) {
                swap(cs, i, j);
                PermutationHelper(cs, i+1, list);
                swap(cs, i, j);
            }
        }
    }
 
    public void swap(char[] cs, int i, int j) {
        char temp = cs[i];
        cs[i] = cs[j];
        cs[j] = temp;
    }
}

参考:https://www.cnblogs.com/liyao0312/p/11343944.html
https://blog.csdn.net/qq_43109561/article/details/89604895
https://blog.csdn.net/qq_42039996/article/details/84504574

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容

  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,340评论 0 2
  • 1)这本书为什么值得看: Python语言描述,如果学的Python用这本书学数据结构更合适 2016年出版,内容...
    孙怀阔阅读 12,465评论 0 15
  • 面试题3——数组中重复的数字 使用LinkedHashMap,有序存放。 面试题4——二维数组中的查找 首先选...
    做自己的Yang光阅读 471评论 0 0
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,231评论 0 4
  • 没有孤单就没有爱情,寂寞中找知己,无聊中找快乐。也许这是一句最易表达现实中的寂寞。我们多少人不是在寂寞的时...
    佳墨年华阅读 87评论 0 0