logo

Langst stijgende vervolgreeks (LIS)

Gegeven een array arr[] van grootte N , de taak is om de lengte van de langst toenemende deelreeks (LIS) te vinden, dat wil zeggen de langst mogelijke deelreeks waarin de elementen van de deelreeks in oplopende volgorde zijn gesorteerd.

LIS

Langste stijgende vervolgreeks



Voorbeelden:

Invoer: arr[] = {3, 10, 2, 1, 20}
Uitgang: 3
Uitleg: De langst stijgende deelreeks is 3, 10, 20

Invoer: arr[] = {50, 3, 10, 7, 40, 80}
Uitgang: 4
Uitleg: De langste stijgende deelreeks is {3, 7, 40, 80}



indexvan lijst

Invoer: arr[] = {30, 20, 10}
Uitgang: 1
Uitleg: De langst stijgende deelreeksen zijn {30}, {20} en (10)

Invoer: arr[] = {10, 20, 35, 80}
Uitgang: 4
Uitleg: De hele array is gesorteerd

Langste toenemende reeks gebruikt Herhaling :

Het idee om de invoerarray van links naar rechts te doorlopen en de lengte van de langst toenemende subreeks (LIS) te vinden die eindigt met elk element arr[i]. Laat de gevonden lengte voor arr[i] L[i] zijn. Aan het einde retourneren we het maximum van alle L[i]-waarden. Nu rijst de vraag: hoe berekenen we L[i]? Hiervoor gebruiken we recursie, we beschouwen alle kleinere elementen aan de linkerkant van arr[i], berekenen recursief de LIS-waarde voor alle kleinere elementen aan de linkerkant, nemen het maximum van allemaal en tellen er 1 bij op. Als er links van een element geen kleiner element staat, geven we 1 terug.



Laten L(ik) de lengte zijn van het LIS dat eindigt op index i zodanig dat arr[i] het laatste element van het LIS is. Vervolgens kan L(i) recursief worden geschreven als:

binaire boom in Java
  • L(i) = 1 + max(L(j) ) waarbij 0
  • L(i) = 1, als zo'n j niet bestaat.

Formeel eindigt de lengte van LIS op index i , is 1 groter dan het maximum aantal lengtes van alle LIS die eindigen op een bepaalde index J zoals dat arr[j] waar J .

We kunnen zien dat de bovenstaande herhalingsrelatie de volgt optimale onderbouw eigendom.

Illustratie:

cast in naar string java

Volg de onderstaande afbeelding voor een beter begrip:

Beschouw arr[] = {3, 10, 2, 11}

L(i): Geeft LIS aan van subarray eindigend op positie 'i'

Recursieboom

Recursieboom

Volg de onderstaande stappen om het bovenstaande idee te implementeren:

  • Maak een recursieve functie.
  • Voor elke recursieve aanroep itereert u vanaf de ik = 1 naar de huidige positie en doe het volgende:
    • Zoek de mogelijke lengte van de langst toenemende deelreeks die eindigt op de huidige positie als de vorige reeks eindigde op i .
    • Werk de maximaal mogelijke lengte dienovereenkomstig bij.
  • Herhaal dit voor alle indices en vind het antwoord

Hieronder vindt u de implementatie van de recursieve benadering:

bestand geopend in Java
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;  } // Vergelijk max_ending_here met de // algemene max. En update indien nodig de // overall max als (*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;  } // Vergelijk max_ending_here met de algemene // max. En update indien nodig het algemene maximum als (*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;  } // Vergelijk max_ending_here met de totale max. En // update indien nodig het algemene maximum als (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 # Vergelijk maxEndingHere met het algehele maximum. En # update het algehele maximum indien nodig maximum = max(maximum, maxEndingHere) return maxEndingHere def lis(arr): # Om toegang tot de globale variabele toe te staan ​​global maximum # Lengte van arr n = len(arr) # Maximale variabele bevat het resultaat maximum = 1 # De functie _lis() slaat zijn resultaat op in maximum _lis(arr, n) retourneert maximum # Stuurprogramma om de bovenstaande functie te testen als __name__ == '__main__': arr = [10, 22, 9, 33 , 21, 50, 41, 60] n = len(arr) # Functieaanroep print('Lengte van lis is', lis(arr)) # Deze code is bijgedragen door 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;  } // Vergelijk max_ending_here met het algemene maximum // en update het algemene maximum indien nodig if (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
>

Uitvoer
Length of lis is 5>

Tijdcomplexiteit: O(2N) De tijdscomplexiteit van deze recursieve benadering is exponentieel omdat er sprake is van overlappende subproblemen, zoals uitgelegd in het recursieve boomdiagram hierboven.
Hulpruimte: O(1). Er wordt geen externe ruimte gebruikt voor het opslaan van waarden, afgezien van de interne stapelruimte.

Langst toenemende vervolgreeks gebruikt Memoriseren :

Als we goed opletten, kunnen we zien dat de bovenstaande recursieve oplossing ook de volgt overlappende deelproblemen eigenschap, dat wil zeggen dezelfde substructuur keer op keer opgelost in verschillende recursie-oproeppaden. We kunnen dit vermijden door de memoisatiebenadering te gebruiken.

We kunnen zien dat elke toestand uniek kan worden geïdentificeerd met behulp van twee parameters:

  • Huidige index (geeft de laatste index van de LIS aan) en
  • Vorige index (geeft de eindindex aan van het vorige LIS waarachter de arr[ik] wordt samengevoegd).

Hieronder vindt u de implementatie van bovenstaande aanpak.

lang om Java te stringen
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][vorige_idx + 1] != -1) { return dp[idx][vorige_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(nemen, niet nemen); } // Functie om de lengte te vinden van // langste toenemende deelreeks int longSubsequence(int n, int a[]) { vector> dp(n + 1, vector (n+1, -1));  retourneer f(0, -1, n, a, dp); } // Stuurprogramma om bovenstaande functie te testen int main() { int a[] = { 3, 10, 2, 1, 20 };  int n = groottevan(a) / groottevan(a[0]);  // Functieoproep 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[vorige_idx]) {neem = 1 + f(idx + 1, idx, n, a, dp);  } return dp[idx][prev_idx + 1] = Math.max(nemen, niet nemen);  } // De wrapperfunctie voor _lis() static int lis(int arr[], int n) {// De functie _lis() slaat zijn resultaat op in max int dp[][] = new int[n + 1][ n+1];  for (int rij[]: dp) Arrays.fill(rij, -1);  retourneert f(0, -1, n, arr, dp);  } // Stuurprogramma om bovenstaande functies te testen public static void main(String args[]) { int a[] = { 3, 10, 2, 1, 20 };  int n = a.lengte;  // Functieaanroep System.out.println('Lengte van lis is ' + lis(a, n));  } } // Deze code is bijgedragen door 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) return dp[idx][prev_idx + 1] # Functie om de lengte van de langste toenemende # subreeks te vinden. def langste deelreeks(n, a): dp = [[-1 voor i binnen bereik(n + 1)]voor j binnen bereik(n + 1)] return f(0, -1, n, a, dp) # Stuurprogramma programma om bovenstaande functie te testen als __name__ == '__main__': a = [3, 10, 2, 1, 20] n = len(a) # Functieaanroep print('Lengte van lis is', langstesubreeks( n, a)) # Deze code is bijgedragen door 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[vorige_idx]) {neem = 1 + f(idx + 1, idx, n, a, dp);  } return dp[idx, prev_idx + 1] = Math.Max(take, notTake);  } // Functie om de lengte van de langst stijgende // subreeks te vinden.  publieke statische int langsteVolgreeks(int n, int[] a) { int[, ] dp = nieuwe int[n + 1, n + 1];  voor (int i = 0; ik< 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[vorige_idx]) {neem = 1 + f(idx + 1, idx, n, a, dp);  } return (dp[idx][prev_idx + 1] = Math.max(take, notTake));  } // Functie om de lengte van de langst stijgende // subreeks te vinden.  function longSubsequence(n, a) { var dp = Array(n + 1) .fill() .map(() => Array(n + 1).fill(-1));  retourneert f(0, -1, n, a, dp);  } /* Stuurprogramma om bovenstaande functie te testen */ var a = [3, 10, 2, 1, 20];  var n = 5;  console.log('Lengte van lis is ' + langstesubreeks(n, a));    // Deze code is bijgedragen door satwiksuman.>

Uitvoer
Length of lis is 3>

Tijdcomplexiteit: OP2)
Hulpruimte: OP2)

Langst toenemende vervolgreeks gebruikt Dynamisch programmeren :

Door een optimale onderbouw en overlappende subprobleemeigenschap kunnen we ook gebruik maken van dynamisch programmeren om het probleem op te lossen. In plaats van te onthouden, kunnen we de geneste lus gebruiken om de recursieve relatie te implementeren.

De buitenste lus loopt vanaf ik = 1 tot N en de binnenste lus zal lopen j = 0 tot ik en gebruik de herhalingsrelatie om het probleem op te lossen.

Hieronder vindt u de implementatie van de bovenstaande aanpak:

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] en 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
>

Uitvoer
Length of lis is 5>

Tijdcomplexiteit: OP2) Omdat er een geneste lus wordt gebruikt.
Hulpruimte: O(N) Gebruik van een willekeurige array om LIS-waarden bij elke index op te slaan.

Opmerking: De tijdscomplexiteit van de bovenstaande Dynamic Programming (DP)-oplossing is O(n^2), maar er is een O(N* logN) oplossing voor het LIS-probleem. We hebben de O(N log N)-oplossing hier niet besproken.
Refereren: Langst toenemende deelreeksgrootte (N * logN) voor de genoemde aanpak.