1. 程式人生 > >轉載:一個一維數軸上有不同的線段,求重複最長的兩個線段

轉載:一個一維數軸上有不同的線段,求重複最長的兩個線段

例:a:1~3

    b:   2~7

    c:2~8

最長重複是b和c

像這種問題,一般就從動態規劃的角度去思考。將原問題分割成小問題。

首先按照線段的起點進行排序,較好的排序演算法的時間複雜度是O(nlogn)

然後考慮將原問題變為相同結構的子問題。考慮f(n)是前n條線段中重複最長的兩個線段的重複長度。現在減小問題規模到n-1,分析f(n)與f(n-1)的遞推公式。前n條線段的最長重複長度要麼與第n條線段無關,要麼與第n條線段有關。

1.如果與第n條線段無關,那麼很簡單,f(n) = f(n-1).

2.如果與第n條線段有關,那麼最長重複長度的兩個線段就是前面n-1條中的一條與第n條本身。由於前面已經按照線段的起始點進行了排序,故,重複部分的起點必然是第n條線段的起點,終點必定是某條線段的終點,其長度可以表示為end(x) - start(n),現在start是固定的,要使得長度最大,那麼必須end(x)最大,找到前面end最大的那條線段即可,其值記為max_end。當然,這裡考慮要更加細化,如果前面的end(x)比end(n)還大,那麼最大重複長度是end(n) - start(n);否則的話,最大長度就是end(x) - start(n).

現在,問題的解已經有比較明朗的遞推公式了f(n) = max{f(n-1), end(x) > end(n) ? end(n) - start(n): end(x) - start(n)}

f(1) = 0; max_end = end(1);

f(2) = end(2)>end(1)?end(1)-start(2):end(2)-start(2); max_end = max{max_end, end(2)};

從頭開始儲存當前線段i前面的f(i-1)以及max_end,直到n,即可求出f(n)。如要同時求出有最大重複長度的兩條線段,在遍歷過程中儲存這兩條線段的編號即可。

其時間複雜度,前面的排序是O(nlogn),後面只需一次掃描,O(n),故總的時間複雜度為O(nlogn)。空間複雜度,不考慮前面的排序演算法,後面只需常量的空間,故為O(1).