zoukankan      html  css  js  c++  java
  • Programming Pearls笔记之二

    Programming Pearls笔记之二

    Programming Pearls笔记之二

      这里是编程珠玑(Programming Pearls)第二部分(中间五个专栏)的笔记.

    1 效率和正确性

    • 问题
      有句话说"效率是第二位的,结果是第一位的--如果结果都错了,再快又有何用".这种观点正确吗?
      
    • 解答

        当错误不是太严重以至于影响结果的时候时间更重要.比如对于一些大型系统,与其修改10个bug,人们往往更愿意将速度提高10倍.

    2 最大子序列和

    • 问题

        这是一道OJ题目,没想到在这里见到了它.或许这就是这个题目的出处?

      对于一组整数,求连续最大子序列和.    
      
    • O(n^2)解法

        这种时间复杂的算法很好设计.这里给出一个比较有启发性的.

      cumarr[-1]=0
      for i = [0, n)
          cumarr[i] = cumarr[i-1] + x[i]
      maxsofar = 0
      for i = [0, n)
          for j = [i, n)
              sum = cumarr[j] - cumarr[i-1]
              /* sum is sum of x[i..j] */
              maxsofar = max(maxsofar, sum)
      

        这里用到了累加求和,很有用处(比如下面的问题 累加数组 就能用到).但这里的求和很盲目,对所有的都求,因此并没有能降低时间复杂度.我们知道如果x[i..j]是最大子序列和,这就说明对于任意的k(i≤k≤j),sum[i..k]≥0.否则sum[k+1..j]将是最大的子序列.因此我们在求和的时候可以每遇到cumarr[i-1]为负时,就不再让cumarr[i] = cumarr[i-1] + x[i],而让cumarr[i] = 0.这时时间复杂度就可以降至O(n).

    • O(n)解法

        根据上面的思路,解法如下.

      cumarr[-1] = 0
      maxsofa = 0
      for i = [0, n]
          cumarr[i] = max(cumarr[i-1], 0)
          maxsofar = max(maxsofar, cumarr[0])
      

        下面是书上给出的一个利用动态归化来推导这个算法的过程.

      http://images.cnblogs.com/cnblogs_com/Open_Source/201208/201208050947148272.png

      图一 示意图

      maxendinghere是以当前下标为最后一个元素的最大子序列和(只有当包含当前元素值为0时可以是空序列),maxsofar是从数组开始到当前下标为止的最大子序列和.假设对于当前下标i-1成立.下面将这个状态推广到i.对于i,这时最大子序列和只有两种可能.要么还是maxsofar,要么是maxendinghere+x[i]. maxendinghere+[i]若小于0,则从0开始,于是代码如下.

    maxsofar = 0
    maxendinghere = 0
    for i = [0, n]
        /* invariant: maxendinghere and maxsofar
           are accurate for x[0..i-1] */
        maxendinghere = max(maxendinghere + x[i], 0)
        maxsofar = max(max, maxendinghere)
    

      其实这和上面的伪代码基本是一样的.

    • O(n log n)解法

        这是一个分治算法,虽然不是最优解,但可以锻炼下思维.直接给出算法.

      float maxsum3(l, u)
          if (l > u)  /* zero elements */
              return 0
          if (l == u)  /* one elements */
              return max(0, x[l])
      
          m = (l + u) / 2
          /* find max crossing to left */
          lmax = sum = 0
          for (i = m; i >= l; i--)
              sum += x[i]
              lmax - max(lmax, sum)
          /* find max crossing to right */
          rmax = sum = 0
          for i = (m, u]
              sum += x[i]
              rmax = max(rmax, sum)
          return max(lmax+rmax, maxsum3(l, m), maxsum3(m+1, u))
      

    3 累加数组

    • 问题
      数组x[0..n-1]中的元素初始化为0,经过n步下面的操作,给出最终的数组元素.其中l,u和v是每个操作的参数(0≤l≤u<n,是整数;v是实数).
      for i = [l, u]                    ①
          x[i] += v                     ②
      
    • 解答

        这个问题用累加数组来解决.操作①、②对应于cum[l]+=v;cum[u+1]-=v.意思是让x[l..n-1]+=v,然后再让x[u+1..n-1]-=v.最终计算x的方式是:

      for (i = 0; i < n; i++)
        x[i] = x[i-1] + cum[i];
      

        书中给出的答案是让操作①、②对应于cum[u]+=v;cum[l-1]-=v.最后计算x时从后往前累加计算.

    4 哨兵元素

    • 问题
      利用哨兵元素求数组最大值.
      
    • 解答

        没什么知识可以学习,就觉得R.G.Dromey这个解答有点儿耐人寻味.

      i = 0
      while i < n
          max = x[i]
          x[n] = max
          i++
          while x[i] < max
              i++
      

    5 多项式计算

    • 问题
      对于下面的多项式,优化下面的算法.
       y = a[0]
       xi = 1
       for i = [1, n]
           xi = x * xi
           y = y + a[i]*xi
      

      $y = a_nx^n + a_{n-1}x^{n-1} + ... + a_1 x^1 + a_0$

    • 解答

        下面Horner的方法几乎可以使效率提高一倍.

      y = a[n]
        for (i = n-1; i >= 0; i--)
          y = x*y + a[i]
      

    Date: 2012-07-25 三

    Author: Hu Wenbiao

    Org version 7.8.11 with Emacs version 24

    Validate XHTML 1.0
  • 相关阅读:
    Andorid自定义attr的各种坑
    git 使用那些事儿
    Gradle task
    他们要消失了吗?探访人工智能浪潮下的鉴黄师
    测试环境docker化—容器集群编排实践
    测试环境docker化(一)—基于ndp部署模式的docker基础镜像制作
    后台服务项目的白盒测试之旅
    利用反向代理测应用的流量
    CCF 201312-5 I’m stuck! (暴力,BFS)
    CodeForces 709C Letters Cyclic Shift (水题)
  • 原文地址:https://www.cnblogs.com/Open_Source/p/2623635.html
Copyright © 2011-2022 走看看