zoukankan      html  css  js  c++  java
  • 子序列的个数 --- 庞果网

    庞果网的新题目:

    题目描述


    本题同样来自caopengcs,只要你有兴趣,每个人都可以出题(出题入口在主页右侧边栏“贡献题目”->“我要发布”内),以下是题目详情:

    • 子序列的定义:对于一个序列a=a[1],a[2],......a[n],则非空序列a'=a[p1],a[p2]......a[pm]为a的一个子序列

      • 其中1<=p1<p2<.....<pm<=n。 例如:4,14,2,3和14,1,2,3都为4,13,14,1,2,3的子序列。
      • 对于给出序列a,有些子序列可能是相同的,这里只算做1个
    • 要求输出a的不同子序列的数量。

    输入:

    • 长度为n的数组1<=n<=100,数组元素0<=a[i]<=110

    输出:

    • 子序列 的个数对1000000007取余数的结果(由于答案比较大,输出Mod 1000000007的结果即可)

    算法描述


    刚开始的时候我总想着直接去算排列组合,然后根据容斥原理把重复的去掉,从而得到结果,后来发现这样不是不行,要考虑的东西实在是太多了,编程起来非常麻烦。放弃了。

    后来休息了一天,再看的时候换了一个思路,仔细分析了一下题目,按照递推关系,找到一个比较靠谱的思路。

    设 f(k)为k长度的序列的子序列个数,那么很显然有以下推论:

    • f(k)的个数包括f(k-1)的个数,因为f(k-1)的每一个都是f(k)的子序列,然后把f(k-1)的每个序列和a[k]组合起来,这些序列也是f(k)的子序列,个数还是f(k-1),载加上单独的a[k],那么

    f(k)=2*f(k-1)+1

    • 上面这个表达式是当a[k]和前面的数都不同的时候的情况,如果a[k]在前面出现过的话,那f(k)的个数除了上面那些的话:

      • 还需要减去最近一次出现a[k]这个数值的地方-1的子序列个数,因为这些算重复了
      • +1也没有了,因为f(a[k]上次出现的位置)包括了a[k]单独算一次的情况

    f(k)=2*f(k-1)-f(a[k]上次出现的位置-1)

    有了这两个表达式,就是一个完整的递推关系了,a[k]上次出现的位置的保存,可以用一个hash表来存储,这样速度很快,但是题目说a[k]的范围是0到220,那可以用一个220的数组来存储,反正也不会溢出,省得用hash了。

    代码比较简单,具体的可以上github上看



    subArray[0]=0;
    for(int i=1;i<=n;i++)
    	 {
    
    	     if(lastSameIndex[a[i-1]] == 0 )
    	     {
    			 subArray[i]=(subArray[i-1]*2)+1;         
    	     }
    	     else 
    	     {
    			 subArray[i]=((subArray[i-1]*2)-subArray[lastSameIndex[a[i-1]]-1]);
    	     }
    	     lastSameIndex[a[i-1]]=i; 
    	 }



  • 相关阅读:
    JSTL笔记(胖先生版)
    EL表达式(胖先生版)
    包装类-Character
    String定义与方法
    冒泡排序(大熊版)
    tomcat Manger App
    第一天
    剑指offer:面试题5、从尾到头打印链表
    剑指offer:面试题4、替换空格
    剑指offer:面试题3、二维数组中的查找
  • 原文地址:https://www.cnblogs.com/james1207/p/3329038.html
Copyright © 2011-2022 走看看