算法提高之LeetCode刷题C++

60.Permutation Sequence-Leetcode

2018-01-15  本文已影响2人  analanxingde

基础回顾

String

头文件中必须包括<string>

string的声明初始化

    string s1 = "abcdefg";  //初始化方式1  
    string s2("abcdefg");   //初始化方式2  
    string s3 = s2;         //通过拷贝构造函数 初始化s3  
    string s4(7,'s');       //初始化7个s的字符串  

遍历

1.str[i]
2.迭代器: 
    for(string::iterator it = s1.begin(); it!= s1.end(); it++)  
    {  
        cout << *it << " ";  
    }
3.str.at[i]//此方式可以在越界时抛出异常

string与char*

//字符指针和字符串的转换  
void strConvert()  
{  
    cout << "字符指针和字符串的转换:"  <<endl;  
    string s1 = "abcdefg";  //初始化字符串  
  
    cout << "string转换为char*:"  <<endl;  
    //string转换为char*  
    cout << s1.c_str() <<endl;  //s1.c_str()即为s1的char *形式  
  
    cout << "char*获取string内容:"  <<endl;  
    //char*获取string内容  
    char buf[64] = {0};  
    s1.copy(buf, 7);//复制7个元素  
    cout << buf <<endl;  
} 

字符串连接

s1.append(s2);
s1+=s2;

string与int转化(注意stringstream)

//int与char*
char* n=a+'0'
itoa(num, str, 10); //stdlib.h中的函数
//int to string,其余类型之间转换也可参考类似的方法stringstream可以stringstream可以吞下任何类型,根据实际需要吐出不同的类型。
stringstream stream;//<sstream>
stream<<n;
stream.str();//stream>>str;
//string to int
n = atoi(str.c_str())

我的算法(受nextPermutation影响大,算法效率低)

nextPermutation算法思想:

https://www.nayuki.io/page/next-lexicographical-permutation-algorithm

#右数第一个非降序序列的前一个元素下标pivot
#右数第一个大于s[pivot]的值的下标设为successor
#交换successor与pivot对应的元素
#将pivot右边的所有元素逆序
class Solution {
    //初始化s,后根据k进行循环限制,每次都取下一个排列数(根据NextPermutation的算法):效率很低
public:
    string getPermutation(int n, int k) {
        int i,j=0;
        for(i=1;i<=n;i++)
        {
            j=j*10+i;
        }
        n=j;
        stringstream ss;
        string begin;
        ss<<n;
        begin=ss.str();
        if(n==1 ||k==1)
        {
            return begin;
        }
        
        for(i=2;i<=k;i++)
        {
            begin=NextPermutation(begin);
        }
        
        return begin;
    }
     string NextPermutation(string s){
         int len=s.length();
         int i=len-1;
         while(s[i]<=s[i-1] && i-1>=0)
         {
             i-=1;
         }
         int pivot=i-1;     #右数第一个非降序序列的前一个元素下标pivot
         int successor;
         for(i=len-1;i>pivot;i--)
         {
             if(s[i]>s[pivot])
             {
                 successor=i;
                 break;    #右数第一个大于s[pivot]的值的下标
             }
         }
         char middle=s[successor];
         s[successor]=s[pivot];
         s[pivot]=middle;  #交换successor与pivot对应的元素
         int j;
         for (i=pivot+1,j=len-1;i<j;i++,j--)
         {                        #将pivot右边的所有元素逆序
            middle=s[i];
            s[i]=s[j];
            s[j]=middle;
         }

        return s;
     }
};

最优解法

http://blog.csdn.net/cinderella_niu/article/details/42927119
主要思想是按阶乘表示可能的组合种类:
1,2,3,… , n构建的全排列中,返回第k个排列。
题目告诉我们:对于n个数可以有n!种排列;那么n-1个数就有(n-1)!种排列。
那么对于n位数来说,如果除去最高位不看,后面的n-1位就有 (n-1)!种排列。
所以,还是对于n位数来说,每一个不同的最高位数,后面可以拼接(n-1)!种排列。
所以你就可以看成是按照每组(n-1)!个这样分组。
利用 k/(n-1)! 可以取得最高位在数列中的index。这样第k个排列的最高位就能从数列中的index位取得,此时还要把这个数从数列中删除。
然后,新的k就可以有k%(n-1)!获得。循环n次即可。

class Solution {
public:
    string getPermutation(int n, int k) {
        string ret;
        vector<int> factorial(n,1);     #计算阶乘
        vector<char> num(n,1);
        
        for(int i=1; i<n; i++) 
            factorial[i] = factorial[i-1]*i;
        
        for(int i=0; i<n; i++)
            num[i] = (i+1)+'0';
        
        k--;
        for(int i=n; i>=1; i--) {
            int j = k/factorial[i-1];
            k %= factorial[i-1];
            ret.push_back(num[j]);
            num.erase(num.begin()+j); //删除第j个元素,同时调整元素排序关系
        }
        
        return ret;
    }
};
上一篇下一篇

猜你喜欢

热点阅读