感谢支持
我们一直在努力

百度面试题——需找下一个排列(Find next permuation, POJ 1883)

面试中关于排列的题目还是蛮常见的,之前有个同学面百度,就遇到了一个排列题目,分享一下。

题目描述:
给你一个数组,如果是按照数字的大小排序,那么请你输出当前数组的下一个排列是什么

例如, 下面的数据,就是按照排列序生成的四组数据。

3 1 2 4 5
3 1 2 5 4
3 1 4 2 5
3 1 4 5 2

虽然有个函数叫next_permutation, 不过做OJ还好,面试这个一定不行啦,所以还是自己分析一下。

分析:
我们用字典序的排列生成方法:

生成给定全排列的下一个排列

所谓一个的下一个就是这一个与

下一个之间没有其他的。这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。

 算法分三个步骤:

一般而言,设P是[1,n]的一个全排列。

1.  P=P1P2…Pn=P1P2…Pj-1PjPj+1…Pk-1PkPk+1…Pn

j=max{i|Pi<Pi+1},k=max{i|Pi>Pj}

2.  对换Pj,Pk,将Pj+1…Pk-1PjPk+1…Pn翻转,

3. P’= P1P2…Pj-1PkPn…Pk+1PjPk-1…Pj+1即P的下一个。

代码如下:

  1. Memory: 168K        Time: 469MS 
  2. Language: C++       Result: Accepted 
  3. Source Code 
  4. #include<stdio.h>  
  5. #include <memory.h>  
  6.  
  7. void swap( int &a, int &b) 
  8.     a = a ^ b; 
  9.     b = a ^ b; 
  10.     a = a ^ b; 
  11.  
  12.  
  13. bool GetNextPermutation(int a[], int size) 
  14.     int m = size – 1; 
  15.     int i,j; 
  16.     while(m > 0 && a[m-1] > a[m]) // step 1  
  17.     { 
  18.         m–; 
  19.     } 
  20.  
  21.     //in this case, the current permutation is the last  
  22.     if(m == 0) //  
  23.     { 
  24.         for( i = 0, j = size – 1; i < j; i++, j–) 
  25.         { 
  26.             swap(a[i], a[j]); 
  27.         } 
  28.         return false
  29.     } 
  30.  
  31.     for( j = size – 1; j > m – 1; j–)//step 2  
  32.     { 
  33.         if(a[j] > a[m-1]) 
  34.         { 
  35.             swap(a[j], a[m-1]); 
  36.             break
  37.         } 
  38.     } 
  39.  
  40.     for( i = m, j = size – 1; i < j; i++, j–)//step 3  
  41.     { 
  42.         swap(a[j], a[i]); 
  43.     } 
  44.     return true
  45.  
  46. void printArray(int a[], int size) 
  47.     int i; 
  48.  
  49.     for( i = 0; i < size; i++) 
  50.     {   
  51.         if( i == 0) 
  52.         { 
  53.             printf(“%d”, a[i]); 
  54.         } 
  55.         else 
  56.         { 
  57.             printf(” %d”, a[i]); 
  58.  
  59.         } 
  60.     } 
  61.     printf(“\n”); 
  62. int main() 
  63.     int nSize; 
  64.     int a[1024]; 
  65.     int ncase; 
  66.  
  67.     scanf(“%d”, &ncase); 
  68.     int n,k; 
  69.     while(ncase–) 
  70.     { 
  71.         scanf(“%d%d”, &n, &k); 
  72.  
  73.         forint i = 0; i < n; i++) 
  74.         { 
  75.             scanf(“%d”, &a[i]); 
  76.         } 
  77.  
  78.         while(k–) 
  79.         { 
  80.             GetNextPermutation(a, n); 
  81.              
  82.         } 
  83.         printArray(a, n); 
  84.      
  85.     } 
  86.     return 0; 

不过既然提到求出排练顺便再给出一个生成所有排列的方法。就是组合数学里面说的“交换法”

这个方法运行的流程如下: 

 

考虑{1,2…n}的一个排列,其上每一个整数都给了一个方向,我们称整数k是可移的(Mobile&Active),如果它的箭头所指的方向的邻点小于它本身。例如

 

635都是可移的。显然1永远不可移,n除了以下两种情形外,它都是可移的:

(1) n是第一个数,且其方向指向左侧

(2) n是最后一个数,且其方向指向右侧

 

于是,我们可由

按如下算法产生所有排列

算法

1开始时:


2,当存在可移数时

(a)找最大的可移数m
(b)m与其箭头所指的邻数互换位置
(c)将所得排列中比m大的数p的方向调整,即改为相反方向。
 
代码如下:

  1. #include <stdio.h>  
  2. #include <memory.h>  
  3.  
  4. enum Direction{LEFT, RIGHT}; //方向枚举  
  5.  
  6.  
  7. struct Num //每个数有一个方向和值  
  8.     Direction d; 
  9.     int value; 
  10. };   
  11.  
  12. Num permutation[100]; 
  13.  
  14. //if return value is -1, it means we can’t find the permutation anymore  
  15. int GetFirstMoveable(int nsize) //在所有数里面找到最大的可以移动的数,返回下标  
  16.     int maxValue = 0; 
  17.     int idx = -1; 
  18.     forint i = 0;i < nsize; i++) 
  19.     { 
  20.         if( i == 0 && permutation[i].d == LEFT)//最左边,并且移动方向是左  
  21.         { 
  22.             continue
  23.         } 
  24.         if( i == nsize – 1 && permutation[i].d == RIGHT)//最右边,并且移动方向向右  
  25.         { 
  26.             continue
  27.         }   
  28.         if(permutation[i].d == LEFT)//如果方向是左,并且比左侧元素大  
  29.         { 
  30.             if(permutation[i].value > permutation[i-1].value) 
  31.             { 
  32.                 if(maxValue < permutation[i].value) 
  33.                 { 
  34.                     maxValue = permutation[i].value; 
  35.                     idx = i; 
  36.                 } 
  37.             } 
  38.         } 
  39.         else   
  40.         { 
  41.             if(permutation[i].value > permutation[i+1].value)//方向向右,比右侧大  
  42.             { 
  43.                 if(maxValue < permutation[i].value) 
  44.                 { 
  45.                     maxValue = permutation[i].value; 
  46.                     idx = i; 
  47.                 } 
  48.             } 
  49.         } 
  50.     } 
  51.     return idx; 
  52.  
  53. void reverseDirection(int r, int nsize) //交换完了以后,将所有大于当前交换的值的 方向调反  
  54.     forint i = 0; i < nsize; i++) 
  55.     { 
  56.         if(permutation[i].value > permutation[r].value) 
  57.         { 
  58.             if(permutation[i].d == LEFT) 
  59.             { 
  60.                 permutation[i].d = RIGHT; 
  61.             } 
  62.             else 
  63.             { 
  64.                 permutation[i].d = LEFT; 
  65.             } 
  66.         } 
  67.     } 
  68.  
  69. void swap(Num & a, Num & b) 
  70.     Num t = a; 
  71.     a = b; 
  72.     b = t; 
  73. void swapValue(int r, int &nr)//交换相邻的值  
  74.  
  75.     if(permutation[r].d == LEFT) 
  76.     { 
  77.         swap(permutation[r], permutation[r-1]); 
  78.         nr = r – 1; 
  79.     } 
  80.     else 
  81.     { 
  82.         swap(permutation[r], permutation[r+1]); 
  83.         nr = r + 1; 
  84.     } 
  85.  
  86.  
  87. void printAll(int nsize) 
  88.     for(int i = 0; i < nsize; i++) 
  89.     { 
  90.         printf(“%d “, permutation[i].value ); 
  91.     } 
  92.     printf(“\n”); 
  93. int main() 
  94.     int n; 
  95.  
  96.     while(scanf(“%d”,&n) != EOF) 
  97.     { 
  98.         forint i = 0; i < n;i++) 
  99.         { 
  100.             permutation[i].value = i + 1; 
  101.             permutation[i].d = LEFT; 
  102.         } 
  103.         int r;   
  104.         int nr; 
  105.         printAll(n); 
  106.         while( (r = GetFirstMoveable(n)) != -1)//算法核心循环  
  107.         { 
  108.             swapValue(r, nr); 
  109.             reverseDirection(nr, n); 
  110.             printAll(n); 
  111.  
  112.  
  113.         } 
  114.     } 
  115.     return 0; 
赞(0) 打赏
转载请注明出处:服务器评测 » 百度面试题——需找下一个排列(Find next permuation, POJ 1883)
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏