zoukankan      html  css  js  c++  java
  • 数据结构与金融算法 18-19秋季学期 期中考试简略题解

    1.一个满二叉树的定义是,所有的节点要么有两个子节点,要么没有子节点。定义Bn为:n个节点的满二叉树,对应的二叉树数量。对称的两个树分别计算。求证:Bn∈Ω(2n

    比如,B1=1,B3=1,B5=2。

    这题的关键在于求出Bn的递推式。多画几次就能发现,实际上对于一颗Bn树,包含的情况有一边子树为B1,一边子树为Bn-2。依次类推可以得到如下递推式:

    那么,就可以运用一下数学归纳法。如果能从Bn-2,Bn-4之类的入手,得到一个放缩的式子大于等于2n的话,那就再好不过了。

    不过很可惜,如果直接Bn = 2Bn-2 x B1 + 2Bn-4 x B3 + 2Bn-6 x B5 + ... ≥ 2 · 2n-2 · 1 + 2 · 2n-4 · 1 + 2 · 2n-6 · 4 + ...,需要算到起码Bn-20之后才能满足放缩条件。这在正常做题中显然是没办法的。

    但是我们可以验证(猜想),当n足够大时,B(n-1)/2是足够大于2n的。那么只要我们从折半的地方入手,很容易就能从类似B(n-1)/2 x B(n-1)/2这样的式子中推出放缩式。具体细节就不再赘述了,读者可以自行验证。

    2. 当前有一个大小为n的无序列表,以及一个数S。设计一个O(nlgn)算法,寻找列表里面是否有两个数加和等于S。

    既然是nlgn算法,当然需要先排序一下,这里的代价就是nlgn了。

    然后,可以考虑这样一个线性的算法:

    假设有序列表为x。现在让两个指针,left和right,分别指向x[0]和x[n-1]。

    然后,若x[left] + x[right] > S,则right -= 1,而若是 < S,则left += 1。

    终止条件为x[left] + x[right] == S或者left == right。

    显然这是一个线性算法。代码如下:

    #...处理x,已知S
    left = 0
    right = n-1
    while left < right:
        if x[left] + x[right] < S:
            left += 1
        else if x[left] + x[right] > S:
            right -= 1
        else:
            return true
    return false

    举一个例子可能有助于理解:

    算法的正确性可以这么考虑:由于数组有序,当left右移,l + r的大小就会增加,反之,right左移,l + r就会减小。无论l + r与S有什么关系,每一次循环总能找到进行一次退出或将right - left减少1的操作。由于right - left最大为n -1,因此这个算法是线性的。

    3. 现在有n个处于区间[0, m]的整数,要求经过O(n+m)的预处理之后,可以用O(1)的算法返回位于指定区间[a, b]之间的数的个数。

    仔细思考一下会发现,预处理其实就是制作出一个类似于离散型分布函数的数组。

    设数据数组为S,分布数组为D。首先,我们可以遍历S,对于一个数i,就使D[k] += 1。然后得出一个类似分布律的东西。实际上,把数组里的每个数除以n,就得到了S的分布律。

    然后,将前一个格的东西加和到后一格,就可以得出分布函数了。

    最后要注意,查询函数是D[b] - D[a - 1],否则就会缺少a上的数值了!

    4. 对于一个栈,给定两个操作:

    Ordered-push( x ):如果x < 栈顶元素first,就弹出first,直到满足x ≥ first为止,然后插入x。

    Pop( x ):弹出first。

    用摊还分析计算操作代价。

    考虑实际代价:

    • O-push:2i + 2。假设弹出了i个元素,则比较次数为i + 1,弹出次数为i,插入次数为1,共2i + 2。
    • Pop:1。

    那么,如何分析会计代价呢?

    一般的会计代价分析,需要将一个大代价的操作平摊到小代价操作上。然而由于这题的O-push大部分的代价本质上也是pop,所以分摊到小pop操作上显然是不合适的。

    所以,这题需要O-push自我分摊。方案是这样的:

    • 弹出i个元素之前,必然需要先进行i次O-push操作。
    • 那么,就可以将2i分摊到pop出的i个元素中,每个元素分配2的代价。

    这样,会计代价就是:

    • O-push:-2i + 2。-2i是分摊出去的,2是被分摊到的。
    • Pop:0

    所以,摊还代价为:

    • O-push:4
    • Pop:1

    整个数据类型的操作代价是O(1)。

    5. 对于一个有向图,

    (1)设计O(n+m)的算法,判断从一个特定的点v是否可以到达图上所有点;

    (2)设计O(n+m)的算法,判断图中是否存在点,可达图上所有点。

    首先摆dfs框架:

    def dfs(adjVers, color, v):
        color[v] = gray
        <preorder proc>
        remAdj = adjVers[v]
        while remAdj:
            w = remAdj.first()
            if (color[v] == white):
                <exploratory proc for vw>
                wAns = dfs(adjVers, color, w)
                <backtrace proc for vw>
            else:
                <checking nontree edge vw>
            remAdj = remAdj.rest()
        <postorder proc>
        color[v] = black
        return ans

    先看看第一题。方法是多种多样的。

    • 我们可以利用活跃区间,即记录一个点探索到的时间和结束探索的时间。在从v开始进行dfs的时候,如果v是最后一个结束访问的节点,即可以得出v可以到达所有的点。
    • 除此之外,也可以利用点的着色,看看v之后是否还有白色点。如果没有则v满足条件。
    • 我自己的做法有点绕:在dfs过程中,记录一个点以自己为根的子树包含的节点数。如果v的这个数为n,说明v满足条件。

    对于我自己的做法,要对dfs做出如下更改:

    #preorder proc
        ans = 1
    
    #backtrace proc for vw
        ans += wAns

    而对于第二题,关键在于,在dfs结束后,最后一个dfs树的根是否可达所有的点。至于为什么可以仔细想想,大概可以往反证法的方向考虑。

    所以基于这个思想,可以在dfs过程中记录这个最后的根,并在dfs结束后对这个根运用(1)的算法。

    仔细考虑会发现,如果这样的点存在,那么如果在dfs过程中,在寻找到根时把根接入,那么最终只会剩下一个dfs树。

    这个时候既可以用记录自根子树节点数的方法,也可以用单纯记录根的方法。殊途同归。

    然而要注意,用自根子树节点数方法时,其实也需要记录根,而不能仅仅靠黑色节点。否则会出现问题。

    6. 一个二进制数N有n位,可以进行以下操作:

    1. Addition(x, y),将x+y的结果保存在x中。

    2. Shift(x, d),将x左移或右移一位,方向取决于d,1为左移,-1为右移。

    现在用以上操作设计两个算法:

    1. 用O(n)次Addition和Shift求出N2

    2. 用O(n2)次Addition和Shift求出⌈√N⌉。

    第一题还是很好做的。如果自己模拟一下乘法,就能知道怎么写这个算法。

    def Pow(x):
        f = x
        ans = 0
        for i = 1 to n:
                if x[i] == 1:
                    Addition(ans, f)
                Shift(f, 1)
        return ans

    在第一题的基础上,第二题其实也不难做了。考虑一下,如果是普通的十进制数,可以用二分搜索的方式——找到一个Pow(k) == N的数就行了。同样的,在这里也可以用二分搜索。但是要注意的是,不能混淆了N和n——n是位数,N的最大大小其实是2n

  • 相关阅读:
    20201016---不做清单
    20201014--增删改查
    20201013--什么是真实的自己?
    多态
    继承
    关键字
    分类思想
    常用的linux命令
    九九乘法表
    稀疏数组
  • 原文地址:https://www.cnblogs.com/KakagouLT/p/9998895.html
Copyright © 2011-2022 走看看