算法优化例子

最大连续子序列和问题:给定(可能是负的)整数序列,寻找(并标识)的值为最大的序列。如果所有的整数都是负的,那么最大连续子序列的和是0。

1、典型的算法

最简单的算法是直接的穷尽查找,即蛮力算法(Brute Force Algorithm),找出所有子序列并求和,遍历所有求和结果找出最大值。

int maxSubsequenceSum(int a[], int &start, int &end){
    int size = sizeof(a)/sizeof(a[0]);
    int maxSum = 0;
    // 起始位置遍历
    for (int i=0; imaxSum){
                    maxSum = thisSum;
                    start = i;
                    end = j;
                }
            }
        }
    }
    return maxSum;
}

这一算法非常简单易于理解,最外层循环需要执行n次,第二层循环需要执行n-i次,第三层循环执行j-i次,由此可得时间复杂度为,即。
在该算法中嵌套循环几乎贡献了所有的时间复杂度,简单的理解一个循环有N的时间复杂度,那么三层嵌套就是N的三次方。

2、改进的算法

由蛮力算法可知,导致时间复杂度的主要是循环,通过减少循环就可以降低时间复杂度。分析蛮力算法可得,第三层循环计算thisSum有太多的重复步骤,没必要每次都重新求和,利用在第二层循环累加即可。

int maxSubsequenceSum(int a[], int &start, int &end){
    int size = sizeof(a)/sizeof(a[0]);
    int maxSum = 0;
    for (int i=0; imaxSum){
                maxSum = thisSum;
                start = i;
                end = j;
            }
        }
    }
    return maxSum;
}

由于循环只有两层,所以时间复杂度降低为。

3、线性算法
从平方算法降低到线性算法还需要再删除一个循环,但是平方算法降低到线性算法,不能只是简单的改变程序,需要思想。前两种算法本质上还是穷尽法,只不过有一些巧妙的改进,想要得到线性算法就需要改变思想。

可以通过分析来排除一些可能的子序列。如果一个子序列是负的,那么它绝对不会出现在最大连续子序列的开始部分,这非常容易理解,因为如果开始部分是负的,显然起到减小作用,为什么又要包含进去呢?以某一序列{a, b, c, d, e, f, g, h, i, j, k......y, z}为例,如果a是负的,肯定不会以a开头;如果cdef是负的,可以直接跳到g开始,可能会问为什么不从d开始呢?原因在于c肯定不会是负的,见a情况,那么整个是负的,c又是正的,那么def也肯定是负的,没有必要再考虑了。

int maxSubsequenceSum(int a[], int &start, int &end){
    int size = sizeof(a)/sizeof(a[0]);
    int maxSum = 0, thisSum = 0, start = 0;
    for (int i=0; imaxSum){
            maxSum = thisSum;
            end = i;
        }
    }
    return maxSum;
}

由于只用到一个至多循环n次的循环,所以是一个线性算法。

总结

算法效率提升有两种,一是程序上的优化,一是设计思想上的优化。思想上的优化是本质上的改变。

你可能感兴趣的:(算法优化例子)