算法交作业之最大子序列问题

最近看《数据结构与算法分析》一书,书中提供的一些算法太棒了,忍不住动手实现了下。有错误请指出,谢谢。

最大子序列问题求解:

1.第一种解法:
int MaxSubSequence(const int array[], int length){
    if (length < 0) //数组长度不可以为0.
        return 0;
    int  MaxSum = 0,ThisSum;
    for (int i = 0; i < length; ++i){
        for (int j = i; j < length; ++j){
            ThisSum=0;
            for (int k = i; k < j + 1; ++k){
                ThisSum += array[k];
                if (ThisSum>MaxSum)
                    MaxSum = ThisSum;
            }
        }
    }
    return MaxSum;
}

/*时间复杂度为O(N3),不是很完美的算法。但是想法很简单。
假设有序列A0,A1,A2......AN-1。既然要求最大子序列。那么最笨的方法就是依次求出A0,A0+A1....A0+...AN-1......AN-1.通过枚举就可以求出。但是交给计算机实现就可以用循环实现了。*/
2.优化解法一:
int MaxSubSequence(const int array[], int length){
    if (length < 0) //数组长度不可以为0.
        return 0;
    int ThisSum, MaxSum = 0;
    for (int i = 0; i < length; ++i){
        ThisSum = 0;//注意
        for (int j = i; j < length; ++j){
                ThisSum += array[j];
                if (ThisSum>MaxSum)
                    MaxSum = ThisSum;
        }
    }
    return MaxSum;
}
/*可以看到对比上面我们少了一层循环,现在的时间复杂度就变成了O(N2),提升不少。
3.优化解法二:
//递归版本.首先确定基准情况。
int Max_numbers(int number1, int number2, int number3){
    if (number1 < number2)
        number1 = number2;
    return (number1>number3) ? number1 : number3;
}
int MaxSub(const int array[], int left,int right){
    if (right == left)
        if (array[left] > 0)
            return array[left];
        else
            return 0;
    int center = (right+left)/2;
    int LeftMax = 0, RightMax=0;
    LeftMax=MaxSub(array, left, center);
    RightMax=MaxSub(array, center + 1, right);
    int LeftBorderSum = 0, RightBorderSum = 0;
    int LeftMaxSum = 0, RightMaxSum = 0;
    for (int i = center; i >= left; --i){
        LeftBorderSum += array[i];
        if (LeftBorderSum > LeftMaxSum)
            LeftMaxSum = LeftBorderSum;
    }
    for (int i = center + 1; i < right + 1; ++i){
        RightBorderSum += array[i];
        if (RightBorderSum>RightMaxSum)
            RightMaxSum = RightBorderSum;
    }
    return Max_numbers(LeftMax, RightMax, LeftMaxSum + RightMaxSum);
}
int MaxSubSequence(const int array[], int length){
    if(length <0)
        return 0;
    return MaxSub(array, 0, length - 1);
}
/*这个算法太精妙了。反正我承认我是想不出如此使用递归。简单的分析下递归的用法,具体的可以去翻书。对于这个最大子序列问题,最大子序列可能出现在前面部分,后面部分,以及中间部分(包括前面部分的最后一个元素,后面部分的第一个元素)。然后这样分析下差不多就能理清代码轮廓了,具体的还是自己慢慢钻研。时间复杂度为O(NlogN),对比上面又优化了一下,但是付出了相应的代价,代码不好读了。
最后一种优化方法:
int MaxSubSequence(const int array[], int length){
    if (length < 0)
        return 0;
    int ThisSum=0, MaxSum = 0;
    for (int i = 0; i < length; ++i){
        ThisSum += array[i];
        if (ThisSum>MaxSum)
            MaxSum = ThisSum;
        else if (ThisSum < 0)
            ThisSum = 0;
    }
    return MaxSum;
}
/*这个算法更精妙了。复杂度和代码可读性控制都比较完美,书上称之为联机算法。算法的思想比较精妙,省去了前面算法中很多无效的步骤。比如算法中有一个判断thissum<0的条件。试想一下最大子序列的第一个数一定是不可能是复数的,所以直接把thissum设置为0。
举个例子:-1,2,-3,4,5,6,-1;
按照最前面的两个算法,肯定是先计算 -1;-1+2;-1+2+-3;但是最后一个算法直接把-1剔除了,直接从2;2+-3...开始算起,是不是节省了大量时间。重点是把握住性质。

ps:其实上述的函数传入参数还可以进行优化,可以参看前面的博文。等有空会写一下。

测试:

#include <iostream>
#include <assert.h>
/*int MaxSubSequence(const int array[], int length){
    if (length < 0) //数组长度不可以为0.
        return 0;
    int  MaxSum = 0,ThisSum;
    for (int i = 0; i < length; ++i){
        for (int j = i; j < length; ++j){
            ThisSum=0;
            for (int k = i; k < j + 1; ++k){
                ThisSum += array[k];
                if (ThisSum>MaxSum)
                    MaxSum = ThisSum;
            }
        }
    }
    return MaxSum;
}*/
/*int MaxSubSequence(const int array[], int length){
    if (length < 0) //数组长度不可以为0.
        return 0;
    int ThisSum, MaxSum = 0;
    for (int i = 0; i < length; ++i){
        ThisSum = 0;
        for (int j = i; j < length; ++j){
                ThisSum += array[j];
                if (ThisSum>MaxSum)
                    MaxSum = ThisSum;
        }
    }
    return MaxSum;
}*/
//递归版本.首先确定基准情况。
/*
int Max_numbers(int number1, int number2, int number3){
    if (number1 < number2)
        number1 = number2;
    return (number1>number3) ? number1 : number3;
}
int MaxSub(const int array[], int left,int right){
    if (right == left)
        if (array[left] > 0)
            return array[left];
        else
            return 0;
    int center = (right+left)/2;
    int LeftMax = 0, RightMax=0;
    LeftMax=MaxSub(array, left, center);
    RightMax=MaxSub(array, center + 1, right);
    int LeftBorderSum = 0, RightBorderSum = 0;
    int LeftMaxSum = 0, RightMaxSum = 0;
    for (int i = center; i >= left; --i){
        LeftBorderSum += array[i];
        if (LeftBorderSum > LeftMaxSum)
            LeftMaxSum = LeftBorderSum;
    }
    for (int i = center + 1; i < right + 1; ++i){
        RightBorderSum += array[i];
        if (RightBorderSum>RightMaxSum)
            RightMaxSum = RightBorderSum;
    }
    return Max_numbers(LeftMax, RightMax, LeftMaxSum + RightMaxSum);
}
int MaxSubSequence(const int array[], int length){
    if(length <0)
        return 0;
    return MaxSub(array, 0, length - 1);
}*/
//最后一个解法:
int MaxSubSequence(const int array[], int length){
    if (length < 0)
        return 0;
    int ThisSum=0, MaxSum = 0;
    for (int i = 0; i < length; ++i){
        ThisSum += array[i];
        if (ThisSum>MaxSum)
            MaxSum = ThisSum;
        else if (ThisSum < 0)
            ThisSum = 0;
    }
    return MaxSum;
}
int main(){
    int arr_1[8] = {4,-3,5,-2,-1,2,6,-2};
    std::cout<<MaxSubSequence(arr_1,8);
    system("pause");
    return 0;
}
时间: 2024-10-31 00:22:49

算法交作业之最大子序列问题的相关文章

算法交作业(一)

首先解释下标题的含义:在网上看了一位大牛写的基础算法相关的博文,感觉自己不是天赋异禀,所以决定自己实现一遍当作交作业. 开篇: 今天这篇博文是关于数组查找的,很简单. 算法是计算机的生命.没有算法,就没有软件,计算机也就成了一个冰冷的机器,没有什么实用价值.很多人认为,算法是数学的内容,学起来特别麻烦.我们不能认为这种观点是错误的.但是我们也知道,软件是一种复合的技术,如果一个人只知道算法,但是不能用编程语言很好地实现,那么再优秀的算法也不能发挥作用.一个人只有有了很好的计算机知识和数学知识,才

算法交作业之最大公约数

今天写一下最大公约数算法,英文简称为Gcd算法. 1.递归解法: /*书上并没有给出递归的解法,可能是觉得这个解法不是很完美,但是给出来就当学习下递归.*/ int Gcd(unsigned num1, unsigned num2){ if (num1 == 0 || num2 == 0)//算法基于欧几里德的算法. return (num1 > num2) ? num1 : num2; return Gcd(num2, num1%num2); } //代码写的很短小,但是效率可能不是很高 //

算法交作业之查找

前言: 刚刚写了一篇发泄文,果不其然,心里面舒服很多.既然心情舒畅了,那就继续写下去吧. 假定: 我们假定查找的数据唯一存在,数组中没有重复的数据存在. 普通查找: 适用情景: 无特征,需要遍历整个范围才可以确定. #include <iostream> #include <assert.h> //普通的查找算法. template<unsigned n> int Find_Array(const int(&arr)[n], const int& val

算法交作业之循环和递归(二)

说明: 循环是学习编程过程中的不可或缺的一部分.同时递归同循环有着千丝万缕的关系. 求和函数示例: //求0到n的和.求和失败返回-1.否则返回结果. #include <iostream> //最常见的循环写法. long long Sum(unsigned int&& n){ long long sum = 0; for (unsigned index = 1; index <n+1; ++index) sum += index; return sum; } //递归

图同构哈希算法实现 (作业)

*/--> 图同构哈希算法实现 (作业) Table of Contents 代码 例子 1 例子 2 例子 3 例子 4 例子 5 例子 6 例子 7 不是同构 例子 8 不是同构 例子 9 不是同构 例子 10 不是同构 测试数据和测试图片参考地址 Hash 函数除了做为 Hash 表的辅助工具,在单独使用的时候可以实现判断两个数据是否相同或等价 代码 // CreateTime: 2015-05-15 21:24:47 #include <iostream> #include &l

BZOJ 3379: [Usaco2004 Open]Turning in Homework 交作业

Description 贝茜有C(1≤C≤1000)门科目的作业要上交,之后她要去坐巴士和奶牛同学回家. 每门科目的老师所在的教室排列在一条长为H(1≤H≤1000)的走廊上,他们只在课后接收作业.交作业不需要时间.贝茜现在在位置0,她会告诉你每个教室所在的位置,以及走廊出口的位置.她每走1个单位的路程,就要用1秒.她希望你计算最快多久以后她能交完作业并到达出口. Input 第1行输入三个整数C,H,B,B是出口的位置.之后C行每行输入两个整数,分别表示一个老师所在的教室和他的下课时间. Ou

ThinkPHP5作业管理系统中处理学生未交作业与已交作业信息

在作业管理系统中,学生登陆到个人中心后可以通过左侧的菜单查看自己已经提交的作业和未提交作业.那么在系统中如何实现这些数据的查询的呢?首先我们需要弄清楚学生(Student).班级(class).作业提交表(Submit)这三个表之间的关系. 每个学生都属于一个班级 班级里的每个学生都会被布置同样的作业 学生提交作业后会在作业提交表中添加响应的记录,如学生的ID,作业的ID,提交的内容等. 可以按照以下步骤获取学生已交作业和未交作业 获取学生所在班级的所有作业 //获取学生所在班级的所有作业  p

算法学习 - 最长公共子序列(LCS)C++实现

最长公共子序列 最长公共子序列的问题很简单,就是在两个字符串中找到最长的子序列,这里明确两个含义: 子串:表示连续的一串字符 . 子序列:表示不连续的一串字符. 所以这里要查找的是不连续的最长子序列, 动态规划 这里为什么要使用动态规划可以说一下,简单来说动态规划是为了降低时间复杂度的一种算法,申请一个额外空间,来保存每一个步骤的结果,最后从这些结果中找到最优的解. 这里有个问题就是:一般来说,当前的最优解,只与当前时刻和上一时刻有关系,和其他时刻没有关系,这样才能让动态规划发生作用,降低复杂度

O(nlogn)算法,最长上升子序列,,非动规

//最长上升子序列最快算法,非动态规划,运用了二分思想,还有栈的思想, //用每一个数去和栈中的栈顶元素相比较,如果大于栈顶元素,则入栈,否则运用二分查找,寻找出第一个比这个数大的那个数替换 #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cmath> using namespace