LeetCode Next Permutation

1.Next Permutation


        原文链接:点击这里进入


        基本内容:

    


        解题思想:


        所谓一个排列的下一个排列的意思就是 这一个排列与下一个排列之间没有其他的排列。这就要求这一个排列与下一个排列有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。可能理解起来比较难懂。
        对于数字序列:
        
        先看前面2排的话,可以看出来第二排是比第一排要大的,参考字符串比较大小的问题。那么第2个排列是不是第一个排列的下一个排列呢。很明显不是,第3个排列才是, 那么如何获取到下一个排列呢。步骤比较简单:假设数组大小为 n
        1.从后往前,找到第一个 A[i-1] < A[i]的。也就是第一个排列中的  6那个位置,可以看到A[i]到A[n-1]这些都是单调递减序列。
        2.从 A[n-1]到A[i]中找到一个比A[i-1]大的值(也就是说在A[n-1]到A[i]的值中找到比A[i-1]大的集合中的最小的一个值)
        3.交换 这两个值,并且把A[n-1]到A[i]排序,从小到大。

        更好的流程图:来源自: http://fisherlei.blogspot.com/2012/12/leetcode-next-permutation.html


        代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //Link:http://oj.leetcode.com/problems/next-permutation/  
  2. //265 / 265 test cases passed.  
  3. //Status: Accepted  
  4. //Runtime: 60 ms  
  5.   
  6. void nextPermutation(vector<int> &num) {  
  7.     int length = num.size() - 1;  
  8.     while( length > 0 ){  
  9.         if( num[ length - 1 ] < num[ length ] )  
  10.             break;  
  11.         length --;  
  12.     }  
  13.     if( length == 0 ){  
  14.         forint i = 0, j = num.size(); i < j; i++ ,j-- )  
  15.             swap( num[ i ], num[ j ] );  
  16.     }  
  17.   
  18.     int k = num.size() - 1;  
  19.     for( ; k >= length; k-- )  
  20.         if( num[ k ] > num[ length - 1 ] )  
  21.             break;  
  22.     swap( num[ k ], num[ length - 1 ] );  
  23.     sort( num.begin() + length , num.end() );  
  24. }  

        
        另外在C++的标准库中有“求一个数字序列的下一个排列”的函数next_permutation,可以实现下一个排列的功能。当然这种函数在A题的时候是可以用的,但是在面试的时候直接调用是不行的。

        代码:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void nextPermutation(vector<int> &num) {  
  2.       next_permutation( num.begin(), num.end() );  
  3.    }  

             对于这样的函数只能表示:爽就一个字了。。。
         源代码在此:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.  /** 
  2.   *  @brief  Permute range into the next @e dictionary ordering. 
  3.   *  @ingroup sorting_algorithms 
  4.   *  @param  __first  Start of range. 
  5.   *  @param  __last   End of range. 
  6.   *  @return  False if wrapped to first permutation, true otherwise. 
  7.   * 
  8.   *  Treats all permutations of the range as a set of @e dictionary sorted 
  9.   *  sequences.  Permutes the current sequence into the next one of this set. 
  10.   *  Returns true if there are more sequences to generate.  If the sequence 
  11.   *  is the largest of the set, the smallest is generated and false returned. 
  12.  */  
  13.  template<typename _BidirectionalIterator>  
  14.    bool  
  15.    next_permutation(_BidirectionalIterator __first,  
  16.          _BidirectionalIterator __last)  
  17.    {  
  18.      // concept requirements  
  19.      __glibcxx_function_requires(_BidirectionalIteratorConcept<  
  20.               _BidirectionalIterator>)  
  21.      __glibcxx_function_requires(_LessThanComparableConcept<  
  22.     typename iterator_traits<_BidirectionalIterator>::value_type>)  
  23.      __glibcxx_requires_valid_range(__first, __last);  
  24.   
  25.      if (__first == __last)  
  26. return false;  
  27.      _BidirectionalIterator __i = __first;  
  28.      ++__i;  
  29.      if (__i == __last)  
  30. return false;  
  31.      __i = __last;  
  32.      --__i;  
  33.   
  34.      for(;;)  
  35. {  
  36.   _BidirectionalIterator __ii = __i;  
  37.   --__i;  
  38.   if (*__i < *__ii)  
  39.     {  
  40.       _BidirectionalIterator __j = __last;  
  41.       while (!(*__i < *--__j))  
  42.     {}  
  43.       std::iter_swap(__i, __j);  
  44.       std::reverse(__ii, __last);  
  45.       return true;  
  46.     }  
  47.   if (__i == __first)  
  48.     {  
  49.       std::reverse(__first, __last);  
  50.       return false;  
  51.     }  
  52. }  
  53.    }  




        全排列:


        既然求出了一个排列的下一个排列,那么我们就可以了解下一个序列的全排列是怎么实现的。

        1.递归算法


        以 数组 [1,2,3]为栗子,如何生成它的全排列呢。在第一个位置上我们有3种选择,分别是1,2,3。当选中第1个位置后,第二个位置上我们有2个选择。当第一个位置选中1的时候,第二个位置我们可以选2,或者3.   当第一个位置选中2的时候,第二个位置我们可以选1,或者3.   当第一个位置选中3的时候,第二个位置我们可以选1,或者2.   同理第3个位置在前2个位置都确定的情况下只有一种选择了。所以它的全排列个数为n!个。如下图所示(图片太烂了)
        

        了解了全排序的生成方式我们可以很明显的看出来这个可以用递归来解(当第一个位置确定为1的时候,需要用到后面2个位置的全排列),So我们可以写出来代码:
 
       代码:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Swap( int & x, int & y ){  
  2.     int temp = x;  
  3.     x = y;  
  4.     y = temp;  
  5. }  
  6. void  AllPersutation( int A[ ], int position, int length ){  
  7.   
  8.     if( position == length - 1 ){  
  9.         static int num = 1;  
  10.         cout << "The " << num++ << " Persutation is :";  
  11.         forint i = 0; i < length; i++ )  
  12.             cout << A[ i ] << " ";  
  13.         cout << endl;  
  14.     }  
  15.     else{  
  16.         forint i = position; i < length; i++ ){  
  17.             Swap( A[ position ], A[ i ] );  
  18.             AllPersutation(A, position + 1, length );  
  19.             Swap( A[ position ], A[ i ] );  
  20.         }  
  21.     }  
  22. }  

        其中最后一个Swap是为了保证你调用了下一步AllPersuatation函数之后得到下一个全排列之后,能够让交换位置的元素还原。以便下一个交换正确完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值