Gegeben ein Array arr[] der Größe N Die Aufgabe besteht darin, die Länge der längsten ansteigenden Teilsequenz (LIS) zu ermitteln, d. h. der längstmöglichen Teilsequenz, in der die Elemente der Teilsequenz in aufsteigender Reihenfolge sortiert sind.

Längste ansteigende Folge
Beispiele:
Eingang: arr[] = {3, 10, 2, 1, 20}
Ausgabe: 3
Erläuterung: Die am längsten ansteigende Teilfolge ist 3, 10, 20Eingang: arr[] = {50, 3, 10, 7, 40, 80}
Ausgabe: 4
Erläuterung: Die am längsten ansteigende Teilfolge ist {3, 7, 40, 80}
Eingang: arr[] = {30, 20, 10}
Ausgabe: 1
Erläuterung: Die am längsten ansteigenden Teilfolgen sind {30}, {20} und (10)zufällig nicht in JavaEingang: arr[] = {10, 20, 35, 80}
Ausgabe: 4
Erläuterung: Das gesamte Array wird sortiert
Längste ansteigende Sequenz mit Rekursion :
Die Idee, das Eingabearray von links nach rechts zu durchlaufen und die Länge der längsten ansteigenden Teilsequenz (LIS) zu ermitteln, die mit jedem Element arr[i] endet. Die für arr[i] gefundene Länge sei L[i]. Am Ende geben wir das Maximum aller L[i]-Werte zurück. Nun stellt sich die Frage: Wie berechnen wir L[i]? Dazu verwenden wir eine Rekursion, betrachten alle kleineren Elemente links von arr[i], berechnen rekursiv den LIS-Wert für alle kleineren Elemente links, nehmen das Maximum von allen und addieren 1 dazu. Wenn links von einem Element kein kleineres Element vorhanden ist, geben wir 1 zurück.
10 Millionen
Lassen L(i) sei die Länge des LIS, das am Index endet ich sodass arr[i] das letzte Element des LIS ist. Dann kann L(i) rekursiv geschrieben werden als:
- L(i) = 1 + max(L(j) ) wobei 0
- L(i) = 1, falls kein solches j existiert.
Formal die Länge von LIS, die beim Index endet ich ist um 1 größer als die maximale Länge aller LIS, die an einem bestimmten Index enden J so dass arr[j]
Wo J .
Wir können sehen, dass die obige Wiederholungsbeziehung dem folgt Optimaler Unterbau Eigentum.
Illustration:
Befolgen Sie zum besseren Verständnis die folgende Abbildung:
Betrachten Sie arr[] = {3, 10, 2, 11}
L(i): Bezeichnet LIS des Subarrays, das an Position „i“ endet
Rekursionsbaum
Befolgen Sie die unten aufgeführten Schritte, um die obige Idee umzusetzen:
- Erstellen Sie eine rekursive Funktion.
- Iterieren Sie für jeden rekursiven Aufruf von ich = 1 zur aktuellen Position und gehen Sie wie folgt vor:
- Finden Sie die mögliche Länge der längsten ansteigenden Teilsequenz, die an der aktuellen Position endet, wenn die vorherige Sequenz dort endete ich .
- Aktualisieren Sie die maximal mögliche Länge entsprechend.
- Wiederholen Sie dies für alle Indizes und finden Sie die Antwort
Unten ist die Implementierung des rekursiven Ansatzes:
C++ // A Naive C++ recursive implementation // of LIS problem #include using namespace std; // To make use of recursive calls, this // function must return two things: // 1) Length of LIS ending with element // arr[n-1]. // We use max_ending_here for this purpose // 2) Overall maximum as the LIS may end // with an element before arr[n-1] max_ref // is used this purpose. // The value of LIS of full array of size // n is stored in *max_ref which is // our final result int _lis(int arr[], int n, int* max_ref) { // Base case if (n == 1) return 1; // 'max_ending_here' is length of // LIS ending with arr[n-1] int res, max_ending_here = 1; // Recursively get all LIS ending with // arr[0], arr[1] ... arr[n-2]. If // arr[i-1] is smaller than arr[n-1], // and max ending with arr[n-1] needs // to be updated, then update it for (int i = 1; i < n; i++) { res = _lis(arr, i, max_ref); if (arr[i - 1] < arr[n - 1] && res + 1>max_ending_here) max_ending_here = res + 1; } // Vergleiche max_ending_here mit dem // Gesamtmaximum. Und aktualisieren Sie bei Bedarf // das Gesamtmaximum, wenn (*max_ref< max_ending_here) *max_ref = max_ending_here; // Return length of LIS ending // with arr[n-1] return max_ending_here; } // The wrapper function for _lis() int lis(int arr[], int n) { // The max variable holds the result int max = 1; // The function _lis() stores its // result in max _lis(arr, n, &max); // Returns max return max; } // Driver program to test above function int main() { int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = sizeof(arr) / sizeof(arr[0]); // Function call cout << 'Length of lis is ' << lis(arr, n); return 0; }>
C // A Naive C recursive implementation // of LIS problem #include #include // To make use of recursive calls, this // function must return two things: // 1) Length of LIS ending with element arr[n-1]. // We use max_ending_here for this purpose // 2) Overall maximum as the LIS may end with // an element before arr[n-1] max_ref is // used this purpose. // The value of LIS of full array of size n // is stored in *max_ref which is our final result int _lis(int arr[], int n, int* max_ref) { // Base case if (n == 1) return 1; // 'max_ending_here' is length of LIS // ending with arr[n-1] int res, max_ending_here = 1; // Recursively get all LIS ending with arr[0], // arr[1] ... arr[n-2]. If arr[i-1] is smaller // than arr[n-1], and max ending with arr[n-1] // needs to be updated, then update it for (int i = 1; i < n; i++) { res = _lis(arr, i, max_ref); if (arr[i - 1] < arr[n - 1] && res + 1>max_ending_here) max_ending_here = res + 1; } // Vergleiche max_ending_here mit dem gesamten // max. Und aktualisieren Sie bei Bedarf das Gesamtmaximum, wenn (*max_ref< max_ending_here) *max_ref = max_ending_here; // Return length of LIS ending with arr[n-1] return max_ending_here; } // The wrapper function for _lis() int lis(int arr[], int n) { // The max variable holds the result int max = 1; // The function _lis() stores its result in max _lis(arr, n, &max); // returns max return max; } // Driver program to test above function int main() { int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = sizeof(arr) / sizeof(arr[0]); // Function call printf('Length of lis is %d', lis(arr, n)); return 0; }>
Java // A Naive Java Program for LIS Implementation import java.io.*; import java.util.*; class LIS { // Stores the LIS static int max_ref; // To make use of recursive calls, this function must // return two things: 1) Length of LIS ending with // element arr[n-1]. We use max_ending_here for this // purpose 2) Overall maximum as the LIS may end with an // element before arr[n-1] max_ref is used this purpose. // The value of LIS of full array of size n is stored in // *max_ref which is our final result static int _lis(int arr[], int n) { // Base case if (n == 1) return 1; // 'max_ending_here' is length of LIS ending with // arr[n-1] int res, max_ending_here = 1; // Recursively get all LIS ending with arr[0], // arr[1] ... arr[n-2]. If arr[i-1] is smaller // than arr[n-1], and max ending with arr[n-1] needs // to be updated, then update it for (int i = 1; i < n; i++) { res = _lis(arr, i); if (arr[i - 1] < arr[n - 1] && res + 1>max_ending_here) max_ending_here = res + 1; } // Vergleiche max_ending_here mit dem Gesamtmaximum. Und // das Gesamtmaximum bei Bedarf aktualisieren, wenn (max_ref< max_ending_here) max_ref = max_ending_here; // Return length of LIS ending with arr[n-1] return max_ending_here; } // The wrapper function for _lis() static int lis(int arr[], int n) { // The max variable holds the result max_ref = 1; // The function _lis() stores its result in max _lis(arr, n); // Returns max return max_ref; } // Driver program to test above functions public static void main(String args[]) { int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = arr.length; // Function call System.out.println('Length of lis is ' + lis(arr, n)); } } // This code is contributed by Rajat Mishra>
Python # A naive Python implementation of LIS problem # Global variable to store the maximum global maximum # To make use of recursive calls, this function must return # two things: # 1) Length of LIS ending with element arr[n-1]. We use # max_ending_here for this purpose # 2) Overall maximum as the LIS may end with an element # before arr[n-1] max_ref is used this purpose. # The value of LIS of full array of size n is stored in # *max_ref which is our final result def _lis(arr, n): # To allow the access of global variable global maximum # Base Case if n == 1: return 1 # maxEndingHere is the length of LIS ending with arr[n-1] maxEndingHere = 1 # Recursively get all LIS ending with # arr[0], arr[1]..arr[n-2] # If arr[i-1] is smaller than arr[n-1], and # max ending with arr[n-1] needs to be updated, # then update it for i in range(1, n): res = _lis(arr, i) if arr[i-1] < arr[n-1] and res+1>maxEndingHere: maxEndingHere = res + 1 # Vergleiche maxEndingHere mit dem Gesamtmaximum. Und # das Gesamtmaximum bei Bedarf aktualisieren. Maximum = max(maximum, maxEndingHere) return maxEndingHere def lis(arr): # Um den Zugriff der globalen Variablen zu ermöglichen. Global Maximum # Länge von arr n = len(arr) # Maximum-Variable enthält das Ergebnis Maximum = 1 # Die Funktion _lis() speichert ihr Ergebnis in Maximum _lis(arr, n) return Maximum # Treiberprogramm zum Testen der obigen Funktion, wenn __name__ == '__main__': arr = [10, 22, 9, 33 , 21, 50, 41, 60] n = len(arr) # Funktionsaufruf print('Länge von lis ist', lis(arr)) # Dieser Code wurde von NIKHIL KUMAR SINGH>'> beigesteuertC#max_ending_here) max_ending_here = res + 1; } // Vergleiche max_ending_here mit dem Gesamtmaximum // und aktualisiere das Gesamtmaximum bei Bedarf, wenn (max_ref< max_ending_here) max_ref = max_ending_here; // Return length of LIS ending with arr[n-1] return max_ending_here; } // The wrapper function for _lis() static int lis(int[] arr, int n) { // The max variable holds the result max_ref = 1; // The function _lis() stores its result in max _lis(arr, n); // Returns max return max_ref; } // Driver program to test above functions public static void Main() { int[] arr = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = arr.Length; // Function call Console.Write('Length of lis is ' + lis(arr, n) + '
'); } }>
Javascript >
Ausgabe
Length of lis is 5>
Zeitkomplexität: O(2N) Die zeitliche Komplexität dieses rekursiven Ansatzes ist exponentiell, da es zu überlappenden Teilproblemen kommt, wie im obigen rekursiven Baumdiagramm erläutert.
Hilfsraum: O(1). Abgesehen vom internen Stapelspeicher wird kein externer Speicherplatz zum Speichern von Werten verwendet.
Längste ansteigende Teilsequenz mit Auswendiglernen :
Wenn wir genau hinsehen, können wir erkennen, dass die obige rekursive Lösung auch dem folgt überlappende Teilprobleme Eigenschaft, d. h. dieselbe Unterstruktur wird immer wieder in verschiedenen Rekursionsaufrufpfaden gelöst. Mit dem Memoisierungsansatz können wir dies vermeiden.
Wir können sehen, dass jeder Zustand anhand von zwei Parametern eindeutig identifiziert werden kann:
Palindrom in Java
- Aktueller Index (bezeichnet den letzten Index des LIS) und
- Vorheriger Index (bezeichnet den Endindex des vorherigen LIS, hinter dem die arr[i] wird verkettet).
Nachfolgend finden Sie die Umsetzung des oben genannten Ansatzes.
C++ // C++ code of memoization approach for LIS #include using namespace std; // To make use of recursive calls, this // function must return two things: // 1) Length of LIS ending with element // arr[n-1]. // We use max_ending_here for this purpose // Overall maximum as the LIS may end with // an element before arr[n-1] max_ref is // used this purpose. // The value of LIS of full array of size // n is stored in *max_ref which is // our final result int f(int idx, int prev_idx, int n, int a[], vector>& dp) { if (idx == n) { return 0; } if (dp[idx][prev_idx + 1] != -1) { return dp[idx][prev_idx + 1]; } int notTake = 0 + f(idx + 1, prev_idx, n, a, dp); int take = INT_MIN; if (prev_idx == -1 || a[idx]> a[prev_idx]) { take = 1 + f(idx + 1, idx, n, a, dp); } return dp[idx][prev_idx + 1] = max(take, notTake); } // Funktion zum Ermitteln der Länge // der längsten ansteigenden Teilsequenz int longestSubsequence(int n, int a[]) { vector> dp(n + 1, Vektor (n + 1, -1)); return f(0, -1, n, a, dp); } // Treiberprogramm zum Testen der obigen Funktion int main() { int a[] = { 3, 10, 2, 1, 20 }; int n = sizeof(a) / sizeof(a[0]); // Funktionsaufruf cout<< 'Length of lis is ' << longestSubsequence(n, a); return 0; }>
Java // A Memoization Java Program for LIS Implementation import java.lang.*; import java.util.Arrays; class LIS { // To make use of recursive calls, this function must // return two things: 1) Length of LIS ending with // element arr[n-1]. We use max_ending_here for this // purpose 2) Overall maximum as the LIS may end with an // element before arr[n-1] max_ref is used this purpose. // The value of LIS of full array of size n is stored in // *max_ref which is our final result static int f(int idx, int prev_idx, int n, int a[], int[][] dp) { if (idx == n) { return 0; } if (dp[idx][prev_idx + 1] != -1) { return dp[idx][prev_idx + 1]; } int notTake = 0 + f(idx + 1, prev_idx, n, a, dp); int take = Integer.MIN_VALUE; if (prev_idx == -1 || a[idx]>a[prev_idx]) { take = 1 + f(idx + 1, idx, n, a, dp); } return dp[idx][prev_idx + 1] = Math.max(take, notTake); } // Die Wrapper-Funktion für _lis() static int lis(int arr[], int n) { // Die Funktion _lis() speichert ihr Ergebnis in max int dp[][] = new int[n + 1][ n + 1]; for (int row[] : dp) Arrays.fill(row, -1); return f(0, -1, n, arr, dp); } // Treiberprogramm zum Testen der oben genannten Funktionen public static void main(String args[]) { int a[] = { 3, 10, 2, 1, 20 }; int n = a.length; // Funktionsaufruf System.out.println('Length of lis is ' + lis(a, n)); } } // Dieser Code wurde von Sanskar beigesteuert.>
Python # A Naive Python recursive implementation # of LIS problem import sys # To make use of recursive calls, this # function must return two things: # 1) Length of LIS ending with element arr[n-1]. # We use max_ending_here for this purpose # 2) Overall maximum as the LIS may end with # an element before arr[n-1] max_ref is # used this purpose. # The value of LIS of full array of size n # is stored in *max_ref which is our final result def f(idx, prev_idx, n, a, dp): if (idx == n): return 0 if (dp[idx][prev_idx + 1] != -1): return dp[idx][prev_idx + 1] notTake = 0 + f(idx + 1, prev_idx, n, a, dp) take = -sys.maxsize - 1 if (prev_idx == -1 or a[idx]>a[prev_idx]): take = 1 + f(idx + 1, idx, n, a, dp) dp[idx][prev_idx + 1] = max(take, notTake) return dp[idx][prev_idx + 1] # Funktion zum Ermitteln der Länge der am längsten # aufsteigenden Teilsequenz. def longestSubsequence(n, a): dp = [[-1 for i in range(n + 1)]for j in range(n + 1)] return f(0, -1, n, a, dp) # Driver Programm zum Testen der obigen Funktion, wenn __name__ == '__main__': a = [3, 10, 2, 1, 20] n = len(a) # Function call print('Length of lis is', longestSubsequence( n, a)) # Dieser Code wurde von Shinjanpatra>'> beigesteuertC#
Javascript /* A Naive Javascript recursive implementation of LIS problem */ /* To make use of recursive calls, this function must return two things: 1) Length of LIS ending with element arr[n-1]. We use max_ending_here for this purpose 2) Overall maximum as the LIS may end with an element before arr[n-1] max_ref is used this purpose. The value of LIS of full array of size n is stored in *max_ref which is our final result */ function f(idx, prev_idx, n, a, dp) { if (idx == n) { return 0; } if (dp[idx][prev_idx + 1] != -1) { return dp[idx][prev_idx + 1]; } var notTake = 0 + f(idx + 1, prev_idx, n, a, dp); var take = Number.MIN_VALUE; if (prev_idx == -1 || a[idx]>a[prev_idx]) { take = 1 + f(idx + 1, idx, n, a, dp); } return (dp[idx][prev_idx + 1] = Math.max(take, notTake)); } // Funktion zum Ermitteln der Länge der am längsten ansteigenden // Teilsequenz. function longestSubsequence(n, a) { var dp = Array(n + 1) .fill() .map(() => Array(n + 1).fill(-1)); return f(0, -1, n, a, dp); } /* Treiberprogramm zum Testen der obigen Funktion */ var a = [3, 10, 2, 1, 20]; var n = 5; console.log('Länge von lis ist ' + longestSubsequence(n, a)); // Dieser Code wurde von satwiksuman beigesteuert.>
Ausgabe
Length of lis is 3>
Zeitkomplexität: AN2)
Hilfsraum: AN2)
Längste ansteigende Teilsequenz mit Dynamische Programmierung :
Aufgrund der optimalen Unterstruktur und der überlappenden Teilproblemeigenschaften können wir auch dynamische Programmierung zur Lösung des Problems nutzen. Anstelle der Memoisierung können wir die verschachtelte Schleife verwenden, um die rekursive Beziehung zu implementieren.
Die äußere Schleife wird ausgeführt i = 1 bis N und die innere Schleife wird ausgeführt j = 0 bis i und verwenden Sie die Wiederholungsbeziehung, um das Problem zu lösen.
Schauspieler Rekha
Nachfolgend finden Sie die Umsetzung des oben genannten Ansatzes:
C++ // Dynamic Programming C++ implementation // of LIS problem #include using namespace std; // lis() returns the length of the longest // increasing subsequence in arr[] of size n int lis(int arr[], int n) { int lis[n]; lis[0] = 1; // Compute optimized LIS values in // bottom up manner for (int i = 1; i < n; i++) { lis[i] = 1; for (int j = 0; j < i; j++) if (arr[i]>arr[j] && lis[i]< lis[j] + 1) lis[i] = lis[j] + 1; } // Return maximum value in lis[] return *max_element(lis, lis + n); } // Driver program to test above function int main() { int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = sizeof(arr) / sizeof(arr[0]); // Function call printf('Length of lis is %d
', lis(arr, n)); return 0; }>
Java // Dynamic Programming Java implementation // of LIS problem import java.lang.*; class LIS { // lis() returns the length of the longest // increasing subsequence in arr[] of size n static int lis(int arr[], int n) { int lis[] = new int[n]; int i, j, max = 0; // Initialize LIS values for all indexes for (i = 0; i < n; i++) lis[i] = 1; // Compute optimized LIS values in // bottom up manner for (i = 1; i < n; i++) for (j = 0; j < i; j++) if (arr[i]>arr[j] && lis[i]< lis[j] + 1) lis[i] = lis[j] + 1; // Pick maximum of all LIS values for (i = 0; i < n; i++) if (max < lis[i]) max = lis[i]; return max; } // Driver code public static void main(String args[]) { int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = arr.length; // Function call System.out.println('Length of lis is ' + lis(arr, n)); } } // This code is contributed by Rajat Mishra>
Python # Dynamic programming Python implementation # of LIS problem # lis returns length of the longest # increasing subsequence in arr of size n def lis(arr): n = len(arr) # Declare the list (array) for LIS and # initialize LIS values for all indexes lis = [1]*n # Compute optimized LIS values in bottom up manner for i in range(1, n): for j in range(0, i): if arr[i]>arr[j] und lis[i]< lis[j] + 1: lis[i] = lis[j]+1 # Initialize maximum to 0 to get # the maximum of all LIS maximum = 0 # Pick maximum of all LIS values for i in range(n): maximum = max(maximum, lis[i]) return maximum # Driver program to test above function if __name__ == '__main__': arr = [10, 22, 9, 33, 21, 50, 41, 60] print('Length of lis is', lis(arr)) # This code is contributed by Nikhil Kumar Singh>
C# // Dynamic Programming C# implementation of LIS problem using System; class LIS { // lis() returns the length of the longest increasing // subsequence in arr[] of size n static int lis(int[] arr, int n) { int[] lis = new int[n]; int i, j, max = 0; // Initialize LIS values for all indexes for (i = 0; i < n; i++) lis[i] = 1; // Compute optimized LIS values in bottom up manner for (i = 1; i < n; i++) for (j = 0; j < i; j++) if (arr[i]>arr[j] && lis[i]< lis[j] + 1) lis[i] = lis[j] + 1; // Pick maximum of all LIS values for (i = 0; i < n; i++) if (max < lis[i]) max = lis[i]; return max; } // Driver code public static void Main() { int[] arr = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = arr.Length; // Function call Console.WriteLine('Length of lis is ' + lis(arr, n)); } } // This code is contributed by Ryuga>
Javascript >
Ausgabe
Length of lis is 5>
Zeitkomplexität: AN2) Da eine verschachtelte Schleife verwendet wird.
Hilfsraum: O(N) Verwendung eines beliebigen Arrays zum Speichern von LIS-Werten an jedem Index.
Notiz: Die zeitliche Komplexität der oben genannten Dynamic Programming (DP)-Lösung beträgt O(n^2), aber es gibt eine O(N* logN) Lösung für das LIS-Problem. Wir haben die O(N log N)-Lösung hier nicht diskutiert.
Verweisen: Längste zunehmende Teilsequenzgröße (N * logN) für den genannten Ansatz.