数据结构(一)-----4种方法求最大子列和

数据结构(一)-----4种方法求最大子列和

1、暴力算法

/*
作者:mys
功能:求最大子列和
日期:2018/7/23
*/
#include<stdio.h>
#include<stdlib.h>
#define N 1000
int maxSubseSum(int a[], int n);
void main()
{
    int a[N] = { 0 },i;
    for (i = 0; i < N; i++)
        a[i] = rand() % 10000;
    printf("maxSubseSum=%d\n", maxSubseSum(a, N));
    system("pause");
}

int maxSubseSum(int a[],int n)
{
    int thisSum, maxSum = 0;
    int i, j, k;
    for (i = 0; i < n; i++)//i是子列左端位置
    {
        for (j = i; j < n; j++)//j是子列右端位置
        {
            thisSum = 0;//thisSum:a[i]到a[j]的子列和
            for (k = i; k <= j; k++)
            {
                thisSum += a[k];
                if (thisSum>maxSum)//更新结果
                    maxSum = thisSum;
            }
        }
    }
    return maxSum;
}

因为有3重for循环,因此时间复杂度为:T(N)=O(N^3),时间复杂度太大,不理想,下面是稍微优化后的。

2、稍微优化

#include<stdio.h>
#include<stdlib.h>
#define N 1000
int maxSubseSum(int a[], int n);
void main()
{
    int a[N] = { 0 }, i;
    for (i = 0; i < N; i++)
        a[i] = rand() % 10000;
    printf("maxSubseSum=%d\n", maxSubseSum(a, N));
    system("pause");
}

int maxSubseSum(int a[], int n)
{
    int thisSum, maxSum = 0;
    int i, j;
    for (i = 0; i < n; i++)//i是子列左端位置
    {
        thisSum = 0;//thisSum:a[i]到a[j]的子列和
        for (j = i; j < n; j++)//j是子列右端位置
        {
                thisSum += a[j];
                if (thisSum>maxSum)//更新结果
                    maxSum = thisSum;

        }
    }
    return maxSum;
}

T(N)=O(N^2)

时间复杂度稍微好一点,但还是比较大,程序员一般看到时间复杂度是N^2,就会想办法将其复杂度变为NlogN,因此出现了下面的分而治之法。

3、分而治之

/*
作者:mys
功能:求最大子列和(分而治之)
*/
#include<stdio.h>
#include<stdlib.h>
#define N 1000

//求三个数的最大值
int Max(int a, int b, int c)
{
    int max;
    max = (a > b) ? a : b;
    max = (max > c) ? max : c;
    return max;
}

//遍历整个子列求最大值
int maxCross(int a[], int left, int mid, int right)
{
    int leftSum=0,rightSum=0,sum=0;
    int i;
    //遍历从中间到左边
    for (i = mid; i >=left; i--)
    {
        sum += a[i];
        if (sum > leftSum)
            leftSum = sum;
    }
    //遍历从中间到右边
    sum = 0;
    for (i = mid + 1; i <= right; i++)
    {
        sum += a[i];
        if (sum > rightSum)
            rightSum = sum;
    }
    return leftSum + rightSum;
}

//分而治之
int divideAndRule(int a[], int left,int right)
{
    int mid=0;
    int maxLeft=0, maxRight=0, maxMiddle=0;
    //如果只有一个数
    if (left == right)
    {
        if (a[left] > 0)
            return a[left];
        else
            return 0;
    }
    //求中间值
    mid = (left + right) / 2;
    //对左边的子列用分而治之法
    maxLeft = divideAndRule(a, left, mid);
    //对右边的子列用分而治之法
    maxRight = divideAndRule(a, mid + 1, right);
    //遍历整个子列
    maxMiddle = maxCross(a,left,mid,right);
    return Max(maxLeft, maxRight, maxMiddle);
}

void main()
{
    int a[N] = { 0 }, i;
    for (i = 0; i < N; i++)
        a[i] = rand() % 10000;
    printf("divideAndRule=%d\n", divideAndRule(a, 0, N - 1));
    system("pause");
}

此程序的时间复杂度计算如下:

T(N)为程序的整个递归的时间复杂度,因此前半的时间复杂度为T(N/2);不断替换,直到T(1);其中N/2^k=1是因为N不断除2,约为k次,因此k=logN 注:复杂度分析小窍门

这个时间复杂度为NlogN,还算比较优化,但还不是最优的方法,下面这个在线处理方法算是最优化的,时间复杂度T(N)=O(N),就算遍历完整个子列也需要O(N),因此这个算法是最优化的了。

4、在线处理

/*
作者:mys
功能:求最大子列和(在线处理)
*/
#include<stdio.h>
#include<stdlib.h>
#define N 1000

void main()
{
    int a[N] = { 0 }, i;
    for (i = 0; i < N; i++)
        a[i] = rand() % 10000;
    printf("onlineProcess=%d\n", onlineProcess(a,N));
    system("pause");
}

int onlineProcess(int a[], int n)
{
    int sum = 0, maxSum = 0;
    int i;
    for (i = 0; i < n; i++)
    {
        sum += a[i];//向右累加
        if (sum>maxSum)
            maxSum = sum;//更新结果
        else if (sum < 0)//如果当前子列和为负,则不可能使后面部分的值增大,因此舍去
            maxSum = 0;
    }
    return maxSum;
}

下图是这四个算法的运行时间比较

NA表示not avaliable,从上可看出分而治之O(NlogN)在线处理O(N) 算法还是比较好。

----------------------------------------------------------------------------------2018.7.23以上是我今天整理的数据结构的一点小小的笔记,以后还会继续更新^-^

原文地址:https://www.cnblogs.com/xq-mys/p/9353643.html

时间: 2024-10-16 15:12:13

数据结构(一)-----4种方法求最大子列和的相关文章

三种方法求最大子数组的和

这是一道考的烂的不能再烂的题目,但是依然有很多公司乐于将这样的题目作为笔试或面试题,足见其经典. 问题是这样的:一个整数数组中的元素有正有负,在该数组中找出一个连续子数组,要求该子数组中各元素的和最大,这个子数组便被称作最大子数组.比如数组{2,4,-7,5,2,-1,2,-4,3}的最大子数组为{5,2,-1,2},最大子数组的和为5+2-1+2=8. 下面按照时间复杂度逐步优化的顺序依次给出这三种算法. 暴力求解法 该方法的思想非常简单,先找出从第1个元素开始的最大子数组,而后再从第2个元素

两种方法求丑数

我们把只包含因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含因子7. 方法1 : 暴力破解,逐个判断 代码: <pre name="code" class="cpp">#include <iostream> #include <vector> using namespace std; //判断是否是丑数 bool isUgly(int index){ while(index % 2

归并排序,树状数组 两种方法求逆序对

我们知道,求逆序对最典型的方法就是树状数组,可是另一种方法就是Merge_sort(),即归并排序. 实际上归并排序的交换次数就是这个数组的逆序对个数,为什么呢? 我们能够这样考虑: 归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来. 在合并的过程中(设l<=i<=mid,mid+1<=j<=h).当a[i]<=a[j]时.并不产生逆序数:当a[i]>a[j]时.在 前半部分中比a[i]大的数都比a[j]

HDU 1013 Digital Roots(两种方法,求数字根)

Digital Roots Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 67949    Accepted Submission(s): 21237 Problem Description The digital root of a positive integer is found by summing the digits of

Math01: 两种方法求下三角矩阵的逆

方法一:单位矩阵消元 1 clear; 2 n = 500; 3 A = zeros(n,n); 4 for j = 1:n 5 for i = j:n 6 A(i,j) = (i + j)^2; 7 end 8 end 9 C = A; 10 B = eye(n); 11 12 for i = 1:(n-1) 13 B(i,:) = B(i,:)/A(i,i); 14 A(i,:) = A(i,:)/A(i,i); 15 for j = (i+1):n 16 B(j,:) = B(j,:) -

数据结构习题记录(1)——最大子列和问题

题目: 给定KK个整数组成的序列{ N_1N?1??, N_2N?2??, ..., N_KN?K?? },"连续子列"被定义为{ N_iN?i??, N_{i+1}N?i+1??, ..., N_jN?j?? },其中 1 \le i \le j \le K1≤i≤j≤K."最大子列和"则被定义为所有连续子列元素的和中最大者.例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20.现要求你编写程序,计

数据结构练习 01-复杂度1. 最大子列和问题(20)

给定K个整数组成的序列{ N1, N2, ..., NK },"连续子列"被定义为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K."最大子列和"则被定义为所有连续子列元素的和中最大者.例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20.现要求你编写程序,计算给定整数序列的最大子列和. 输入格式: 输入第1行给出正整数 K (<= 10000

两种方法求最大公约数最小公倍数

<pre name="code" class="cpp">/* *coyright(c)2014 龙城无泪 *All rights reserved *文件名称 digui.c *作者:封尘之魂 *完成日期:20141108 *版本号V1.0 *问题描述:求两个整数的最大公约数最小公倍数 *输入描述:输入两个整数 *输出描述:成功输出最大公约数最小公倍数 */ #include<stdio.h> int main() {int m,n,q,t

55. 2种方法求字符串的组合[string combination]

[本文链接] http://www.cnblogs.com/hellogiser/p/string-combination.html [题目] 题目:输入一个字符串,输出该字符串中字符的所有组合.举个例子,如果输入abc,它的组合有a.b.c.ab.ac.bc.abc. [分析] 在之前的博文28.字符串的排列[StringPermutation]中讨论了如何用递归的思路求字符串的排列.同样,本题也可以用递归的思路来求字符串的组合. [递归法求组合] 可以考虑求长度为n的字符串中m个字符的组合,