【算法练习】字符串处理 百练poj 1496:Word Index

本文探讨了如何对特定类型的五字母及以下的英文单词进行编码,并将其转化为整数。文章通过实例解释了有效单词的定义,即字母在字母表中严格递增的单词,并介绍了如何为有效单词分配其在字母表顺序中的位置。同时,提供了两种解题思路,一种是暴力枚举存储,另一种是利用组合数学计算方法。文章提供了样例输入和输出,以及AC代码示例。
摘要由CSDN通过智能技术生成

1496:Word Index

题目链接:http://bailian.openjudge.cn/practice/1496

总时间限制: 

1000ms

 

内存限制: 

65536kB

描述

Encoding schemes are often used in situations requiring encryption or information storage/transmission economy. Here, we develop a simple encoding scheme that encodes particular types of words with five or fewer (lower case) letters as integers. 

Consider the English alphabet {a,b,c,...,z}. Using this alphabet, a set of valid words are to be formed that are in a strict lexicographic order. In this set of valid words, the successive letters of a word are in a strictly ascending order; that is, later letters in a valid word are always after previous letters with respect to their positions in the alphabet list {a,b,c,...,z}. For example, 

abc aep gwz 

are all valid three-letter words, whereas 

aab are cat 

are not. 

For each valid word associate an integer which gives the position of the word in the alphabetized list of words. That is: 

    a -> 1
    b -> 2
    .
    .
    z -> 26
    ab -> 27
    ac -> 28
    .
    .
    az -> 51
    bc -> 52
    .
    .
    vwxyz -> 83681


Your program is to read a series of input lines. Each input line will have a single word on it, that will be from one to five letters long. For each word read, if the word is invalid give the number 0. If the word read is valid, give the word's position index in the above alphabetical list. 

输入

The input consists of a series of single words, one per line. The words are at least one letter long and no more that five letters. Only the lower case alphabetic {a,b,...,z} characters will be used as input. The first letter of a word will appear as the first character on an input line. 

The input will be terminated by end-of-file.

输出

The output is a single integer, greater than or equal to zero (0) and less than or equal 83681. The first digit of an output value should be the first character on a line. There is one line of output for each input line.

样例输入

z
a
cat
vwxyz

样例输出

26
1
0
83681

题目理解:

输出某个字符串str在字典中的位置,若不是字典中的字符则输出0。 
单词中每个字母严格递增

解题思路:

方法一:我的思路就是把字符串全部map映射起来,从一位数、两位数、三位数这样枚举存到字典里,然后再去查字典。。

应该就是暴力?找不到就输出0,找到了就输出对应的。。于是就AC了。

看AC代码1

 

但是感觉比较正常或者说通用的解法应该是方法二

参考blog:https://blog.csdn.net/lyy289065406/article/details/6648492

就是组合数学的方法

方法二思路:①判断输入的str是否是升序序列

②计算出比str长度少的所有字符串个数

③计算长度等于str,但值比str 小的字符串个数

组合数C_{n}^{m}用数组c[n][m]表示

考虑一位数、两位数  字符串的个数 ,根据下面的公式和推理,我们可以

得到规律:

或者直接可以直接这样想。。 长度为n的字符串要满足升序排列, 只需要在26个字母中选出n个字符就可以了 因为升序排列只有一种。直接就C[26][n] 了

长度为1的字符串个数为c[26][1]个
长度为2的字符串个数为c[26][2]个
长度为3的字符串个数为c[26][3]个
长度为4的字符串个数为c[26][4]个

所以我们可以计算出比str长度少的所有字符串个数,

 

AC代码1:

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;

map<string,int> dic;
int main(){
    int i=1;
    char c='a';
    for(;i<=26;i++){
        string str="";
        str+=c;
        dic[str]=i;
        c++;
    }
    //两位的情况
    for(int j='a';j<='z';j++){
        for(int k=j+1;k<='z' && j!=k;k++){
            string str="";
            str+=(char)j;
            str+=(char)k;
            dic[str]=i++;
        }
    }

    //三位数的情况
    for(int j='a';j<='z';j++){
        for(int k=j+1;k<='z' && j!=k;k++){
            for(int m=k+1;m<='z' && m!=k && m!=j ;m++){
                string str="";
                str+=(char)j;
                str+=(char)k;
                str+=(char)m;
                dic[str]=i++;
            }
        }
    }

    //四位数
    for(int j='a';j<='z';j++){
        for(int k=j+1;k<='z' && j!=k;k++){
            for(int m=k+1;m<='z' && m!=k && m!=j ;m++){
                for(int n=m+1;n<='z' && n!=j && n!=k && n!=m ;n++){
                    string str="";
                    str+=(char)j;
                    str+=(char)k;
                    str+=(char)m;
                    str+=(char)n;
                    dic[str]=i++;
                }
            }
        }
    }

    for(int j='a';j<='z';j++){
        for(int k=j+1;k<='z' && j!=k;k++){
            for(int m=k+1;m<='z' && m!=k && m!=j ;m++){
                for(int n=m+1;n<='z' && n!=j && n!=m && n!=k ;n++){
                    for(int q=n+1;q<='z' && q!=j && q!=k && q!=m && q!=n;q++){
                        string str="";
                        str+=(char)j;
                        str+=(char)k;
                        str+=(char)m;
                        str+=(char)n;
                        str+=(char)q;
                        dic[str]=i++;
                    }
                }
            }
        }
    }

    string ss;
    while(cin>>ss){
        map<string,int>::iterator it=dic.find(ss);
        if(it!=dic.end()){
            cout<<it->second<<endl;
        }
        else{
            cout<<0<<endl;
        }
    }




    return 0;
}

 

方法二 AC代码二:

//wordIndex的
#include <iostream>
#include <string.h>
using namespace std;

int C[50][50];   //组合数
void  initTable(){
    //c n m= c n-1 m-1 + c n-1 m
    for(int i=0;i<=26;i++){
        for(int j=0;j<=i;j++){
            if(j==0 || i==j )
                C[i][j]=1;
            else
                C[i][j]=C[i-1][j-1]+C[i-1][j];
        }
    }
    C[0][0]=0;
}

int main(){
    initTable();
    char str[50];

    while(cin>>str){
        int sum=0;
        int len=strlen(str);
        //判断是否升序
        bool flag=false;
        for(int i=1;i<len;i++){
            if(str[i]<str[i-1])
            {
                cout<<0<<endl;
                flag=true;
                break;
            }
        }
        if(flag){
            continue;
        }
        //计算长度小于len的字符串的个数
        for(int i=1;i<len;i++)
            sum+=C[26][i];     //长度为i的字符串的个数  就是C[26][i] 长度为n的字符串要满足升序排列只需要在26个字母中选出i个字符就可以

        //计算长度等于len,但值比str小的字符串个数
        for(int i=0;i<len;i++){
            char c=(i==0)?'a':str[i-1]+1;  //枚举到这里 就证明i位之前小于的所有字符串已经枚举完毕
            while(c<str[i]){   //枚举到的这个字符小于当前位对应的字符 那么枚举所有的以这个字符开头的字符串 直到相等之后再枚举下一位
                sum+=C['z'-c][len-1-i];   //从剩下的可以枚举的字符数 中 选出 n( len-1-i)个  一开始写反了
                c++;
            }

        }
        cout<<sum+1<<endl;
    }

    return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值