• 【读后感】编程珠玑(第二版)第八章


    第八章 算法设计技术
      这一章主要说明一个问题,一个看似复杂的算法有时可以极大的缩短程序的运行时间。
    8.1 问题及简单算法
    一个数组,有正有负,求出和最大的序列的值。比如1 -2 3 5,答案就是8。
    一道很经典的动态规划题,出处是不是在这里呀?
    一个简单的算法,三层循环,枚举起点和终点,然后从起点开始加到终点,最后更新max值。看似简单,但是n三次方的复杂度是不能够接受的。

    8.2 两个平方算法
    接着作者提出了两个平方的算法,主要是针对上一个三次放算法的优化。
    1. 因为每次都要计算从起点到终点的sum值,那么可以使用前面的sum值来简化计算这次sum值,这样就少了一层循环。
    2. 在进入主体循环之前,计算Ai,代表从0到i的和,这样我需要从3到5的和,那么就可以通过A5-A2来得到。
    虽然进行了优化,但算法还是n平方的。

    8.3 分治算法
    分治(divide and conquer),把原问题划分成2个子问题,然后求解出2个子问题,并将子问题的结果合并,就得到了原问题的解。
    这样,对于求一个数组的最大子序列的值,我们就可以分成2个子序列,然后求这两个子序列的最大序列和,最后对求出的子问题的解进行合并,合并的方法有两种,一是两个解不能拼成一个更长的序列,那么就求出二者的最大值;二是两个解可以拼成一个更长的序列,那么答案就是二者的和。
    怎么样才能求解出子问题的解呢?
    float recmax(int l, int u)
    {   int i, m;
    float lmax, rmax, sum;
    if (l > u)  /* zero elements */
    return 0;
    if (l == u)  /* one element */
    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];
    if (sum > lmax)
    lmax = sum;
    }
    /* find max crossing to right */
    rmax = sum = 0;
    for (i = m+1; i <= u; i++) {
    sum += x[i];
    if (sum > rmax)
    rmax = sum;
    }
    return max(lmax + rmax,
    max(recmax(l, m), recmax(m+1, u)));
    //max中的三个式子分别代表3种情况,左右相连,左最大,右最大。它们三个不可能同时最大
    }

    float alg3()
    {   return recmax(0, n-1);
    }

    算法公式T(n) = 2T(n/2)+O(n),可推导出T(n) = O(nlogn)

    8.4 扫描算法
    作者提出一种思路,“假设我们已经解决了x[0...i-1]的问题,那么如何将其扩展为包含x[i]的问题呢?我们使用类似于分治算法的原理:前i个元素中,最大总和子数组要么在前i-1个元素中,要么其结束位置为i”
    float alg4c()
    {   int i;
    float maxsofar = 0, maxendinghere = 0;
    for (i = 0; i < n; i++) {
    maxendinghere += x[i];
    maxendinghere = maxfun(maxendinghere, 0);
    maxsofar = maxfun(maxsofar, maxendinghere);
    }
    return maxsofar;
    }
    “理解这个程序的关键就在于变量maxendinghere。在循环中的第一个赋值语句之前,maxendinghere是结束位置为i-1的最大子向量的和;复制语句将其修改为结束位置为i的最大子向量的和。若加上x[i]之后结果依然为正值,则该赋值语句使maxendinghere增大x[i];若加上x[i]之后结果为负值,则该赋值语句就将maxendinghere重新设为0。”

    8.6 原理
    几种重要的算法设计技术。
    保存状态,避免重复计算
    将信息预处理至数据结构中
    分治算法
    扫描算法(与数组相关的题目经常可以通过思考(如何将x[0...i-1]的解扩展为x[0...i]的解)?)
    累积
    下界
    阅读全文
    类别:名著观感 查看评论
  • 相关阅读:
    PostgreSQL使用MySQL外表(mysql_fdw)
    使用node+puppeteer+express搭建截图服务
    零碎知识
    miniconda 搭建tensorflow框架
    有效需求分析阅读笔记(六)
    有效需求分析阅读笔记(五)
    索引原理和优势
    存储过程的优缺点
    RestSharp
    在vue中安装sass/scss报错
  • 原文地址:https://www.cnblogs.com/iammatthew/p/1803866.html
Copyright © 2020-2023  润新知