全排列 字典序排列

智商是个好东西,自己写了一下午没写出来,最后还得靠剑指offer书上的思路

上剑指

这里写图片描述
这里写图片描述

根据以上的思路写出的代码

#include<iostream>  
using namespace std;  

int counter=0;

void permutation(char * str,char *begin)
{
        if(*begin == '\0')
        {
                cout<<counter<<":"<<str<<endl;
                counter++;
        }
        else
        {
                for(char *p = begin;*p!='\0';p++)
                {
                        if(p!=begin && *p == *begin)
                                continue;   //去掉重复的 比如 aa 和 aa

                        char tmp=*p;
                        *p = *begin;
                        *begin = tmp;

                        permutation(str,begin+1);

                        /*原书上的代码 我去掉好像也没事 可能我没有遇到某些特殊情况吧*/
                        tmp = *p;
                        *p = *begin;
                        *begin = tmp;
                        /****************************/
                }
        }
}


int main()
{   
    char str[] ={'a','b','c','\0'};  

    permutation(str,str);  
    return 0;  
}  

字典排序

 一般而言,设P是[1,n]的一个全排列。
 P=P1P2…Pn=P1P2…Pj-1PjPj+1…Pk-1PkPk+1…Pn
find:  j=max{i|Pi<Pi+1}
    k=max{i|Pi>Pj}
1,  对换Pj,Pk,
2,  将Pj+1…Pk-1PjPk+1…Pn翻转
       P’= P1P2…Pj-1PkPn…Pk+1PjPk-1…Pj+1即P的下一个


 如何得到346987521的下一个
    1,从尾部往前找第一个P(i-1) < P(i)的位置
            3 4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1
        最终找到6是第一个变小的数字,记录下6的位置i-1
    2,从i位置往后找到最后一个大于6的数
            3 4 6 -> 9 -> 8 -> 7 5 2 1
        最终找到7的位置,记录位置为m
    3,交换位置i-1和m的值
            3 4 7 9 8 6 5 2 1
    4,倒序i位置后的所有数据
            3 4 7 1 2 5 6 8 9347125689346987521的下一个排列

写出代码  由于太懒  翻转部分直接冒泡重排了
void setmin(char *str,int length,const int protect)
{
        int i=0,j=0;
        //冒泡献丑
        for(i=protect;i<length;i++)
                for(j=i;j<length;j++)
                {
                        if(str[i]>str[j])
                        {
                                char tmp = str[i];
                                str[i] = str[j];
                                str[j] = tmp;
                        }
                }
}

int setnext(char *str,int length)
{
        for(int i=length-1;i>0;i--)
        {
                if(str[i]>str[i-1])
                {
                        for(int j=length-1;j>=i;j--)
                        {
                                if(str[j]>str[i-1])
                                {
                                char tmp = str[j];
                                str[j]=str[i-1];
                                str[i-1] = tmp;
                                setmin(str,length,i);
                                return 1;
                                }
                        }
                        return 0;
                }
        }
        return 0;
}

int main()
{   
    char str[] ={'b','a','c','d','\0'};  

    setmin(str,4,0);

        printf("%s\n",str);
        while(setnext(str,4))
                printf("%s\n",str);
    return 0;  
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值