字符串计数-字典排序

来源:互联网 发布:新路由器有信号没网络 编辑:程序博客网 时间:2024/04/30 04:36

1、牛客网题目:

题目描述

求字典序在s1和s2之间的,长度在len1到len2的字符串的个数,结果mod 1000007。

输入描述:

每组数据包涵s1(长度小于100),s2(长度小于100),len1(小于100000),len2(大于len1,小于100000)

输出描述:

输出答案。
示例1

输入

ab ce 1 2

输出

56



2、code实现:已a

package schooloffer;import java.util.Scanner;/** * Created by caoxiaohong on 17/10/17. * 求字典序在s1和s2之间的,长度在len1到len2的字符串的个数,结果mod 1000007。 * 题目看了一天,总算是基本明白了 * 遇到的2个问题: * 1.本题的字典排序中,错误以为一个字符串中各个字符必须是不同的,以为ab..后面只能是c..z,但其实ab后面任意一位都可以是a..z * 2.Math.pow()函数使用时,没有强制专为long类型,导致算法写好后,一直结果不对,后来发现是结果类型没有被强制转换. */public class StringCounts {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        while (scanner.hasNext()) {            String[] strs = scanner.nextLine().split(" ");            char[] str1=strs[0].toCharArray();            char[] str2=strs[1].toCharArray();            int minLen=Integer.valueOf(strs[2]);            int maxLen=Integer.valueOf(strs[3]);            long res=0;            for(int i=minLen;i<=maxLen;i++){                char a=str1[0];                char b=str2[0];                /**                 * Math.pow(26,i-1)表示:长度为i的字符串,第一位是固定字符的情况下,后面i-1位,每一位均有26种情况,即为a~z;                 * (b-a)表示:字典排序中,从字符a到字符b有多少种情况                 * 求两个字符串分别以a和b开头,且长度均为i时,如果用n表示可以出现的所有的字典排序的情况数目,则理想情况下n为26的整数倍.                 * 比如:ab和bc两个字符串求长度为2的中间字串个数就是刚刚好26个:ac~az,ba~bb; ~理想情况                 * 但是,ab和ba两个字符串求长度为2的中间字符串个数就是24个:ac~az; ~理想情况-1                 * ab和bd两个字符串长度为2的中间字符串个数是27个:ac~bc;~理想情况+1                 */                res+=(long)Math.pow(26,i-1)*(b-a);                /**                 * 为什么会有两个for循环?                 * 第一个for循环作用:j从1开始,然后分别以str1[j]开头,长度为i-1-j的字符串有多少种字典排序~显然这是长度为i,j=0开始的字符串的子串                 *                 比如:对于字符串abcdd,i=4时.母串为abcd  &&  子串分别为bcd ; cd; d 这3种情况.                 * 第二个for循环作用:j从1开始,然后分别以str2[j]开头,长度为i-1-j的字符串有多少种字典排序.                 * 上面的Math.pow(26,i-1)*(b-a)求出了res可以增加到理想值.而这种赋值在某些情况下会出现多加或者少加的情况:                 *                 * 比如:                 * 例子1:字符串为ab和ba,显然从ac到ba之间的字符串个数=24,那么怎么把多出来的1减掉呢?这就到了两个for循环其作用的时候了.                 * 每次大循环中,两个小for循环都会进行减值:给出运行过程中关键变量的值:                 * i=1时,第一个小for循环中,程序运行过程中值变化过程:res=0;sum1=0;sum2=0;res=1;                 * i=2时,第二个小for循环中,程序运行过程中值变化过程:res==27;sum1=1;sum2=0;res=26;                 * 显然,第二个小for循环进行了-1操作.                 *                 * 例子2:字符串为ab和bc,显然ab到bc之间的字符串个数=27,那么怎么把少的1给加回来,这就到了两个for循环其作用的时候了.                 * 每次大循环中,两个小for循环都会进行减值:给出运行过程中关键变量的值:                 * i=1时,第一个小for循环中,程序运行过程中值变化过程:res=1;sum1=0;sum2=0;res=1;                 * i=2时,第二个小for循环中,程序运行过程中值变化过程:res=27;sum1=1;sum2=2;res=28;                 * 显然,第二个小for循环进行了+1操作.                 */                long sum1=0;                for(int j=1;j<str1.length;j++){                    sum1+=(long)Math.pow(26,i-1-j)*(str1[j]-'a');//                    if(sum1>=1000007)//                        sum1%=1000007;为什么这里会被注释掉?因为下面涉及两个数的减法sum2-sum1,那就会出现,本来sum2-sum1>0,但是取余后结果确是负值,eg:sum1=1000008,sum2=2000014.                }                long sum2=0;                for(int j=1;j<str2.length;j++){                    sum2+=(long)Math.pow(26,i-1-j)*(str2[j]-'a');//                    if(sum2>=1000007)//                        sum2%=1000007;                }                res+=sum2-sum1;                if(res>=1000007)                    res%=1000007;            }            /**             * 为什么-1?             * 因为res中包括了给出的字符串str2的这种情况.             * 比如:字符串a和字符串b,求i=1的字符串个数             * 显然:res+=1;  //来源于:res+=(long)Math.pow(26,i-1)*(b-a);             * 但是显然,a和b之间并没有子字符串.此时就包括了b这个字符串.所以结果得减去1.             */            res--;            System.out.println(res%1000007);        }    }}



原创粉丝点击