編程之法:面試和算法心得(最大連續乘積子串)

內容所有來自編程之法:面試和算法心得一書,實現是本身寫的使用的是java

題目描述

給一個浮點數序列,取最大乘積連續子串的值,例如 -2.5,4,0,3,0.5,8,-1,則取出的最大乘積連續子串爲3,0.5,8。也就是說,上述數組中,3 0.5 8這3個數的乘積30.58=12是最大的,並且是連續的。java

分析與解法

此最大乘積連續子串與最大乘積子序列不一樣,請勿混淆,前者子串要求連續,後者子序列不要求連續。也就是說,最長公共子串(Longest CommonSubstring)和最長公共子序列(LongestCommon Subsequence,LCS)是:面試

  • 子串(Substring)是串的一個連續的部分,
  • 子序列(Subsequence)則是從不改變序列的順序,而從序列中去掉任意的元素而得到的新序列;

更簡略地說,前者(子串)的字符的位置必須連續,後者(子序列LCS)則沒必要。好比字符串「 acdfg 」同「 akdfc 」的最長公共子串爲「 df 」,而它們的最長公共子序列LCS是「 adf 」,LCS可使用動態規劃法解決。算法

解法一

或許,讀者初看此題,可能立馬會想到用最簡單粗暴的方式:兩個for循環直接輪詢。編程

但這種蠻力的方法的時間複雜度爲O(n^2),可否想辦法下降時間複雜度呢?數組

解法二

考慮到乘積子序列中有正有負也還可能有0,咱們能夠把問題簡化成這樣:數組中找一個子序列,使得它的乘積最大;同時找一個子序列,使得它的乘積最小(負數的狀況)。由於雖然咱們只要一個最大積,但因爲負數的存在,咱們同時找這兩個乘積作起來反而方便。也就是說,不但記錄最大乘積,也要記錄最小乘積。markdown

假設數組爲a[],直接利用動態規劃來求解,考慮到可能存在負數的狀況,咱們用maxend來表示以a[i]結尾的最大連續子串的乘積值,用minend表示以a[i]結尾的最小的子串的乘積值,那麼狀態轉移方程爲:spa

maxend = max(max(maxend * a[i], minend * a[i]), a[i]); minend = min(min(maxend * a[i], minend * a[i]), a[i]); 

初始狀態爲maxend = minend = a[0]。code

參考代碼以下:blog

 public static double  maxProductSubstring(double[] a)
    {
        double maxEnd = a[0];
        double minEnd = a[0];
        double maxResult = a[0];
        for (int i = 1; i < a.length; ++i)
        {
            double end1 = maxEnd * a[i], end2 = minEnd * a[i];
            maxEnd = Math.max(Math.max(end1, end2), a[i]);
            minEnd = Math.min(Math.min(end1, end2), a[i]);
            maxResult = Math.max(maxResult, maxEnd);
        }
        return maxResult;
    }

 

動態規劃求解的方法一個for循環搞定,因此時間複雜度爲O(n)。字符串

相關文章
相關標籤/搜索