zoukankan      html  css  js  c++  java
  • 剑指27.字符串的排列

    题目描述

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

    输入描述:

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

    思路

    求整个字符串的排列,可以看成两步。

    第一步:求所有可能出现在第一个位置的字符,即把第一个字符先与自身交换,再和后面所有的字符交换。每交换完一次相当于确定了一个字符。

    第二步:固定第一个字符,求后面所有字符的排列。   例如接着确定下一个字符即第二个字符,让它再与自身交换然后与它之后的字符逐一交换……典型的递归

    需要注意的地方:“输出按字典序排”—因此需要有排序操作;“可能由字符重复”—因此需要去重

    解法1

    import java.util.*;
    public class Solution {
        /*
         *  通过递归去查找每一个位置的字符可能出现的情况。
         *  比如要找index位置的字符,那么交换index以及index位置之后的那些字符即可。
         */
        public ArrayList<String> Permutation(String str) {
            ArrayList<String> res = new ArrayList<>();
            if (str.length() == 0 || str == null)
                return res;
            char[] strArray = str.toCharArray();  // 把字符串String转化为char类型的字符数组
            solve(strArray,0,res);
            res = new ArrayList<String>(new HashSet<String>(res)); // 去重操作
            Collections.sort(res);  // 字典排序 -> 等价于 res.sort(null);  null意思是升序
            return res;
        }
        private void solve(char[] strArray, int index, ArrayList<String> res) {
            int length = strArray.length;
            if (index == length - 1){ // 把当前确定的结果(char数组的形式)转化为字符串保存下来
                res.add(String.valueOf(strArray)); //  String.valueOf(strArray) 把字符数组转化为字符串
            }else{
                // 确定index位置的字符
                // i要从index位置开始,原因是当前index位置的字符可以是原始字符串所对应的字符
                for (int i = index; i < length; i++) {
                    swap(strArray,index,i);  // 交换index位置和index位置之后的字符
                    // 当前index位置的字符已经通过交换找到了,接着递归找下一个位置的字符
                    solve(strArray, index + 1, res);
                    // 消除当前层递归时交换字符的影响,不消除会造成原index位置的字符发生变化
                    // 即字符串输出后要将字符交换回来,变回原始的字符串,以便进行下一轮交换。
                    swap(strArray,index,i);
                }
            }
        }
        private void swap(char[] strArray, int a, int b){
            char temp = strArray[a];
            strArray[a] = strArray[b];
            strArray[b] = temp;
        }
    }

    解法2(在解法1的基础上,使用TreeSet)

    import java.util.*;
    public class Solution {
        public ArrayList<String> Permutation(String str) {
            ArrayList<String> res = new ArrayList<>();
            if (str.length() == 0 || str == null)
                return res;
            TreeSet<String> treelist = new TreeSet<>(); //TreeSet是一个有序的集合,它的作用是提供有序的Set集合。
            Solve(str.toCharArray(),0,treelist);
            for (String s : treelist)
                res.add(s);
            return res;
        }
        private void Solve(char[] strArray, int index, TreeSet<String> treelist) {
            int length = strArray.length;
            if (index == length - 1){
                treelist.add(String.valueOf(strArray));
            }else{
                for (int i = index; i < length; i++) {
                    swap(strArray,index,i);
                    Solve(strArray,index + 1,treelist);
                    swap(strArray,index,i);
                }
            }
        }
        private void swap(char[] strArray, int a, int b) {
            char temp = strArray[a];
            strArray[a] = strArray[b];
            strArray[b] = temp;
        }
    }

    拓展(字符串的全组合)

    首先对比一下全排列和全组合,给定一个字符串"abc",

    • 全组合形式:a,b,c,ab,ac,bc,abc
    • 全排列形式:abc,acb,bac,bca,cab,cba

     交换字符串中的两个字符时,虽然能得到两个不同的排列,但却是同一个组合。比如ab和ba是不同的排列,但只算一个组合。

     全组合思路:

     

    Java实现对 数字 进行全组合

    import java.util.ArrayList;
    public class test {
        public static void main(String[] args) {
            int[] A = {1,2,3,4};
            for (int i = 1; i <= A.length ; i++) {
                ArrayList<Integer> res = new ArrayList<>();
                getCombination(A, i, 0, res);
            }
        }
        private static void getCombination(int[] A, int m, int start, ArrayList<Integer> res) {
            if (m == 0){
                // m个元素已经找齐,则打印
                for (Integer i : res){
                    System.out.print(i + " ");
                }
                System.out.println();
                return;
            }
            if (start < A.length){
                res.add(A[start]);
                //使用A[start],从剩下的(n-start)-1个元素中找m - 1个元素求它的组合
                getCombination(A,m - 1, start + 1, res);
                //不使用A[start],从剩下(n-start)-1个元素中找m个元字符,求它的组合
                res.remove(res.size() - 1);//删掉本次添加的元素
                getCombination(A,m, start + 1, res);
            }
        }
    }
    View Code

    Java实现对 字符 进行全组合

    import java.util.ArrayList;
    public class test {
        public static void main(String [] args) {
            String str = "abc";
            ArrayList<String> res = new ArrayList<>();
            for (int i = 1; i <= str.length(); i++) {
                multiCombination(str.toCharArray(), i,0, res);
            }
        }
        private static void multiCombination(char[] strArray, int m, int start,ArrayList<String> res) {
            if (m == 0) {
                System.out.println(res);
                return;
            }
            if (start < strArray.length) {
                res.add(String.valueOf(strArray[start]));
                multiCombination(strArray, m - 1,start + 1, res); // 从剩余的n-1个中选择m-1个
                res.remove(res.size() - 1);
                multiCombination(strArray, m,start + 1, res);  // 从剩余的n-1个中选择m个
            }
        }
    }
    View Code

    举一反三

    如果题目是按照一定要求摆放若干个数字,则可以先求出这些数字的所有排列,然后一一判断每个排列是不是满足题意。

    总结

    去重操作:可以用HashMap()去重,也可以使用 list.contains() 方法判断是否有重复字符串,如果没有重复,再进行 list.add操作。

    排序操作:Collections.sort(list)可以将list中的字符串进行排序。

    字符串和字符数组的相互转化:str.toCharArray()     String.valueOf(strArray)

    字符在递归过程中进行了交换后,要记得交换回来。

    参考:

    【Java】 剑指offer(38) 字符串的排列

  • 相关阅读:
    Pygal之掷骰子
    pygal之掷骰子 2颗面数为6的骰子
    matplotlib之scatter
    使用Flash Builder 4 beta和FlexUnit进行Test Driven Development
    FlexUnit单元测试(第二章FlexUnit基本应用)
    FlexUnit单元测试(第三章FlexUnit事件断言)
    [Flex]Flex SDK 4(Gumbo)更方便的自定义样式、自定义SparkSkin(二)
    Flex开源项目
    Flex 4 : Chart 控件
    Flex SDK 4(Gumbo)更方便的自定义样式、自定义SparkSkin(三)
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/13510648.html
Copyright © 2011-2022 走看看