算法——bing字典问题

本届大赛由微软必应词典冠名,必应词典(Bing Dictionary)是微软推出的新一代英语学习引擎,里面收录了很多我们常见的单词。但现实生活中,我们也经常能看到一些毫无规则的字符串,导致词典无法正常收录,不过,我们是否可以从无规则的字符串中提取出正规的单词呢?

例如有一个字符串"iinbinbing",截取不同位置的字符‘b’、‘i’、‘n’、‘g’组合成单词"bing"。若从1开始计数的话,则‘b’ ‘i’ ‘n’ ‘g’这4个字母出现的位置分别为(4,5,6,10) (4,5,9,10),(4,8,9,10)和(7,8,9,10),故总共可以组合成4个单词”bing“。

咱们的问题是:现给定任意字符串,只包含小写‘b’ ‘i’ ‘n’ ‘g’这4种字母,请问一共能组合成多少个单词bing?

字符串长度不超过10000,由于结果可能比较大,请输出对10^9 + 7取余数之后的结果。

我的做法是:

(1)将b、i、n、g分别放入四个桶中(实际放的不是这些字符),每个桶有个记录桶内当前字符数量的变量num(初始值为0),桶内的每个元素记录的内容是这样的:

如果是b桶,那么里面的元素记录的是这个b字符后面的第一个i字符在桶i内的索引(桶的索引从0开始,也就是桶的num变量值);

如果是i桶,那么里面的元素记录的是这个i字符后面的第一个n字符在桶n内的索引;

如果是n桶,那么里面的元素记录的是这个n字符后面的第一个g字符在桶g内的索引;

g桶只需要记录桶内的字符数量即可;

桶内每插入一个元素,桶的num变量+1.

这可以通过一次从前向后扫描字符串得到,这部分的复杂度为O(n),以题目中的"iinbinbing"为例,桶的构建结果如下:

(2)根据(1)计算数量,以这个例子进行说明:

第3个n字符后面的g字符数量为1-0=1(桶g的num值减去这个n字符对应位置保存的桶g的索引值)

第2个n字符后面的g字符数量为1-0=1 

第1个n字符后面的g字符数量为1-0=1 

        并用计算出来的这些值代替桶中原来的值,如下:

第4个i字符后面的n,g序列的数量为:for j=2 to 3-1 :sum(n[j]) = 1

第3个i字符后面的n,g序列的数量为:for j=1 to 3-1 :sum(n[j]) = 1+1 =2

第2个i字符后面的n,g序列的数量为:for j=0 to 3-1 :sum(n[j]) = 1+1+1 =3

第1个i字符后面的n,g序列的数量为:for j=0 to 3-1 :sum(n[j]) = 1+1+1 =3

并用计算出来的这些值代替桶中原来的值,如下:

       

第2个b字符后面的i,n,g序列的数量为:for j=3 to 4-1 :sum(i[j]) = 2+1 =3

第1个b字符后面的i,n,g序列的数量为:for j=2 to 4-1 :sum(i[j]) = 1

那么结果就是3+1=4。

到这里你应该明白了计算过程。

这个计算过程可以优化:每个循环可以利用上一个循环的计算结果加上本次循环需要增加的量来计算:

比如计算“第3个i字符后面的n,g序列的数量为”,可以通过第4个i字符后面的n,g序列的数量+增加的量来计算。

优化后计算过程的复杂度也为O(n)。

(3)综上复杂度为O(n)

(4)代码如下,计算部分未优化:

[cpp] view
plain
copy

  1. #include <stdio.h>  
  2. #include <iostream>  
  3. #include <string>  
  4. using namespace std;  
  5. class Test {  
  6. public:  
  7.     static int howmany (string   s){  
  8.         int div=1000000007;  
  9.         long long res=0;  
  10.         int *tmp[4];//其实3个就可以了  
  11.         int nums[4];  
  12.         for(int i=0;i<=3;++i){  
  13.             tmp[i]=new int[s.size()+1];  //  
  14.             nums[i]=0;  
  15.         }  
  16.         for(int i=0;i<=s.size();++i){//可以使用memset,会更快点  
  17.             tmp[0][i]=0;  
  18.             tmp[1][i]=0;  
  19.             tmp[2][i]=0;  
  20.             tmp[3][i]=0;  
  21.         }  
  22.         for(int i=0;i<s.size();++i){  
  23.             if(s[i]=='b'){  
  24.                 tmp[0][nums[0]]=nums[1];  
  25.                 ++nums[0];  
  26.             }else if (s[i]=='i'){  
  27.                 //可以优化  
  28.                 tmp[1][nums[1]]=nums[2];  
  29.                 ++nums[1];  
  30.             }else if(s[i]=='n'){  
  31.                 tmp[2][nums[2]]=nums[3];  
  32.                 ++nums[2];  
  33.             }else {  
  34.                 ++nums[3];  
  35.             }  
  36.         }  
  37.         for(int i=nums[2]-1;i>=0;--i){  
  38.             tmp[2][i]=nums[3]-tmp[2][i];  
  39.         }  
  40.         for(int i=nums[1]-1;i>=0;--i){  
  41.             int j=tmp[1][i];  
  42.             tmp[1][i]=0;  
  43.             for(;j<nums[2];++j){  
  44.                 //这里可以优化,可以减少加法的次数  
  45.                 //通过利用tmp[1][i+1]的值  
  46.                 tmp[1][i]+=tmp[2][j];  
  47.             }  
  48.         }  
  49.         long long t=0;  
  50.         for(int i=nums[0]-1;i>=0;--i){  
  51.             int j=tmp[0][i];  
  52.             for(;j<nums[1];++j){  
  53.                 //这里可以优化,可以减少加法的次数  
  54.                 //通过利用上一次i循环的t的值  
  55.                 t+=tmp[1][j];  
  56.                 t%=div;  
  57.             }  
  58.         }  
  59.         return t;  
  60.     }  
  61. };  
  62. //start 提示:自动阅卷起始唯一标识,请勿删除或增加。  
  63. int main()  
  64. {     
  65.     cout<<Test::howmany("iinbinbing")<<endl;     
  66. }   
  67. //end //提示:自动阅卷结束唯一标识,请勿删除或增加。  
  1. public class Test   
  2. {   
  3.    public static int howmany(String s){  
  4.         int bNum = 0;  
  5.         int biNum = 0;  
  6.         int binNum = 0;  
  7.         int bingNum = 0;  
  8.         for(int i=0;i<s.length();i++){  
  9.             switch (s.charAt(i)) {  
  10.             case 'b':bNum++;break;  
  11.             case 'i':biNum=biNum%1000000007+bNum; break;  
  12.             case 'n':binNum = binNum%1000000007+biNum;    break;  
  13.             case 'g':bingNum = bingNum%1000000007+binNum; break;  
  14.             default:  
  15.                 break;  
  16.             }  
  17.         }  
  18.         return bingNum%1000000007;  
  19.     }  
  20.     //start 提示:自动阅卷起始唯一标识,请勿删除或增加。   
  21.     public static void main(String args[])   
  22.     {   
  23.        System.out.println(howmany("binbinggg"));  
  24.     }   
  25.     //end //提示:自动阅卷结束唯一标识,请勿删除或增加。  
  26. }          
时间: 2024-11-10 08:18:44

算法——bing字典问题的相关文章

C#常用算法:字典

.Net(4.0)为我们提供了如下类型的字典结构:Dictionary, SortedDictionary, Lookup.这些类型都支持范型,它们的工作原理基本一致,都是提供如下功能:接收健返回值.它们之间的不同处为: SortedDictionar:有序字典,插入字典的元素都按升序进行了排列. Lookup:一键可以对应多值. 在字典的数据结构中,真实充当键的不是当前对象的值.而是对象的hash值,这个值是通过object.GetHashCode()方法返回的.按照不同的对象应该具有不同的h

PHP 实现的字典序排列算法

感谢 bird 告诉我 $_POST[] 的用法.代码如下: <?php if ($_POST["perdata"] == "") { $_POST["perdata"] = "1 2 3 4"; } $data = chop (trim ($_POST["perdata"])); $a = explode (" ", $data); sort ($a); $data = impl

Android应用安全开发之浅谈密钥硬编码

Android应用安全开发之浅谈密钥硬编码 作者:伊樵.呆狐@阿里聚安全 1 简介 在阿里聚安全的漏洞扫描器中和人工APP安全审计中,经常发现有开发者将密钥硬编码在Java代码.文件中,这样做会引起很大风险.信息安全的基础在于密码学,而常用的密码学算法都是公开的,加密内容的保密依靠的是密钥的保密,密钥如果泄露,对于对称密码算法,根据用到的密钥算法和加密后的密文,很容易得到加密前的明文:对于非对称密码算法或者签名算法,根据密钥和要加密的明文,很容易获得计算出签名值,从而伪造签名. 2 风险案例 密

破解 Ashley Madison 1100万个口令

本文讲的是 破解 Ashley Madison 1100万个口令,一组口令破解的爱好者在 Ashley Madison 被泄露出的网站源代码中发现,其处理口令的方式存在严重问题,他们利用这个编程失误,从泄露的3600万账户口中破解了1100万个口令. 几周前,研究人员还以为这些账户是安全的,因为这些口令是以一种通用的哈希算法,用Bcrypt加密函数存储在数据库中. 这样保护口令是对的 哈希属于单向加密,把明文通过多次加密算法以生成一个唯一的字符串,该过程是不可逆的,除非算法被破解.但有时暴力破解

任何数据都可压缩成1‰

不管你信不信,我己经实现了将任何数据压缩重千分之一,我压缩的依据就是数据中含有大量的重复字符,将这些重复字符信息用占用空间较少的符号或代码来代替的过程. 压缩的原理 每个文件都由各种不同代码组成,比如01代码.这类文件只有数字0与1组合.压缩原理就是"通过查找其中的规律,简化数字的排列".比如00000110001111111111简化成5个0,2个1,3个0,10个1的排列.在极限压缩方式下可以将28.1G压到25.8M. 用WinRAR压缩后可以看出,多媒体文件压缩比最低,与原文件

算法题:HDU 1251 统计难题(字典树,统计前缀个数)

链接: http://acm.hdu.edu.cn/showproblem.php?pid=1251 题目 Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组 成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的 前缀). Input 输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师 交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提

求一个密码字典的生成算法!!!!!!!!!!!!!!!!

问题描述 求一个密码字典的生成算法!!!!!!!!!!!!!!!! 求一个密码字典的生成算法,要求生成一个学号,外加6位生日码,结果保存在文本文件中 解决方案 http://blog.csdn.net/rancheice/article/details/8741962 解决方案二: 首先你可以自己定义一个hashcode可以实现,这只不过是简单地实现方式,另外的方法就是使用加密算法,网上有很多的加密算法,直接搬过来就可以了,然后对学号和生日分别加密分别保存,解决!

[算法系列之二十]字典树(Trie)

一 概述 又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计. 二 优点 利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高. 三 性质 (1)根节点不包含字符,除根节点外每一个节点都只包含一个字符: (2)从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串: (3)每个节点的所有子节点包含的字符都不相同. 单词列表为"apps&

算法 全排列 动态规划-算法实战题:创建摩尔斯电码字典计算第k个答案

问题描述 算法实战题:创建摩尔斯电码字典计算第k个答案 题目如下:计算第k个答案 摩尔斯电码字典 在没有电话的时代,摩尔斯电码是无线电传输领域中的一种常用代码.电码以短信号(短点,o)和长信号(长点,-)的不同组合表示各种文字.例如:o-表示英文字母J,而-表示英文字母M. 假设有一本以n个长点和m(n.m<=100)个短点组成的.包含所有信号的字典.例如:n=m=2,就会包含如下信号. --oo -o-o -oo- o--o o-o- oo-- 这些信号已按照字典顺序排列好了.-的ASKII码