Codility上的练习(11)

(1)Ladder

给定两个等长的数组A和B, A[i]和B[i]表示求一个有A[i]级的梯子,每次上1级或者两级,上到最高级的方法数对2^B[i]取余数的结果。

数据范围:数组长度 L [1..30000] , A中数字范围 [1..L], B中数字范围[1..30]

要求复杂度 时间空间都是O(L)

分析:打表法——我们循环可以把0..L的结果都算出来 f[i] = f[i - 1] + f[i - 2]  , f[0] = f[1] = 1。 关键点在于取余数,这个取余数很特殊,对2^B[i]取余数,相当于取结果的低B[i] bit。因此我们可以取所有结果的低30位,打好表,输出时再真正取B[i]位,就能达到O(L)的复杂度了。

// you can also use includes, for example:
// #include <algorithm>

const int M = (1 << 30) - 1;
vector<int> solution(vector<int> &A, vector<int> &B) {
    // write your code in C++98

    int m = 0;
    for (int i = 0; i < A.size(); ++i) {
        m = max(m, A[i]);
    }
    vector<int> f;
    f.resize(m + 1);
    f[0] = f[1] = 1;
    for (int i = 2; i <= m; ++i) {
        f[i] = (f[i - 1] + f[i - 2]) & M;
    }
    vector<int> answer;
    for (int i = 0; i < A.size(); ++i) {
        answer.push_back(f[A[i]] & ((1 << B[i]) - 1));
    }
    return answer;
}

(2) FibFrog

先给了Fibonacci的定义F[0] = 0, F[1] = 1, F(M) = F(M - 1) + F(M - 2) if M >= 2。一只青蛙想从河岸(-1)跳到对岸(N)。中间有0..N-1这N个位置,有一个数组A[]表示这些位置是否有荷叶 ,0表示没有,1表示有。青蛙从岸上要跳到荷叶上,通过0个或者多个荷叶跳到对岸,而且只能朝对岸的方向跳——不能往回跳。而且青蛙每次跳的距离必须是一个Fibonacci数,请问青蛙最少几步跳到对岸?无解返回-1。

数据范围: N [0..30000]

要求复杂度 :时间O(NlogN),空间O(N)。

分析: 首先我们可以把数组尾端加一个1,表示对岸。可以认为首端有一个1或者认为数组下标从1开始,我们现在目标是到数组最后一个元素,只能通过1且跳的距离是Fibonacci数的最小步数。 这是一个显然的dp (或者说是bfs)。对于位置i 并且A[i] == 1,我们有 dp[i] = min(dp[i - f[j]]) + 1 其中f[j]是fibonacci数并且满足A[i - f[j]]==1

因为Fibonacci是指数增长的,所以不超过N的Fibonacci数是O(logN)个,整个递推的时间复杂度是O(NlogN)。

// you can also use includes, for example:
// #include <algorithm>
int solution(vector<int> &A) {
    // write your code in C++98
    A.push_back(1);
    int n = A.size();
    vector<int> f;
    f.push_back(1);
    f.push_back(1);
    for (int i = 1; f[i] < n; ++i) {
        f.push_back(f[i] + f[i - 1]);
    }
    vector<int> answer;
    answer.resize(n + 1, -1);
    answer[0] = 0;
    for (int i = 1; i <= n; ++i) {
        answer[i] = -1;
        if (A[i - 1] == 0) {
            continue;
        }
        for (int j = 0;(j < f.size()) && (i >= f[j]); ++j) {
            if ((answer[i - f[j]] >= 0) && ((answer[i] < 0) || (answer[i] > answer[i - f[j]] + 1))) {
                answer[i] = answer[i - f[j]] + 1;
            }

        }

    }
    return answer[n];
}
时间: 2024-10-13 16:21:36

Codility上的练习(11)的相关文章

Codility上的问题(35) Neon 2014

也是比较有意思的题,越来越数学了--不善于做这种题. 如图一个码头有N个木桩,用于拴住船,码头长度是M,可以理解未0到M的线段.有N调船,每条船的一半长度为X,所以船长是2 * X.每个船的中心必须拴在一个木桩上.并且每个木桩只能拴一条船.拴船的绳子长度是船的中心与木桩位置的距离.当然,木桩的位置不能移动,但是船可以自由左右移动.要求船头船尾必须都在码头上(0..M的线段),船也可以看作长度为2 * X的线段,请给每条船指定一个位置让拴船的最长绳子长度最短,求这个最短的绳子长度.如果无法容纳下所

codility上的问题 (36)Natrium 2014

这个题比较简单,好像也比较old,给定一个整数数组A,有N个元素,找到所有下标对(P,Q)满足  0 ≤ P ≤ Q < N 并且 A[P] ≤ A[Q]中最大的Q-P. 数据范围N [1..3*10^5] 数组元素[-10^9, +10^9] 要求时间复杂度O(N),空间复杂度O(N). 分析: 如果b[i] = max{a[i..N - 1]} ,则对每个i,我们找到最大的j,满足b[j]>=a[i],就可以了.这样做的目的是b,反映了后面还有没有比a[i]大的.注意到假如现在找到的最大差

我的淘宝:Ubuntu 14.04.5上安装 Oracle 11.2.0.4 RAC

进入淘宝店铺 教程:Ubuntu 14.04.5上安装 Oracle 11.2.0.4 RAC 请支持下.价格好商量!

我的淘宝:Ubuntu 16.04.2上安装 Oracle 11.2.0.4 RAC

进入淘宝店铺 教程:Ubuntu 16.04.2上安装 Oracle 11.2.0.4 RAC 请支持下.价格好商量!

我的淘宝:Ubuntu 12.04.5上安装 Oracle 11.2.0.4 RAC

进入淘宝店铺 教程:Ubuntu 12.04.5上安装 Oracle 11.2.0.4 RAC 请支持下.价格好商量!

codility上的问题(34) Fluorum 2014

好久没写codility的题了,一来没时间,二来有的题目不太好分析.这个题比较有意思,我还没有给出非常严格的证明. 给定一棵树(无向无环图),从一个节点出发,每次选择一个节点,从起点到目的节点的路径上没经过的节点尽可能多,直到遍历完所有的节点.如果起点到两个目的节点的路径中没经过的节点同样多,则选择标号较小的节点作为目的节点.如此继续,直到遍历所有的节点,求按顺序选择了哪些目的节点? 例如从2 开始,第一次选择0,然后1,0变为经历过的节点. 然后从0开始,第二次选择6, 然后4,6变为经历过的

【翻译自mos文章】在RHEL7 or OEL7上安装oracle 11.2.0.4 db时的要求

在RHEL7 or OEL7上安装oracle 11.2.0.4 db时的要求 来源于: Requirements for Installing Oracle 11.2.0.4 RDBMS on RHEL7 or OL7 64-bit (x86-64) (文档 ID 1962100.1) 适用于: Oracle Database - Standard Edition - Version 11.2.0.4 to 11.2.0.4 [Release 11.2] Oracle Database - E

Codility上的练习 (14)

(1) TieRopes 给定n段绳子--一个正整数数组,和一个正整数K,每次只能连接相邻的两根绳子,连接好了绳子长度为之前的绳子长度和,并且位置不变,问这么连接下去,最多能形成多少根长度至少为K的绳子? 数据范围: N[1..10^5], 数组元素和K的范围[1..10^9]. 要求复杂度: 时间O(N), 空间O(1). 分析: 假设最终扔掉一根绳子,那么为什么不把这根绳子连接到它相邻的绳子上呢? 所以不会扔绳子的-- 于是就线性扫一下 总和 >= K就是一条... // you can a

Codility上的练习 (10)

(1)ChocolatesByNumbersN块巧克力,从0到N - 1编号,排成一个圈.从0号开始吃,如果上一次吃了x号,这一次吃(x + M) % N号,如果该号码已经存在,则停止.问结束前,吃了多少块巧克力?数据范围M ,N [1..10^9]要求复杂度 时间O(log(M + N)) 空间O(1) 分析: 可以证明吃巧克力必然形成一个从0号开始的圈.因为0, M % N,  M * 2 % N .... 这些编号,如果有两个相等,比如a * M % N 和 b * M % N,满足0 <