算法分析--复杂度杂谈

算法分析

本文符号释义

常见的复杂度有

  • O(1):常量时间阶
  • O(n):线性时间阶
  • O(logn):对数时间阶
  • O(n*logn):线性对数时间阶
  • O (n^k):k≥2,k次方时间阶

下面书归正传 开始胡扯

算法分析第一个要解决的问题——What to analyze

衡量算法的一个重要指标就是runtime,影响runtime的因素有很多,比如使用的编译器,你的电脑本身存取速度读写速度等等,所以势必有其他可量化的,不受外界干扰的指标去多角度地衡量算法的好坏。

输入数据的大小是main consideration

预先定义两个函数Tavg(N) Tworst(N) 作为一般输入条件和最坏输入条件的runtime

明显的,Tavg(N)≤Tworst(N) 每多一组输出,这两个函数就多一种情况需要讨论

我们一般需要的是worst-case 的runtime来衡量算法的好坏(对应算法的健壮性,输入规模较大的数据时,输出不能崩)

让我们举个栗子

Given a sequence of K integers {N1,N2,...Nk}. A continuous subsequence is defined to be {Ni,Ni+1,...Nj} where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.

Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.

先把天书翻译出来

大意是给你一个序列,求这个序列的最大子序列和,并按以下格式打印结果。

最大子序列和 最大子序列中第一个数 最大子序列中最后一个数

解决这道题的算法有很多 此处不具体列举

下面一一分析它们的复杂度
| 算法| 1 |2 |3 | 4 |
| -----------: | -----------: | -----------: | -----------: | -----------: |
| 时间复杂度 |O(N3) |O(N2) |O(NlogN) |O(N) |
| 输入规模N=10 |0.00103 |0.00045 |0.00066 |0.00034 |
|N=100 |0.47015 |0.01112 |0.00486 |0.00063 |
|N=1000 |448.77 |1.1233 |0.05843 |0.00333 |
| N=10000| NA |111.13 |0.68631 |0.03042 |
| N=100000 | NA |NA |8.0113 |0.29832 |
该数据在MingW-w64编译器环境下测得

这道题放上我认为最优算法题解

#include <bits/stdc++.h>
using namespace std;
 
int main()
{
    int N;
    cin >> N;
    int a[N];
    //最大连续子序列和sum、临时的最大连续子序列和tempsum、临时的最大连续子序列的起始下标tempindex、最大连续子序列的起始下标start、最大连续子序列的结束下标end
    int sum = -1,tempsum = 0,tempindex = 0, start = 0, end = N-1;
    for(int i = 0; i < N; i++)
    {
        cin >> a[i];
        tempsum += a[i];
        if(tempsum < 0)
        {
            tempsum = 0;
            tempindex = i+1;
        }
        else if(tempsum > sum)
        {
            sum = tempsum;
            start = tempindex;
            end = i;
        }
    }
    if(sum == -1)
    {
        sum = 0;
    }
    cout << sum << " " << a[start] << " " << a[end];
    return 0;
}

runtime的估算

举个栗子
关于计算立方之和:1³+2³+3³+···+n³
最简单的大家都知道

int Sum(int n)
{
    int i,PatialSum;
    PartialSum = 0;//**1**
    for(i=1;i<=n;i++);//**2**
        PartialSum +=i*i*i;//**3**
   return PartialSum;//**4**
}

分析它很简单 1,4执行一次,运算一次

3每执行一次,运算四次 (两次✖,一次➕,还有一次assignment) 执行N次,运算4N次

其中2处有一处隐藏的时间消耗,因为要进行判断i与N的大小关系 所有的判断计入复杂度为N+1

每次对i执行自增,复杂度记作1 对总和进行相加,复杂度记作N

那么总复杂度是6N+4(忽略函数回调)

于是,我们得出结论:这个算法复杂度为O(N)


Rules for analyze

  • 对于for循环 复杂度为O(N)
  • 对于嵌套for循环 每个for循环的复杂度相乘
  • 连续语句
for(i=0;i<N;i++)
   A[i] = 0;
for (i = 0;i<N;i++)
    for(j=0lj<N;j++)
        A[i] +=A[j]+i+j;

O(n)紧接着O(N²) 那么总复杂度为O(N²)


1.29 先到这里了,要去摸鱼

猜你喜欢

转载自www.cnblogs.com/sqx-AC/p/12240244.html