27 剑指offer--字符串--字符串的排列

                                           字符串排列

题目

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

思路

我们求整个字符串的排列,可以看成两步:首先求所有可能出现在第一个位置的字符,即把第一个字符和后面所有的字符交换。如下图所示:

上图就是分别把第一个字符a和后面的b、c等字符交换的情形。首先固定第一个字符,求后面所有字符的排列。这个时候我们仍把后面的所有字符分为两部分:后面的字符的第一个字符,以及这个字符之后的所有字符。然后把第一个字符逐一和它后面的字符交换。

这道题和全排列不一样的地方是全排列1是没有重复全排列,全排列2是有重复但是不要全排列。这道题是没有说,默认是全排列1可以做。

代码一   剑指offer从第一个往后递推

public class Test4 {
    public static void main(String[] args) {
        permutation("abca".toCharArray());
    }

    public static void permutation(char[] chars) {
        // 输入较验
        if (chars == null || chars.length < 1) {
            return;
        }
        // 进行排列操作
        permutation(chars, 0);
    }


    public static void permutation(char[] chars, int begin) {
        // 如果是最后一个元素了,就输出排列结果
        if (chars.length - 1 == begin) {
            System.out.print(new String(chars) + " ");
        } else {
            char tmp;
            // 对当前还未处理的字符串进行处理,每个字符都可以作为当前处理位置的元素
            for (int i = begin; i < chars.length; i++) {
                // 下面是交换元素的位置
                tmp = chars[begin];
                chars[begin] = chars[i];
                chars[i] = tmp;

                // 处理下一个位置
                permutation(chars, begin + 1);
            }
        }
    }

代码二 dfs

public class Test5 {
    public static void main(String[] args) {
        List<String> strings  = Permutation("abc");
        for(String str : strings){
            System.out.println(str);
        }
    }
    static ArrayList<String> returnList = new ArrayList<>();
    public static List<String> Permutation(String str) {
        if(str=="" || str.length() ==0){
            return returnList;
        }
        helper(str.toCharArray(),0);
        Collections.sort(returnList);
        return returnList;
    }
    public static void helper(char[] chars, int index) {
        if(index == chars.length-1){
            String val = String.valueOf(chars);
            if (!returnList.contains(val)) {
                //如果最后list没有这个string,因为可能交换后有重复的
                returnList.add(val);
            }
            return;
        }
        for(int i =index;i<chars.length;i++){
            swap(chars, index, i);
            helper(chars,index+1);
            swap(chars, index, i);
        }
    }
    public static void swap(char[] chars,int i, int j) {//交换数组中的两个位置中的值
        char temp =chars[i];
        chars[i] = chars[j];
        chars[j] = temp;

    }
}

代码三 全排列代码

public static void main(String[] args) {
    List<List<Character>> returnlist = permute("abc".toCharArray());
    for(int i =0;i<returnlist.size();i++){
        System.out.println(returnlist.get(i));
    }


}
static List<List<Character>> list = new ArrayList<>();

public static List<List<Character>> permute(char[] nums) {
    if (nums == null || nums.length == 0) {
        return list;
    }
    List<Character> list1 = new ArrayList<>();
    dpf(nums,list1);
    return list;
}
public static void dpf(char[] nums,List<Character> list1){
    if(list1.size() ==nums.length){
        list.add(new ArrayList<>(list1));
    }else {
        for(int i =0;i<nums.length;i++){
            //如果已经在数组里面了
            if(list1.contains(nums[i])){
                continue;
            }
            list1.add(nums[i]);
            dpf(nums,list1);
            list1.remove(list1.size()-1);
        }
    }
}

代码四 大神解读

/**

 * 题目:

 * 字符串的排列 -- newcoder 剑指Offer 27

 *

 * 题目描述:

 * 输入一个字符串,按字典序打印出该字符串中字符的所有排列。

 * 例如输入字符串abc,则打印出由字符a,b,c 所能排列出来的所有字符串

 * abc,acb,bac,bca,cab和cba。

 *

 * 输入描述:

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

 */

public class Permutation
{
    /**
     * 思路:
     * 
     * 对于无重复值的情况
     *
     * 固定第一个字符,递归取得首位后面的各种字符串组合;
     * 再把第一个字符与后面每一个字符交换,并同样递归获得首位后面的字符串组合; *递归的出口,就是只剩一个字符的时候,
     * 递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。
     *
     * 假如有重复值呢?
     * 由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换了。
     * 例如abb,第一个数与后面两个数交换得bab,bba。然后abb中第二个数和第三个数相同,就不用交换了。
     * 但是对bab,第二个数和第三个数不 同,则需要交换,得到bba。
     * 由于这里的bba和开始第一个数与第三个数交换的结果相同了,因此这个方法不行。
     *
     * 换种思维,对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数,
     * 所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!
     * 
     */
    public ArrayList<String> permutation(String str) {
        ArrayList<String> ret = new ArrayList<>();
        
        if (str == null || str.isEmpty()) {
            return ret;
        }
        
        char[] arr = str.toCharArray();
        
        permutation(arr, 0, ret);
        
        Collections.sort(ret);
        return ret;
    }
    
    private void permutation(char[] arr, int begin, ArrayList<String> cache) {
        if (begin == arr.length - 1) {
            cache.add(new String(arr));
            return;
        }
        
        int len = arr.length;
        for (int i=begin; i<len; i++) {
            // 与begin不同位置的元素相等,不需要交换
            if (i!=begin && arr[i]==arr[begin]) {
                continue;
            }
            // 交换元素
            swap(arr, begin, i);
            // 处理后续元素
            permutation(arr, begin+1, cache);
            // 数组复原
            swap(arr, begin, i);
            
        }
    }
    
    private void swap(char[] arr, int i, int j) {
        if (i == j) {
            return;
        }
        arr[i] = (char)(arr[i]^arr[j]);
        arr[j] = (char)(arr[i]^arr[j]);
        arr[i] = (char)(arr[i]^arr[j]);
    }

 

全部评论

相关推荐

02-14 07:38
已编辑
门头沟学院 Java
2.4&nbsp;一面2.6&nbsp;二面2.9&nbsp;三面(hr面)2.13&nbsp;oc1.15号收到面试电话那会就开始准备,因为一开始没底所以选择推迟一段时间面试,之后开始准备八股,准备实习可能会问的东西,这期间hot100过了有六七遍,真的是做吐了快,八股也是背了忘,忘了背,面经也看了很多,虽然最后用上的只有几道题,可是谁知道会问什么呢自从大二上开始学java以来,一路走来真的太痛了,一开始做外卖,点评,学微服务,大二下五六月时,开始投简历,哎,投了一千份了无音讯,开始怀疑自己(虽然能力确实很一般),后来去到一家小小厂,但是并不能学到什么东西,而且很多东西都很不规范,没待多久便离开,大二暑假基本上摆烂很怀疑自己,大三上因为某些原因开始继续学,期间也受到一俩个中小厂的offer,不过学校不知道为啥又不允许中小厂实习只允许大厂加上待遇不太好所以也没去,感觉自己后端能力很一般,于是便打算转战测开,学习了一些比较简单的测试理论(没有很深入的学),然后十二月又开始继续投,java和测开都投,不过好像并没有几个面试,有点打击不过并没有放弃心里还是想争一口气,一月初因为学校事比较多加上考试便有几天没有继续投,10号放假后便继续,想着放假应该很多人辞职可能机会大一点,直到接到字节的面试,心里挺激动的,总算有大厂面试了,虽然很开心,但同时压力也很大,心里真的很想很想很想进,一面前几天晚上都睡不好觉,基本上都是二三点睡六七点醒了,好在幸运终于眷顾我一次了(可能是之前太痛了),一面三十几分钟结束,问的都不太难,而且面试官人挺好但是有些问题问的很刁钻问到了测试的一些思想并不是理论,我不太了解这方面,但是也会给我讲一讲他的理解,但是面完很伤心觉得自己要挂了。但是幸运的是一面过了(感谢面试官),两天后二面,问的同样不算难,手撕也比较简单,但也有一两个没答出来,面试官人很好并没有追问,因为是周五进行的二面,没有立即出结果,等到周一才通知到过了,很煎熬的两天,根本睡不好,好在下周一终于通知二面过了(感谢面试官),然后约第二天三面,听别的字节同学说hr面基本上是谈薪资了,但是我的并不是,hr还问了业务相关的问题,不过问的比较浅,hr还问我好像比较紧张,而且hr明确说了还要比较一下,我说我有几家的面试都拒了就在等字节的面试(当然紧张,紧张到爆了要),三面完后就开始等结果,这几天干啥都没什么劲,等的好煎熬,终于13号下午接到了电话通知oc了,正式邮件也同时发了,接到以后真的不敢信,很激动但更重要的是可以松一口气了,可以安心的休息一下了终于可以带着个好消息过年了,找实习也可以稍微告一段落了,虽然本人很菜,但是感谢字节收留,成为忠诚的节孝子了因为问的比较简单,面经就挑几个记得的写一下一面:1.实习项目的难点说一下2.针对抖音评论设计一下测试用例3.手撕:合并两个有序数组二面:1.为什么转测开2.线程进程区别,什么场景适合用哪个3.发送一个朋友圈,从发出到别人看到,从数据流转的角度说一下会经历哪些过程4.针对抖音刷到广告视频设计测试用例5.手撕:无重复字符的最长字串
查看8道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务