Gitt en matrise arr[] av størrelse N , er oppgaven å finne lengden på den lengste økende delsekvensen (LIS), dvs. den lengste mulige delsekvensen der elementene i delsekvensen er sortert i økende rekkefølge.

Lengst økende etterfølge
Eksempler:
Inndata: arr[] = {3, 10, 2, 1, 20}
Produksjon: 3
Forklaring: Den lengste økende undersekvensen er 3, 10, 20Inndata: arr[] = {50, 3, 10, 7, 40, 80}
Produksjon: 4
Forklaring: Den lengste økende undersekvensen er {3, 7, 40, 80}
dele en streng i c++Inndata: arr[] = {30, 20, 10}
Produksjon: 1
Forklaring: De lengste økende undersekvensene er {30}, {20} og (10)Inndata: arr[] = {10, 20, 35, 80}
Produksjon: 4
Forklaring: Hele matrisen er sortert
Lengste økende sekvens ved hjelp av Rekursjon :
Ideen om å krysse inngangsmatrisen fra venstre til høyre og finne lengden på den lengste økende undersekvensen (LIS) som slutter med hvert element arr[i]. La lengden funnet for arr[i] være L[i]. På slutten returnerer vi maksimum av alle L[i]-verdier. Nå oppstår spørsmålet, hvordan beregner vi L[i]? For dette bruker vi rekursjon, vi vurderer alle mindre elementer til venstre for arr[i], beregner rekursivt LIS-verdien for alle de mindre elementene til venstre, tar maksimum av alle og legger til 1 til den. Hvis det ikke er noe mindre element til venstre for et element, returnerer vi 1.
La L(i) være lengden på LIS som slutter på indeks Jeg slik at arr[i] er det siste elementet i LIS. Deretter kan L(i) skrives rekursivt som:
- L(i) = 1 + maks(L(j) ) hvor 0
- L(i) = 1, hvis ingen slik j eksisterer.
Formelt slutter lengden på LIS på indeks Jeg , er 1 større enn maksimum av lengder for alle LIS som slutter på en eller annen indeks j slik at arr[j]
hvor j .
Vi kan se at gjentakelsesrelasjonen ovenfor følger optimal underbygning eiendom.
Illustrasjon:
uri vs url
Følg illustrasjonen nedenfor for en bedre forståelse:
Tenk på arr[] = {3, 10, 2, 11}
L(i): Angir LIS til undermatrise som slutter på posisjon 'i'
Rekursjonstre
Følg trinnene nevnt nedenfor for å implementere ideen ovenfor:
- Lag en rekursiv funksjon.
- For hvert rekursivt anrop, Iterer fra i = 1 til gjeldende posisjon og gjør følgende:
- Finn den mulige lengden på den lengste økende undersekvensen som slutter på gjeldende posisjon hvis den forrige sekvensen endte kl Jeg .
- Oppdater maksimalt mulig lengde tilsvarende.
- Gjenta dette for alle indekser og finn svaret
Nedenfor er implementeringen av den rekursive tilnærmingen:
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 // totalt maks. Og oppdater // overall max hvis nødvendig 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 total // max. Og oppdater den totale maks om nødvendig 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 totale maks. Og // oppdater den totale maks om nødvendig 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 totalt maksimum. Og # oppdater det totale maksimumet om nødvendig maksimum = maks(maksimum, maksEndingHere) returner maxEndingHere def lis(arr): # For å tillate tilgang til global variabel global maksimum # Lengde på arr n = len(arr) # Maksimal variabel holder resultatet maksimum = 1 # Funksjonen _lis() lagrer resultatet i maksimum _lis(arr, n) returner maksimum # Driverprogram for å teste funksjonen ovenfor hvis __name__ == '__main__': arr = [10, 22, 9, 33 , 21, 50, 41, 60] n = len(arr) # Function call print('Length of lis is', lis(arr)) # Denne koden er bidratt med 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 den totale maks // og oppdater den totale maks om nødvendig 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 >
Produksjon
Length of lis is 5>
Tidskompleksitet: O(2n) Tidskompleksiteten til denne rekursive tilnærmingen er eksponentiell ettersom det er et tilfelle av overlappende delproblemer som forklart i det rekursive trediagrammet ovenfor.
Hjelpeplass: O(1). Ingen ekstern plass brukes til å lagre verdier bortsett fra den interne stabelplassen.
Lengst økende sekvens ved hjelp av Memoisering :
Hvis vi legger merke til nøye, kan vi se at den ovennevnte rekursive løsningen også følger overlappende delproblemer egenskap, dvs. samme understruktur løst igjen og igjen i forskjellige rekursjonsanropsveier. Vi kan unngå dette ved å bruke husketilnærmingen.
Vi kan se at hver tilstand kan identifiseres unikt ved hjelp av to parametere:
- Gjeldende indeks (angir den siste indeksen til LIS) og
- Forrige indeks (angir sluttindeksen til forrige LIS bak som arr[i] blir slått sammen).
Nedenfor er implementeringen av tilnærmingen ovenfor.
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); } // Funksjon for å finne lengden av // lengst økende undersekvens int lengsteSubsequence(int n, int a[]) { vektor> dp(n + 1, vektor (n + 1, -1)); returner f(0, -1, n, a, dp); } // Driverprogram for å teste ovenfor funksjon int main() { int a[] = { 3, 10, 2, 1, 20 }; int n = størrelse på(a) / størrelse på(a[0]); // Function call 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); } // Innpakningsfunksjonen for _lis() statisk int lis(int arr[], int n) { // Funksjonen _lis() lagrer resultatet i maks. int dp[][] = new int[n + 1][ n + 1]; for (int rad[] : dp) Arrays.fill(row, -1); returner f(0, -1, n, arr, dp); } // Driverprogram for å teste funksjonene ovenfor public static void main(String args[]) { int a[] = { 3, 10, 2, 1, 20 }; int n = a.lengde; // Funksjonsanrop System.out.println('Lengden på lis er ' + lis(a, n)); } } // Denne koden er bidratt av 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] # Funksjon for å finne lengden på lengst økende # undersekvens. def lengsteSubsequence(n, a): dp = [[-1 for i i området(n + 1)]for j i området(n + 1)] returner f(0, -1, n, a, dp) # Driver program for å teste funksjonen ovenfor hvis __navn__ == '__main__': a = [3, 10, 2, 1, 20] n = len(a) # Funksjonsanrop print('Lengde på lis er', lengsteSubsequence( n, a)) # Denne koden er bidratt av 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); } // Funksjon for å finne lengden på lengst økende // undersekvens. 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)); } // Funksjon for å finne lengden på lengst økende // undersekvens. function longestSubsequence(n, a) { var dp = Array(n + 1) .fill() .map(() => Array(n + 1).fill(-1)); returner f(0, -1, n, a, dp); } /* Driverprogram for å teste funksjonen ovenfor */ var a = [3, 10, 2, 1, 20]; var n = 5; console.log('Lengden på lis er ' + lengsteSubsequence(n, a)); // Denne koden er bidratt av satwiksuman.>
Produksjon
Length of lis is 3>
Tidskompleksitet: PÅ2)
Hjelpeplass: PÅ2)
Lengst økende sekvens ved hjelp av Dynamisk programmering :
På grunn av optimal understruktur og overlappende delproblemegenskap kan vi også benytte Dynamisk programmering for å løse problemet. I stedet for memoisering, kan vi bruke den nestede løkken for å implementere den rekursive relasjonen.
Den ytre sløyfen vil løpe fra i = 1 til N og den indre løkken vil løpe fra j = 0 til i og bruk gjentakelsesrelasjonen for å løse problemet.
Nedenfor er implementeringen av tilnærmingen ovenfor:
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 >
Produksjon
Length of lis is 5>
Tidskompleksitet: PÅ2) Som en nestet løkke brukes.
Hjelpeplass: O(N) Bruk av en hvilken som helst matrise for å lagre LIS-verdier ved hver indeks.
df.loc
Merk: Tidskompleksiteten til løsningen for dynamisk programmering (DP) ovenfor er O(n^2), men det er en O(N* logN) løsning for LIS-problemet. Vi har ikke diskutert O(N log N)-løsningen her.
Henvise: Lengst økende undersekvensstørrelse (N * logN) for den nevnte tilnærmingen.