Chinaunix首页 | 论坛 | 博客
  • 博客访问: 612697
  • 博文数量: 79
  • 博客积分: 848
  • 博客等级: 军士长
  • 技术积分: 1800
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-26 19:30
文章分类

全部博文(79)

文章存档

2015年(4)

2013年(39)

2012年(36)

分类: C/C++

2013-09-28 21:49:36

常见的全排列问题,是可以用递归去解决的,但是递归是很难保证输出的结果的大小顺序的,当然我们可以保存所有的结果,然后对于结果进行排序,这样无疑增加了时间上的复杂度,那么我们如何解决这个问题呢?
其实,这个问题我们可以用另外一个经典的套路来解决:
给定一个数X,他的兄弟数Y定义为:是由X中的数字组合而成,并且Y是大于X的数中最小的。例如,38276的兄弟数字为38627。给定X,求Y。

分析
当开始想到这个题目的时候就想到和求排列很像,想借用排列的方法,但是发现用这个方法不知道在哪里停止,无法降低O(n^2)的复杂度。

那 有没有更好的方法呢?不想对所有情况进行穷举,就要想办法,尽可能缩小要处理的范围,一般的思路,从右边开始,两两交换,查看是否可以找到Y,最开始考虑 两位,进而考虑三位,依次类推,那么如何确定,要考虑多少位呢?假设X的形式如下:x1x2x3...xky1y2y3y4,并且其中 y1>y2>y3>y4,xk

下面以一个具体例子来说明上述过程:

3 4 7 2 2 6 4 1

首先找到,从右边开始的递增的、尽可能长的数位,这里是641。

3 4 7 2 2 (6 4 1)

则,选取前一位数字2,进行交换。641中,大于2的最小的值是4,则作如下交换:

3 4 7 2 4 (6 2 1)

为了得到最小值,对621,从小到大进行排序,得到

3 4 7 2 4 (1 2 6)

则,Y为34724126.

所以,然后我们利用上面讲到的方法,来找到一个最小序列的所有的兄弟数字,就可以求得这个序列的全排列。

点击(此处)折叠或打开

  1. #include<iostream>
  2. #include<string>
  3. #include<algorithm>
  4. using namespace std;

  5. bool getBrother(string &dest)
  6. {
  7.     if(dest.size() <= 1)
  8.         return false;
  9.     int before = dest.size() - 2;
  10.     int after = dest.size() - 1;
  11.     if(dest[after] > dest[before])
  12.     {
  13.         swap(dest[after], dest[before]);
  14.         return true;
  15.     }
  16.     char min = '9';
  17.     int pos;
  18.     while((--before) >= 0)
  19.     {
  20.         pos = 0;//每次循环记得要把pos复位
  21.         for(int i = after; i > before; i--)
  22.         {
  23.             if(dest[i] > dest[before] && dest[i] < min)
  24.             {
  25.                 min = dest[i];
  26.                 pos = i;
  27.             }
  28.         }
  29.         if(pos > before)
  30.         {
  31.             swap(dest[pos], dest[before]);
  32.             sort(&dest[before + 1], &dest[after + 1]);//从开始元素到待排序元素的下一个位置
  33.             return true;
  34.         }
  35.     }
  36.     return false;
  37. }

  38. void allRank(string &dest)
  39. {
  40.     if(dest.size() <= 1)
  41.         return;
  42.     sort(&dest[0], &dest[dest.size()]);
  43.     do{
  44.         cout << dest << endl;
  45.     }while(getBrother(dest));
  46. }

  47. int main()
  48. {
  49.     string s("12543");
  50.     allRank(s);
  51.     return 0;
  52. }


阅读(2881) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

CU博客助理2013-10-10 11:39:37

嘉宾点评:博主风箫夜吟在算法上很有想法,通过逆序逐步处理给定数的兄弟数来实现能够按照大小顺序输入的数字序列的全排序,代码精炼,较纯粹的递归方式节省了不少时间。如果博主能够将算法的复杂度和时间节省程度进行量化并给出对比结果,将是更上一层楼。(感谢您参与“原创博文评选”获奖结果即将公布)