Givet en array arr[] av storlek N , är uppgiften att hitta längden på den längsta ökande delsekvensen (LIS), dvs. den längsta möjliga delsekvensen där elementen i delsekvensen sorteras i ökande ordning.

Längst ökande efterföljd
Exempel:
Inmatning: arr[] = {3, 10, 2, 1, 20}
Produktion: 3
Förklaring: Den längsta ökande följdsekvensen är 3, 10, 20Inmatning: arr[] = {50, 3, 10, 7, 40, 80}
Produktion: 4
Förklaring: Den längsta ökande undersekvensen är {3, 7, 40, 80}
d flip flopInmatning: arr[] = {30, 20, 10}
Produktion: 1
Förklaring: De längst ökande undersekvenserna är {30}, {20} och (10)Inmatning: arr[] = {10, 20, 35, 80}
Produktion: 4
Förklaring: Hela arrayen är sorterad
Längsta ökande sekvens med Rekursion :
Idén att gå igenom inmatningsmatrisen från vänster till höger och hitta längden på den längsta ökande subsekvensen (LIS) som slutar med varje element arr[i]. Låt längden som hittas för arr[i] vara L[i]. I slutet returnerar vi maximalt av alla L[i]-värden. Nu uppstår frågan, hur beräknar vi L[i]? För detta använder vi rekursion, vi betraktar alla mindre element till vänster om arr[i], beräknar rekursivt LIS-värde för alla mindre element till vänster, tar maximalt av alla och lägger till 1 till det. Om det inte finns något mindre element till vänster om ett element returnerar vi 1.
Låta L(i) vara längden på LIS som slutar på index i så att arr[i] är det sista elementet i LIS. Sedan kan L(i) skrivas rekursivt som:
byta namn på katalogen i linux
- L(i) = 1 + max(L(j) ) där 0
- L(i) = 1, om inget sådant j existerar.
Formellt, längden på LIS som slutar på index i , är 1 större än maxlängden för alla LIS som slutar på något index j Så att arr[j]
var j .
Vi kan se att ovanstående återkommande relation följer optimal understruktur fast egendom.
Illustration:
dfs algoritm
Följ illustrationen nedan för en bättre förståelse:
Tänk på arr[] = {3, 10, 2, 11}
L(i): Betecknar LIS för subarray som slutar på position 'i'
Rekursionsträd
Följ stegen nedan för att implementera idén ovan:
- Skapa en rekursiv funktion.
- För varje rekursivt samtal, Iterera från i = 1 till den aktuella positionen och gör följande:
- Hitta den möjliga längden på den längst ökande delsekvensen som slutar på den aktuella positionen om den föregående sekvensen slutade på i .
- Uppdatera högsta möjliga längd därefter.
- Upprepa detta för alla index och hitta svaret
Nedan följer implementeringen av det rekursiva tillvägagångssättet:
giltiga identifierare i javaC++
// 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; } // Jämför max_ending_here med // totala max. Och uppdatera // totala max vid behov om (*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; } // Jämför max_ending_here med den totala // max. Och uppdatera det totala maxvärdet om det behövs om (*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; } // Jämför max_ending_here med det totala max. Och // uppdatera det totala maxvärdet om det behövs om (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>
Pytonorm # 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 # Jämför maxEndingHere med totalt max. Och # uppdatera det totala maxvärdet om det behövs max = max(maximum, maxEndingHere) return maxEndingHere def lis(arr): # För att tillåta åtkomst av global variabel global maximi # Längd på arr n = len(arr) # Maximal variabel håller resultatet maximum = 1 # Funktionen _lis() lagrar sitt resultat i maximum _lis(arr, n) returnerar maximum # Drivrutinsprogram för att testa ovanstående funktion om __name__ == '__main__': arr = [10, 22, 9, 33 , 21, 50, 41, 60] n = len(arr) # Funktionsanrop print('Längd på lis är', lis(arr)) # Denna kod har bidragit från 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; } // Jämför max_ending_here med det totala max // och uppdatera det totala max vid behov om (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>
Tidskomplexitet: O(2n) Tidskomplexiteten för detta rekursiva tillvägagångssätt är exponentiell eftersom det finns ett fall av överlappande delproblem som förklaras i det rekursiva träddiagrammet ovan.
Hjälputrymme: O(1). Inget externt utrymme används för att lagra värden förutom det interna stackutrymmet.
Längst ökande sekvens med hjälp av Memoisering :
Om vi uppmärksammas noggrant kan vi se att ovanstående rekursiva lösning också följer överlappande delproblem egenskap, dvs samma understruktur löses om och om igen i olika rekursionsanropsvägar. Vi kan undvika detta genom att använda memoiseringsmetoden.
Vi kan se att varje tillstånd kan identifieras unikt med två parametrar:
- Aktuellt index (betecknar det sista indexet i LIS) och
- Föregående index (betecknar slutindexet för föregående LIS bakom vilket arr[i] håller på att sammanfogas).
Nedan är implementeringen av ovanstående tillvägagångssätt.
inorderpasseringC++
// 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); } returnera dp[idx][prev_idx + 1] = max(take, notTake); } // Funktion för att hitta längden på // längst ökande undersekvens int längstaSubsequence(int n, int a[]) { vektor> dp(n + 1, vektor (n + 1, -1)); returnera f(0, -1, n, a, dp); } // Drivrutinsprogram för att testa ovan funktion int main() { int a[] = { 3, 10, 2, 1, 20 }; int n = storlek på(a) / storlek på(a[0]); // Funktionsanrop 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); } // Omslagsfunktionen för _lis() statisk int lis(int arr[], int n) { // Funktionen _lis() lagrar sitt resultat i max int dp[][] = new int[n + 1][ n + 1]; for (int row[] : dp) Arrays.fill(row, -1); returnera f(0, -1, n, arr, dp); } // Drivrutinsprogram för att testa ovanstående funktioner public static void main(String args[]) { int a[] = { 3, 10, 2, 1, 20 }; int n = a.längd; // Funktionsanrop System.out.println('Längden på lis är ' + lis(a, n)); } } // Denna kod är bidragit av Sanskar.>
Pytonorm # 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(ta, notTake) returnera dp[idx][prev_idx + 1] # Funktion för att hitta längden på längst ökande # efterföljd. def längstaSubsequence(n, a): dp = [[-1 för i i intervallet(n + 1)]för j i intervallet(n + 1)] returnera f(0, -1, n, a, dp) # Drivrutin program för att testa ovanstående funktion om __name__ == '__main__': a = [3, 10, 2, 1, 20] n = len(a) # Funktionsanrop print('Längd på lis är', längstaSubsequence( n, a)) # Denna kod är bidragit 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); } // Funktion för att hitta längden på längst ökande // underföljd. public static int longestSubsequence(int n, int[] a) { int[, ] dp = new int[n + 1, n + 1]; för (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 för att hitta längden på längst ökande // underföljd. function longestSubsequence(n, a) { var dp = Array(n + 1) .fill() .map(() => Array(n + 1).fill(-1)); returnera f(0, -1, n, a, dp); } /* Drivrutinsprogram för att testa ovanstående funktion */ var a = [3, 10, 2, 1, 20]; var n = 5; console.log('Längd på lis är ' + längstaSubsequence(n, a)); // Den här koden är bidragit av satwiksuman.>
Produktion
Length of lis is 3>
Tidskomplexitet: PÅ2)
Hjälputrymme: PÅ2)
Längst ökande sekvens med hjälp av Dynamisk programmering :
På grund av optimal understruktur och överlappande delproblemegenskap kan vi även använda dynamisk programmering för att lösa problemet. Istället för memoisering kan vi använda den kapslade slingan för att implementera den rekursiva relationen.
Den yttre slingan kommer att löpa från i = 1 till N och den inre slingan kommer att löpa från j = 0 till i och använda återfallsrelationen för att lösa problemet.
Nedan är implementeringen av ovanstående tillvägagångssätt:
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>
Pytonorm # 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] och 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>
Tidskomplexitet: PÅ2) Som en kapslad loop används.
Hjälputrymme: O(N) Användning av valfri array för att lagra LIS-värden vid varje index.
Notera: Tidskomplexiteten för ovanstående dynamisk programmeringslösning (DP) är O(n^2), men det finns en O(N* logN) lösning för LIS-problemet. Vi har inte diskuterat O(N log N)-lösningen här.
Hänvisa: Längst ökande sekvensstorlek (N * logN) för det nämnda tillvägagångssättet.