【试题描述】输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab,cba。

分析:这是一道很好的考查对递归理解的编程题,因此在过去一年中频繁出现在各大公司的面试、笔试题中。

我们以三个字符abc为例来分析一下求字符串排列的过程。首先我们固定第一个字符a,求后面两个字符bc的排列。当两个字符bc的排列求好之后,我们把第一个字符a和后面的b交换,得到bac,接着我们固定第一个字符b,求后面两个字符ac的排列。现在是把c放到第一位置的时候了。记住前面我们已经把原先的第一个字符a和后面的b做了交换,为了保证这次c仍然是和原先处在第一位置的a交换,我们在拿c和第一个字符交换之前,先要把b和a交换回来。在交换b和a之后,再拿c和处在第一位置的a进行交换,得到cba。我们再次固定第一个字符c,求后面两个字符b、a的排列。

既然我们已经知道怎么求三个字符的排列,那么固定第一个字符之后求后面两个字符的排列,就是典型的递归思路了。

为方便起见,用123来示例下。123的全排列有123、132、213、231、312、321这六种。首先考虑213和321这二个数是如何得出的。显然这二个都是123中的1与后面两数交换得到的。然后可以将123的第二个数和每三个数交换得到132。同理可以根据213和321来得231和312。因此可以知道——全排列就是从第一个数字起每个数分别与它后面的数字交换。找到这个规律后,递归的代码就很容易写出来了:

对于一个n 位的字符串来讲,它是n-1位字符串的排列 加上 没有在 n -1 位字符串里 那个字符 的排列。 有点难理解,用例子说明:对于字符串ABC来讲,它所有的排列就是 A + BC 的排列 加上 B + AC 的排列,再加上 C + AB的排列。而BC的排列是 B + C 的排列 加上 C + B 的排列。所以,对一个字符串,我们从中去一个值,然后求剩余部分的排列,然后把它们再组合在一起。所有,代码如下

【参考代码】

如果字符串中有重复字符的话,这个方法肯定不会符合要求的

 1 public static void permutation(char[] arr, int begin)
 2     {
 3         // if pBegin points to the end of string,
 4         // this round of permutation is finished,
 5         // print the permuted string
 6
 7         if (begin == arr.length)
 8             System.out.println(Arrays.toString(arr));
 9         else
10         {
11             for (int i = begin; i < arr.length; i++)
12             {
13                 swap(arr, i, begin);
14                 permutation(arr, begin + 1);
15                 // restore pCh and pBegin
16                 // PS:改变字符串顺序后必须还原回来!
17                 swap(arr, i, begin);
18             }
19         }
20     }
21
22     public static void swap(char[] arr, int i, int j)
23     {
24         char temp = arr[i];
25         arr[i] = arr[j];
26         arr[j] = temp;
27     }

二、去掉重复的全排列的递归实现

由于全排列就是从第一个数字起每个数分别与它后面的数字交换。我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这二个数就不交换了。如122,第一个数与后面交换得212、221。然后122中第二数就不用与第三个数交换了,但对212,它第二个数与第三个数是不相同的,交换之后得到221。与由122中第一个数与第三个数交换所得的221重复了。所以这个方法不行。

换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。

 1 // 在[nBegin,nEnd)区间中是否有字符与下标为pEnd的字符相等
 2     static boolean isSwap(char[] arr ,int pBegin, int pEnd)
 3     {
 4         int p;
 5         for (p = pBegin; p < pEnd; p++)
 6         {
 7             if (arr[p] == arr[pEnd])
 8                 return false;
 9         }
10         return true;
11     }
12
13     public static void permutation2(char[] arr, int begin)
14     {
15         // if pBegin points to the end of string,
16         // this round of permutation is finished,
17         // print the permuted string
18         if (begin == arr.length)
19             System.out.println(Arrays.toString(arr));
20
21         else
22         {
23             for (int i = begin; i < arr.length; i++)
24             {
25                 if (isSwap(arr,begin, i))
26                 {
27                     swap(arr, begin, i);
28                     permutation(arr, begin + 1);
29                     // restore pCh and pBegin
30                     // PS:改变字符串顺序后必须还原回来!
31                      swap(arr, begin, i);
32                 }
33             }
34         }
35     }

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

这样,只要一个循环再加上计算字符串下一个排列的函数就可以轻松的实现非递归的全排列算法。按上面思路并参考STL中的实现源码,不难写成一份质量较高的代码。值得注意的是在循环前要对字符串排序下,可以自己写快速排序的代码

转:http://blog.csdn.net/zz198808/article/details/7657168

总结:
1、全排列就是从第一个数字起每个数分别与它后面的数字交换。
2、去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。
3、全排列的非递归就是由后向前找替换数和替换点,然后由后向前找第一个比替换数大的数与替换数交换,最后颠倒替换点后的所有数据。

字符串全排列扩展----八皇后问题
    题目:在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。

这就是有名的八皇后问题。解决这个问题通常需要用递归,而递归对编程能力的要求比较高。因此有不少面试官青睐这个题目,用来考察应聘者的分析复杂问题的能力以及编程的能力。

由于八个皇后的任意两个不能处在同一行,那么这肯定是每一个皇后占据一行。于是我们可以定义一个数组ColumnIndex[8],数组中第i个数字表示位于第i行的皇后的列号。先把ColumnIndex的八个数字分别用0-7初始化,接下来我们要做的事情就是对数组ColumnIndex做全排列。由于我们是用不同的数字初始化数组中的数字,因此任意两个皇后肯定不同列。我们只需要判断得到的每一个排列对应的八个皇后是不是在同一对角斜线上,也就是数组的两个下标i和j,是不是i-j==ColumnIndex[i]-Column[j]或者j-i==ColumnIndex[i]-ColumnIndex[j]。

转载于:https://www.cnblogs.com/WayneZeng/archive/2013/04/09/3011233.html

【IT笔试面试题整理】字符串的排列相关推荐

  1. 剑指offer:面试题38. 字符串的排列

    题目:面试题38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" 输 ...

  2. 网易历届笔试面试题整理大全

    整理了一下网易往届笔试面试题,希望对大家有帮助: 超级有用的面试题:Java常见面试题    常见算法面试题   数据库常见面试题  操作系统常见面试题   C/C++常见面试题  大数据常见面试   ...

  3. 【IT笔试面试题整理】字符串的组合

    [试题描述]输入一个字符串,输出该字符串中字符的所有组合.举个例子,如果输入abc,它的组合有a.b.c.ab.ac.bc.abc. 分析:这是一道很好的考查对递归理解的编程题,因此在过去一年中频繁出 ...

  4. 【IT笔试面试题整理】字符串转数组+数组转字符串

    [试题描述]定义一个函数,字符串转数组数组转字符串 [参考代码] 1 public static int strToInt(String str) 2 { 3 int i = 0, num = 0; ...

  5. 剑指Offer - 面试题38. 字符串的排列(全排列,排序,回溯+剪枝)

    1. 题目 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" 输出:["ab ...

  6. 剑指offer面试题38. 字符串的排列(回溯)

    题目描述 **输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素.** 思路 详见链接 代码 class Solution:def permut ...

  7. 【IT笔试面试题整理】不用加减乘除做加法

    [试题描述]写一个函数,求两个整数的和,要求在函数体内不得使用加减乘除四则运算符合. 基本思路是这样的: int A, B;A&B //看哪几位有进位A^B //不带进位加 考虑二进制加法的过 ...

  8. 【IT笔试面试题整理】给定二叉树先序中序,建立二叉树的递归算法

    [试题描述]:  给定二叉树先序中序,建立二叉树的递归算法 其先序序列的第一个元素为根节点,接下来即为其左子树先序遍历序列,紧跟着是右子树先序遍历序列,固根节点已可从先序序列中分离.在中序序列中找到 ...

  9. 【IT笔试面试题整理】连续子数组的最大和

    [试题描述]输入一个整型数组,数组里有正数也有负数.数组中一个或连续的多个整数组成一个子数组. 求所有子数组的和的最大值.要求时间复杂度O(n). 思路:当我们加上一个正数时,和会增加:当我们加上一个 ...

最新文章

  1. iOS 本地DNS解析方法
  2. AtCoder AGC001F Wide Swap (线段树、拓扑排序)
  3. hutool 自定义excel_Hutool Java 工具类库导出 Excel,超级简单!
  4. 洛谷P2622 关灯问题II【状压dp+bfs】
  5. c++ winpcap开发(2)
  6. BestCoder Round #77 (div.2)解题报告
  7. VS中的多线程(/MT)、多线程调试(/MTd)、多线程DLL(/MD)、多线程调试DLL(/MDd)的区别(转载)
  8. C语言嵌入式系统编程修炼之(四)屏幕操作
  9. ThinkPHP中使用聚合查询去重求和
  10. 作为前端程序员:你必须知道的常用英语词汇!!全是干货!!!
  11. 汇编语言基础知识(二)
  12. word文档中怎么输入公式符号
  13. steer clear of用法
  14. 虚拟网络之Kubernetes Cilium CNI 快速部署实操
  15. 图片如何转化为pdf格式?
  16. 计算机课程word教学,Word教学方法及使用技巧
  17. ccxprocess启动项可以禁用么_启动项禁用
  18. 毫米波技术入局智能家居,是大材小用还是技术革命?
  19. 2012蓝桥杯C++本科 取球游戏
  20. 乐鑫esp8266学习rtos3.0笔记第9篇:整理分享那些我在项目中常用的esp8266 rtos3.0版本的常见驱动,Button按键长短按、PWM平滑调光等。(附带demo)

热门文章

  1. 【JavaScript】【PPT】继承的本质
  2. 《软件工程》总结——第十一章
  3. UVA 11626 凸包(含共线)
  4. PyCharm的隐藏技巧(Tips)-快捷键等积累
  5. 嵌入式Linux下跑自整定pid,告诉过你PID很重要,你不听
  6. leetcode算法题--把数字翻译成字符串
  7. C语言编译、链接过程探究
  8. leetcode算法题--飞机座位分配概率
  9. 解密module_init幕后的故事
  10. VMware14黑屏问题