<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 最長遞增子序列大小(`N log N`) > 原文: [https://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/](https://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/) 給定一個隨機數數組。 在數組中找到最長的[遞增子序列](http://en.wikipedia.org/wiki/Substring)(LIS)。 我知道你們中許多人可能已經閱讀[遞歸和動態編程](https://www.geeksforgeeks.org/longest-increasing-subsequence-dp-3/)(DP)解決方案。 論壇帖子中很少有人要求[`O(N log N)`](http://en.wikipedia.org/wiki/Longest_increasing_subsequence#Efficient_algorithms)算法。 暫時,無需考慮遞歸和 DP 解決方案。 讓我們抽取少量樣本并將解決方案擴展到大型實例。 盡管乍一看可能很復雜,但是一旦我們理解了邏輯,編碼就很簡單。 考慮輸入數組`A = {2, 5, 3}`。 我將在解釋過程中擴展數組。 通過觀察,我們知道 LIS 是`{2, 3}`或`{2, 5}`。 **請注意,我僅考慮嚴格增加的序列**。 讓我們再添加兩個元素,例如 7、11。 這些元素將擴展現有序列。 現在,輸入數組`{2, 5, 3, 7, 11}`的遞增序列為`{2, 3, 7, 11}`和`{2, 5, 7, 11}`。 此外,我們在數組中再添加一個元素,例如 8,即輸入數組變為`{2, 5, 3, 7, 11, 11}`。 請注意,最新元素 8 大于任何活動序列的最小元素(*將簡短討論活動序列*)。 如何將現有序列擴展為 8? 首先,8 可以成為 LIS 的一部分嗎? 如果是,怎么辦? 如果我們要添加 8,它應該在 7 之后(通過替換 11)。 由于此方法是*脫機(我們的意思是[脫機](https://www.geeksforgeeks.org/median-of-stream-of-integers-running-integers/)嗎?)*,因此我們不確定是否添加 8 將擴展該系列。 假設輸入數組中有 9 個,例如`{2, 5, 3, 7, 11, 11, 8, 7, 9, …}`。 我們可以將 8 替換為 11,因為可能存在*最佳*候選(9),可以擴展新系列`{2, 3, 7, 8}`或`{2, 5, 7, 8}`。 我們的觀察結果是,假設最大序列的結尾元素為`E`。如果存在元素`A[j] (j > i)`,我們可以向現有序列中添加(替換)當前元素`E < A[i] < A[j]`或(`E > A[i] < A[j]` – 用于替換)。 在上面的示例中,`E = 11`,`A[i] = 8`,`A[j] = 9`。 對于原始數組`{2, 5, 3}`,請注意,當我們將 3 添加到遞增序列`{2, 5}`時,我們會遇到相同的情況。 我只是創建了兩個遞增的序列,以使說明變得簡單。 3 可以代替序列`{2, 5}`中的 5,而不是兩個序列。 我知道這會令人困惑,我會盡快清除它! *問題是,什么時候可以安全地添加或替換現有序列中的元素?* 讓我們考慮另一個樣本`A = {2, 5, 3}`。 假設下一個元素是 1。如何擴展當前序列`{2, 3}`或`{2, 5}`。 顯然,它也不能擴展。 但是,新的最小元素有可能成為 LIS 的開始。 為了清楚起見,請考慮數組為`{2, 5, 3, 1, 2, 3, 4, 5, 6}`。 將 1 設為新序列將創建最大的新序列。 *觀察結果是,當我們遇到數組中的新最小元素時,它可能是開始新序列的潛在候選者。* 從觀察中,我們需要維護遞增序列的列表。 總的來說,我們有一組**活動列表**不同長度。 我們將元素`A[i]`添加到這些列表中。 我們以長度減少的順序掃描列表(用于結束元素)。 我們將驗證所有列表的末端元素,以找到一個末端元素小于`A[i]`(*下限*值)的列表。 我們的策略由以下條件決定, ``` 1\. If A[i] is smallest among all *end* candidates of active lists, we will *start* new active list of length 1. ``` ``` 2\. If A[i] is largest among all *end* candidates of active lists, we will clone the *largest* active list, and extend it by A[i]. ``` ``` 3\. If A[i] is in between, we will find a list with *largest end element that is smaller than* A[i]. Clone and extend this list by A[i]. We will discard all other lists of same length as that of this modified list. ``` 請注意,在構造活動列表的任何時候,都將保持以下條件。 *“較小列表的末尾元素小于較大列表的末尾元素”* 。 舉一個很明顯的例子,使用 [Wiki](http://en.wikipedia.org/wiki/Longest_increasing_subsequence) `{0, 8, 4, 12, 2, 10, 6, 14, 1, 1, 9, 5, 13, 13, 3, 11, 7 , 15}`。 ``` A[0] = 0\. Case 1\. There are no active lists, create one. 0. ----------------------------------------------------------------------------- A[1] = 8\. Case 2\. Clone and extend. 0. 0, 8. ----------------------------------------------------------------------------- A[2] = 4\. Case 3\. Clone, extend and discard. 0. 0, 4. 0, 8. Discarded ----------------------------------------------------------------------------- A[3] = 12\. Case 2\. Clone and extend. 0. 0, 4. 0, 4, 12. ----------------------------------------------------------------------------- A[4] = 2\. Case 3\. Clone, extend and discard. 0. 0, 2. 0, 4. Discarded. 0, 4, 12. ----------------------------------------------------------------------------- A[5] = 10\. Case 3\. Clone, extend and discard. 0. 0, 2. 0, 2, 10. 0, 4, 12. Discarded. ----------------------------------------------------------------------------- A[6] = 6\. Case 3\. Clone, extend and discard. 0. 0, 2. 0, 2, 6. 0, 2, 10. Discarded. ----------------------------------------------------------------------------- A[7] = 14\. Case 2\. Clone and extend. 0. 0, 2. 0, 2, 6. 0, 2, 6, 14. ----------------------------------------------------------------------------- A[8] = 1\. Case 3\. Clone, extend and discard. 0. 0, 1. 0, 2. Discarded. 0, 2, 6. 0, 2, 6, 14. ----------------------------------------------------------------------------- A[9] = 9\. Case 3\. Clone, extend and discard. 0. 0, 1. 0, 2, 6. 0, 2, 6, 9. 0, 2, 6, 14. Discarded. ----------------------------------------------------------------------------- A[10] = 5\. Case 3\. Clone, extend and discard. 0. 0, 1. 0, 1, 5. 0, 2, 6. Discarded. 0, 2, 6, 9. ----------------------------------------------------------------------------- A[11] = 13\. Case 2\. Clone and extend. 0. 0, 1. 0, 1, 5. 0, 2, 6, 9. 0, 2, 6, 9, 13. ----------------------------------------------------------------------------- A[12] = 3\. Case 3\. Clone, extend and discard. 0. 0, 1. 0, 1, 3. 0, 1, 5. Discarded. 0, 2, 6, 9. 0, 2, 6, 9, 13. ----------------------------------------------------------------------------- A[13] = 11\. Case 3\. Clone, extend and discard. 0. 0, 1. 0, 1, 3. 0, 2, 6, 9. 0, 2, 6, 9, 11. 0, 2, 6, 9, 13. Discarded. ----------------------------------------------------------------------------- A[14] = 7\. Case 3\. Clone, extend and discard. 0. 0, 1. 0, 1, 3. 0, 1, 3, 7. 0, 2, 6, 9. Discarded. 0, 2, 6, 9, 11. ---------------------------------------------------------------------------- A[15] = 15\. Case 2\. Clone and extend. 0. 0, 1. 0, 1, 3. 0, 1, 3, 7. 0, 2, 6, 9, 11. 0, 2, 6, 9, 11, 15\. <-- LIS List ---------------------------------------------------------------------------- ``` 設計算法需要了解以上策略。 另外,確保我們保持以下條件:“較小列表的*結束元素小于較大列表*的結束元素”。 在進一步閱讀之前,請嘗試其他一些示例。 重要的是要了解結束元素發生了什么。 **算法**: 查詢最長的長度相當容易。 請注意,我們僅處理末端元素。 我們不需要維護所有列表。 我們可以將結束元素存儲在數組中。 丟棄操作可以通過替換進行模擬,并且擴展列表類似于向數組添加更多元素。 我們將使用輔助數組來保留結束元素。 該數組的最大長度是輸入的長度。 在最壞的情況下,數組會分成`N`個大小為 1 的列表(*注意,這不會導致最壞情況下的復雜性*)。 要丟棄一個元素,我們將在輔助數組中跟蹤`A[i]`的`ceil`值(再次觀察您的粗略工作中的末端元素),并將`ceil`值替換為`A[i]`。 我們通過將元素添加到輔助數組來擴展列表。 我們還維護一個計數器來跟蹤輔助數組的長度。 **Bonus:**?You have learnt?[Patience Sorting](http://en.wikipedia.org/wiki/Patience_sorting)?technique partially ?? Here is a proverb, “*Tell me and I will forget. Show me and I will remember. Involve me and I will understand*.” So, pick a suit from deck of cards. Find the longest increasing sub-sequence of cards from the shuffled suit. You will never forget the approach. ?? **更新 – 2016 年 7 月 17 日**:讀者們的回響頗為深刻,很少有網站引用此帖子,感到很高興,因為我為別人提供幫助而感到辛苦。 看來讀者在發表評論之前沒有做任何功課。 閱讀本文后要求閱讀一些示例,并請在紙上做您的工作(請勿使用編輯器/編譯器)。 要求是幫助自己。 對``知道''的專業不同于真正的理解(不尊重)。 以下是我的個人經歷。 *最初的內容準備工作大約花了我 6 個小時。 但是,這是一個很好的教訓。 我在一個小時內完成了初始代碼。 當我開始寫內容向讀者解釋時,我意識到我不理解這些案例。 拿了我的筆記本(我習慣于裝訂綁定的筆記本以跟蹤我的粗略工作),幾個小時后,我填寫了將近 15 頁的粗略工作。 無論您在灰色示例中看到的內容是來自這些頁面的。 我強烈建議您實踐《Udi Manber 算法入門》一書中的注釋觸發解決方案的所有思考過程。* 我懷疑,許多讀者可能無法理解`CeilIndex`(二分搜索)背后的邏輯。 我把它作為練習讓讀者理解它是如何工作的。 在紙上瀏覽幾個示例。 我意識到我已經在[另一篇文章](https://www.geeksforgeeks.org/the-ubiquitous-binary-search-set-1/)中介紹了該算法。 **更新 – 2016 年 8 月 5 日**: 完成工作后,以下鏈接值得參考。 我通過最近創建的 **Disqus** 個人資料認識了該鏈接。 該鏈接具有 Wiki 中提到的方法的說明。 [http://stackoverflow.com/questions/2631726/how-to-determine-the-longest-increasing-subsequence-using-dynamic-programming](http://stackoverflow.com/questions/2631726/how-to-determine-the-longest-increasing-subsequence-using-dynamic-programming) 下面給出的是查找 LIS 長度的代碼(*更新為 C++ 11 代碼,沒有 C 樣式的數組*), ## C++ ```cpp #include <iostream> #include <vector> // Binary search (note boundaries in the caller) int CeilIndex(std::vector<int>& v, int l, int r, int key) { ????while (r - l > 1) { ????????int m = l + (r - l) / 2; ????????if (v[m] >= key) ????????????r = m; ????????else ????????????l = m; ????} ????return r; } int LongestIncreasingSubsequenceLength(std::vector<int>& v) { ????if (v.size() == 0) ????????return 0; ????std::vector<int> tail(v.size(), 0); ????int length = 1; // always points empty slot in tail ????tail[0] = v[0]; ????for (size_t i = 1; i < v.size(); i++) { ????????// new smallest value ????????if (v[i] < tail[0]) ????????????tail[0] = v[i]; ????????// v[i] extends largest subsequence ????????else if (v[i] > tail[length - 1]) ????????????tail[length++] = v[i]; ????????// v[i] will become end candidate of an existing ????????// subsequence or Throw away larger elements in all ????????// LIS, to make room for upcoming grater elements ????????// than v[i] (and also, v[i] would have already ????????// appeared in one of LIS, identify the location ????????// and replace it) ????????else ????????????tail[CeilIndex(tail, -1, length - 1, v[i])] = v[i]; ????} ????return length; } int main() { ????std::vector<int> v{ 2, 5, 3, 7, 11, 8, 10, 13, 6 }; ????std::cout << "Length of Longest Increasing Subsequence is " ??????????????<< LongestIncreasingSubsequenceLength(v) << '\n'; ????return 0; } ``` ## Java ```java // Java program to find length of longest increasing subsequence // in O(n Log n) time import java.io.*; import java.util.*; import java.lang.Math; class LIS { ????// Binary search (note boundaries in the caller) ????// A[] is ceilIndex in the caller ????static int CeilIndex(int A[], int l, int r, int key) ????{ ????????while (r - l > 1) { ????????????int m = l + (r - l) / 2; ????????????if (A[m] >= key) ????????????????r = m; ????????????else ????????????????l = m; ????????} ????????return r; ????} ????static int LongestIncreasingSubsequenceLength(int A[], int size) ????{ ????????// Add boundary case, when array size is one ????????int[] tailTable = new int[size]; ????????int len; // always points empty slot ????????tailTable[0] = A[0]; ????????len = 1; ????????for (int i = 1; i < size; i++) { ????????????if (A[i] < tailTable[0]) ????????????????// new smallest value ????????????????tailTable[0] = A[i]; ????????????else if (A[i] > tailTable[len - 1]) ????????????????// A[i] wants to extend largest subsequence ????????????????tailTable[len++] = A[i]; ????????????else ????????????????// A[i] wants to be current end candidate of an existing ????????????????// subsequence. It will replace ceil value in tailTable ????????????????tailTable[CeilIndex(tailTable, -1, len - 1, A[i])] = A[i]; ????????} ????????return len; ????} ????// Driver program to test above function ????public static void main(String[] args) ????{ ????????int A[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 }; ????????int n = A.length; ????????System.out.println("Length of Longest Increasing Subsequence is " + LongestIncreasingSubsequenceLength(A, n)); ????} } /* This code is contributed by Devesh Agrawal*/ ``` ## Python3 ```py # Python program to find # length of longest # increasing subsequence # in O(n Log n) time # Binary search (note # boundaries in the caller) # A[] is ceilIndex # in the caller def CeilIndex(A, l, r, key): ????while (r - l > 1): ????????m = l + (r - l)//2 ????????if (A[m] >= key): ????????????r = m ????????else: ????????????l = m ????return r def LongestIncreasingSubsequenceLength(A, size): ????# Add boundary case, ????# when array size is one ????tailTable = [0 for i in range(size + 1)] ????len = 0 # always points empty slot ????tailTable[0] = A[0] ????len = 1 ????for i in range(1, size): ????????if (A[i] < tailTable[0]): ????????????# new smallest value ????????????tailTable[0] = A[i] ????????elif (A[i] > tailTable[len-1]): ????????????# A[i] wants to extend ????????????# largest subsequence ????????????tailTable[len] = A[i] ????????????len+= 1 ????????else: ????????????# A[i] wants to be current ????????????# end candidate of an existing ????????????# subsequence. It will replace ????????????# ceil value in tailTable ????????????tailTable[CeilIndex(tailTable, -1, len-1, A[i])] = A[i] ????return len # Driver program to # test above function A = [ 2, 5, 3, 7, 11, 8, 10, 13, 6 ] n = len(A) print("Length of Longest Increasing Subsequence is ", ???????LongestIncreasingSubsequenceLength(A, n)) # This code is contributed # by Anant Agarwal. ``` ## C# ```cs // C# program to find length of longest // increasing subsequence in O(n Log n) // time using System; class GFG { ????// Binary search (note boundaries ????// in the caller) A[] is ceilIndex ????// in the caller ????static int CeilIndex(int[] A, int l, ?????????????????????????int r, int key) ????{ ????????while (r - l > 1) { ????????????int m = l + (r - l) / 2; ????????????if (A[m] >= key) ????????????????r = m; ????????????else ????????????????l = m; ????????} ????????return r; ????} ????static int LongestIncreasingSubsequenceLength( ????????int[] A, int size) ????{ ????????// Add boundary case, when array size ????????// is one ????????int[] tailTable = new int[size]; ????????int len; // always points empty slot ????????tailTable[0] = A[0]; ????????len = 1; ????????for (int i = 1; i < size; i++) { ????????????if (A[i] < tailTable[0]) ????????????????// new smallest value ????????????????tailTable[0] = A[i]; ????????????else if (A[i] > tailTable[len - 1]) ????????????????// A[i] wants to extend largest ????????????????// subsequence ????????????????tailTable[len++] = A[i]; ????????????else ????????????????// A[i] wants to be current end ????????????????// candidate of an existing ????????????????// subsequence. It will replace ????????????????// ceil value in tailTable ????????????????tailTable[CeilIndex(tailTable, -1, ????????????????????????????????????len - 1, A[i])] ????????????????????= A[i]; ????????} ????????return len; ????} ????// Driver program to test above function ????public static void Main() ????{ ????????int[] A = { 2, 5, 3, 7, 11, 8, 10, 13, 6 }; ????????int n = A.Length; ????????Console.Write("Length of Longest " ??????????????????????+ "Increasing Subsequence is " + LongestIncreasingSubsequenceLength(A, n)); ????} } // This code is contributed by nitin mittal. ``` ## PHP ```php <?php // PHP program to find // length of longest // increasing subsequence // in O(n Log n) time // Binary search (note // boundaries in the caller) // A[] is ceilIndex // in the caller function CeilIndex($A, $l, $r, $key) { ????while ($r - $l > 1) ????{ ????????$m = (int)($l + ($r - $l)/2); ????????if ($A[$m] >= $key) ????????????$r = $m; ????????else ????????????$l = $m; ????} ????return $r; } function LongestIncreasingSubsequenceLength($A, $size) { ????// Add boundary case, ????// when array size is one ????$tailTable = array_fill(0, ($size + 1), 0); ????$len = 0; // always points empty slot ????$tailTable[0] = $A[0]; ????$len = 1; ????for($i = 1; $i < $size; $i++) ????{ ????????if ($A[$i] < $tailTable[0]) ????????????// new smallest value ????????????$tailTable[0] = $A[$i]; ????????else if ($A[$i] > $tailTable[$len-1]) ????????{ ????????????// A[i] wants to extend ????????????// largest subsequence ????????????$tailTable[$len] = $A[$i]; ????????????$len++; ????????} ????????else ????????????// A[i] wants to be current ????????????// end candidate of an existing ????????????// subsequence. It will replace ????????????// ceil value in tailTable ????????????$tailTable[CeilIndex($tailTable, -1, $len-1, $A[$i])] = $A[$i]; ????} ????return $len; } // Driver program to // test above function $A = array( 2, 5, 3, 7, 11, 8, 10, 13, 6 ); $n = count($A); print("Length of Longest Increasing Subsequence is ". ????????LongestIncreasingSubsequenceLength($A, $n)); // This code is contributed by chandan_jnu ?> ``` **輸出**: ``` Length of Longest Increasing Subsequence is 6 ``` **復雜度**: 循環運行`N`個元素。 在最壞的情況下(什么是最壞情況的輸入?),我們最終可能會使用二分搜索(`log i`)來查詢許多`A[i]`的`ceil`值。 因此,`T(n) < O(log N!)= O(N log N)`。 分析以確保上限和下限也是`O(N log N)`。 復雜度為`THETA(N log N)`。 **練習**: 1. [設計一種算法,以構造最長的遞增列表](https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/)。 另外,使用 DAG 對解決方案進行建模。 2. 設計一種算法,以構造**所有**的列表,這些列表具有相同的最長大小。 3. 上述算法是*在線*算法嗎? 4. 設計一種算法來構造最長的*遞減*列表。 [**在 C++ 中使用`lower_bound()`的替代實現**](https://www.geeksforgeeks.org/lower_bound-in-cpp/) ``` #include<bits/stdc++.h> using namespace std;? int LongestIncreasingSubsequenceLength(std::vector<int>& v)? {? ????if (v.size() == 0)? ????????return 0;? ????std::vector<int> tail(v.size(), 0);? ????int length = 1; // always points empty slot in tail? ????tail[0] = v[0];? ????for (int i = 1; i < v.size(); i++) {? ????????????// Do binary search for the element in? ????????????// the range from begin to begin + length ????????auto b = tail.begin(), e = tail.begin() + length; ????????auto it = lower_bound(b, e, v[i]);? ????????// If not present change the tail element to v[i]? ????????if (it == tail.begin() + length) ????????tail[length++] = v[i];? ????????else??? ????????*it = v[i];? ????}? ????return length;? }? int main()? {? ????std::vector<int> v{ 2, 5, 3, 7, 11, 8, 10, 13, 6 };? ????std::cout << "Length of Longest Increasing Subsequence is " ????????????<< LongestIncreasingSubsequenceLength(v);? ????return 0;? }? ``` 輸出: ``` Length of Longest Increasing Subsequence is 6 ``` — [Venki](http://www.linkedin.com/in/ramanawithu) 。 如果發現任何不正確的地方,或者想分享有關上述主題的更多信息,請寫評論。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看