Givet et array arr[] af størrelse N , er opgaven at finde længden af den længste stigende delsekvens (LIS), dvs. den længst mulige delsekvens, hvor elementerne i delsekvensen er sorteret i stigende rækkefølge.

Længst stigende efterfølger
Eksempler:
Input: arr[] = {3, 10, 2, 1, 20}
Produktion: 3
Forklaring: Den længste stigende sekvens er 3, 10, 20Input: arr[] = {50, 3, 10, 7, 40, 80}
Produktion: 4
Forklaring: Den længste stigende sekvens er {3, 7, 40, 80}
hvad er modulo i c++Input: arr[] = {30, 20, 10}
Produktion: 1
Forklaring: De længst stigende undersekvenser er {30}, {20} og (10)Input: arr[] = {10, 20, 35, 80}
Produktion: 4
Forklaring: Hele arrayet er sorteret
Længste stigende sekvens ved hjælp af Rekursion :
Ideen om at krydse input-arrayet fra venstre mod højre og finde længden af den længste stigende subsequence (LIS), der slutter med hvert element arr[i]. Lad længden fundet for arr[i] være L[i]. Til sidst returnerer vi maksimum af alle L[i] værdier. Nu opstår spørgsmålet, hvordan beregner vi L[i]? Til dette bruger vi rekursion, vi betragter alle mindre elementer til venstre for arr[i], beregner rekursivt LIS-værdien for alle de mindre elementer til venstre, tager maksimum af alle og lægger 1 til det. Hvis der ikke er et mindre element til venstre for et element, returnerer vi 1.
Lade L(i) være længden af LIS, der slutter på indeks jeg sådan at arr[i] er det sidste element i LIS. Derefter kan L(i) skrives rekursivt som:
- L(i) = 1 + max(L(j) ) hvor 0
- L(i) = 1, hvis et sådant j ikke eksisterer.
Formelt er længden af LIS ender på indeks jeg , er 1 større end maksimum af længder af alle LIS, der slutter på et eller andet indeks j sådan at arr[j]
hvor j .
Vi kan se, at ovenstående gentagelsesforhold følger optimal underbygning ejendom.
Illustration:
forårets rammer
Følg nedenstående illustration for en bedre forståelse:
Overvej arr[] = {3, 10, 2, 11}
L(i): Angiver LIS af underarray, der slutter ved position 'i'
Rekursionstræ
Følg nedenstående trin for at implementere ovenstående idé:
- Opret en rekursiv funktion.
- For hvert rekursivt opkald, gentag fra i = 1 til den aktuelle position og gør følgende:
- Find den mulige længde af den længst stigende undersekvens, der slutter på den aktuelle position, hvis den forrige sekvens sluttede kl jeg .
- Opdater den maksimalt mulige længde i overensstemmelse hermed.
- Gentag dette for alle indekser og find svaret
Nedenfor er implementeringen af den rekursive tilgang:
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; } // Sammenlign max_ending_here med // overordnede max. Og opdater // overall max, hvis det er nødvendigt, hvis (*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; } // Sammenlign max_ending_here med den samlede // max. Og opdater det samlede max, hvis det er nødvendigt, hvis (*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; } // Sammenlign max_ending_here med det samlede max. Og // opdater det samlede max, hvis det er nødvendigt, hvis (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 # Sammenlign maxEndingHere med samlet maksimum. Og # opdater det overordnede maksimum om nødvendigt maksimum = max(maksimum, maxEndingHere) returner maxEndingHere def lis(arr): # For at tillade adgang til global variabel global maksimum # Længde af arr n = len(arr) # Maksimal variabel holder resultatet maksimum = 1 # Funktionen _lis() gemmer sit resultat i maksimum _lis(arr, n) returner maksimum # Driverprogram for at teste ovenstående funktion, hvis __name__ == '__main__': arr = [10, 22, 9, 33 , 21, 50, 41, 60] n = len(arr) # Funktionskald print('Længde af lis er', lis(arr)) # Denne kode er bidraget af NIKHIL KUMAR SINGH>
C# using System; // A Naive C# Program for LIS Implementation 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; } // Sammenlign max_ending_here med det overordnede max // og opdater det samlede max, hvis det er nødvendigt, hvis (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 >
Produktion
Length of lis is 5>
Tidskompleksitet: O(2n) Tidskompleksiteten af denne rekursive tilgang er eksponentiel, da der er tilfælde af overlappende underproblemer som forklaret i det rekursive trædiagram ovenfor.
Hjælpeplads: O(1). Der bruges ikke noget eksternt rum til lagring af værdier bortset fra det interne stabelrum.
Længst stigende sekvens ved hjælp af Memoisering :
Hvis det bemærkes nøje, kan vi se, at ovenstående rekursive løsning også følger overlappende delproblemer egenskab, dvs. samme understruktur løst igen og igen i forskellige rekursionsopkaldsveje. Vi kan undgå dette ved at bruge huskemetoden.
Vi kan se, at hver tilstand kan identificeres entydigt ved hjælp af to parametre:
- Nuværende indeks (betegner det sidste indeks af LIS) og
- Tidligere indeks (betegner slutindekset for den tidligere LIS, bag hvilken arr[i] bliver sammenkædet).
Nedenfor er implementeringen af ovenstående tilgang.
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); } returner dp[idx][prev_idx + 1] = max(take, notTake); } // Funktion til at finde længden af // længst stigende undersekvens int længstSubsequence(int n, int a[]) { vektor> dp(n + 1, vektor (n + 1, -1)); returner f(0, -1, n, a, dp); } // Driverprogram til at teste ovenstående funktion int main() { int a[] = { 3, 10, 2, 1, 20 }; int n = størrelse på(a) / størrelse på(a[0]); // Funktionskald 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); } // Indpakningsfunktionen for _lis() statisk int lis(int arr[], int n) { // Funktionen _lis() gemmer sit resultat i max int dp[][] = new int[n + 1][ n + 1]; for (int row[] : dp) Arrays.fill(row, -1); returner f(0, -1, n, arr, dp); } // Driverprogram til at teste ovenstående funktioner public static void main(String args[]) { int a[] = { 3, 10, 2, 1, 20 }; int n = a. længde; // Funktionskald System.out.println('Længde af lis er ' + lis(a, n)); } } // Denne kode er bidraget af Sanskar.>
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) returner dp[idx][prev_idx + 1] # Funktion til at finde længden af længst stigende # undersekvens. def længsteSubsequence(n, a): dp = [[-1 for i i interval(n + 1)]for j i interval(n + 1)] returner f(0, -1, n, a, dp) # Driver program til at teste ovenstående funktion hvis __navn__ == '__main__': a = [3, 10, 2, 1, 20] n = len(a) # Funktionskald print('Længde af lis er', længsteSubsequence( n, a)) # Denne kode er bidraget af shinjanpatra>
C# // C# approach to implementation the memoization approach using System; class GFG { // 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 public static int INT_MIN = -2147483648; public 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 = 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] = Math.Max(take, notTake); } // Funktion til at finde længden af længst stigende // efterfølger. public static int longestSubsequence(int n, int[] a) { int[, ] dp = new int[n + 1, n + 1]; for (int i = 0; i< n + 1; i++) { for (int j = 0; j < n + 1; j++) { dp[i, j] = -1; } } return f(0, -1, n, a, dp); } // Driver code static void Main() { int[] a = { 3, 10, 2, 1, 20 }; int n = a.Length; Console.WriteLine('Length of lis is ' + longestSubsequence(n, a)); } } // The code is contributed by Nidhi goel.>
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 til at finde længden af længst stigende // efterfølger. function longestSubsequence(n, a) { var dp = Array(n + 1) .fill() .map(() => Array(n + 1).fill(-1)); returner f(0, -1, n, a, dp); } /* Driverprogram til at teste ovenstående funktion */ var a = [3, 10, 2, 1, 20]; var n = 5; console.log('Længde af lis er ' + længsteSubsequence(n, a)); // Denne kode er bidraget af satwiksuman.>
Produktion
Length of lis is 3>
Tidskompleksitet: PÅ2)
Hjælpeplads: PÅ2)
Længst stigende sekvens ved hjælp af Dynamisk programmering :
På grund af optimal understruktur og overlappende delproblemegenskab kan vi også benytte Dynamisk programmering til at løse problemet. I stedet for memoisering kan vi bruge den indlejrede løkke til at implementere den rekursive relation.
Den ydre sløjfe vil løbe fra i = 1 til N og den indre løkke vil løbe fra j = 0 til i og bruge gentagelsesrelationen til at løse problemet.
Nedenfor er implementeringen af ovenstående tilgang:
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] og 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 >
Produktion
Length of lis is 5>
Tidskompleksitet: PÅ2) Som en indlejret løkke bruges.
Hjælpeplads: O(N) Brug af ethvert array til at gemme LIS-værdier ved hvert indeks.
df.loc
Bemærk: Tidskompleksiteten af ovenstående Dynamic Programming (DP) løsning er O(n^2), men der er en O(N* logN) opløsning for LIS-problemet. Vi har ikke diskuteret O(N log N)-løsningen her.
Henvise: Længst stigende sekvensstørrelse (N * logN) for den nævnte tilgang.