剑指offer:字符串的排列

http://blog.csdn.net/libing13820393394/article/details/45072029?ref=myread

 

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

 

要考虑全排列的非递归实现,先来考虑如何计算字符串的下一个排列。如"1234"的下一个排列就是"1243"。只要对字符串反复求出下一个排列,全排列的也就迎刃而解了。
如何计算字符串的下一个排列了?来考虑"926520"这个字符串,我们从后向前找第一双相邻的递增数字,"20"、"52"都是非递增的,"26 "即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到"956220",然后再将替换点后的字符串"6220"颠倒即得到"950226"。
对于像“4321”这种已经是最“大”的排列,采用STL中的处理方法,将字符串整个颠倒得到最“小”的排列"1234"并返回false。

 

 public ArrayList<String> Permutation(String str) {
    java.util.ArrayList<String> list = new java.util.ArrayList<String>();
        if(str==null||str.length()==0){
            return list;
        }
        //先把初始字符串加进去
        list.add(str);
        
        //对全部字符排序
        char[] data = str.toCharArray();
        Arrays.sort(data);
        
        //存在后续字符串则符合条件
        while (hasNext(data))
        {
            //获取后续字符串
            next(data);
            
            //打印
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.length; i++) {  
                sb.append(data[i]);
            }  
            list.add(sb.toString());
        }
        return list;
    }
    
    public boolean hasNext(char[] data)
    {
        for(int i=data.length-1;i>0;i--)
            if(data[i]>data[i-1])
                return true;
        return false;
    }
    
    public void next(char[] data)
    {
        
        int top=0;
        int mm=0;
        
        //1.找到峰值
        for ( int i=data.length-1;i>0;i--)if(data[i] > data[i-1]){top = i;break;}
        //2.1找到交换的数,大于峰值前一个数的 最小的数
        mm = top-1;
        int max=top;
        for ( int i=top+1;i<data.length;i++) 
            if(data[i]<data[max]&&data[i]>data[mm]){
                max = i;
            }
        
        //2.2交换
        char tmp = data[mm]; 
        data[mm] = data[max]; 
        data[max] = tmp;
        
        //3颠倒后面的数 
        int end = data.length-1;
        int middle=(top+end)/2;
        while(top<=middle){
                tmp = data[top]; 
                data[top] = data[end];
                data[end] = tmp;
                top++;
                end--;
        }
    }

 

递归

  1. 把字符串分成两部分,一部分是第一个字符,另一个部分是后面其余的字符串
  2. 拿第一个字符和后面的字符串依次交换,这是一个递归的过程
  3. 注意:在递归里第一次交换是自身和自身的交换,保证不缺少字符串
public ArrayList<String> Permutation(String str) {
        ArrayList<String> list = new ArrayList<String>();
        if (str == null || str.length() == 0) {
            return list;
        }
        char[] strArr = str.toCharArray();
        permu(list, strArr, 0);
        Collections.sort(list);
        return list;
    }
public void permu(ArrayList<String> list, char[] strArr, int start) {
    if (start == strArr.length - 1) {
        String result = String.valueOf(strArr);
        if (list.indexOf(result) < 0) {
            list.add(String.valueOf(strArr));
        }
    }
    for (int i = start; i < strArr.length; i++) {
        char temp = strArr[i];
        strArr[i] = strArr[start];
        strArr[start] = temp;
        permu(list, strArr, start + 1);
        temp = strArr[i];
        strArr[i] = strArr[start];
        strArr[start] = temp;
    }
    return;
}

 

posted on 2017-08-28 16:30  zhangxiaoyu  阅读(196)  评论(0)    收藏  举报

导航