How to determine the longest increasing subsequence using dynamic programming?

前端 未结 19 2335
醉梦人生
醉梦人生 2020-11-22 10:55

I have a set of integers. I want to find the longest increasing subsequence of that set using dynamic programming.

相关标签:
19条回答
  • 2020-11-22 11:16

    The O(NLog(N)) Approach To Find Longest Increasing Sub sequence
    Let us maintain an array where the ith element is the smallest possible number with which a i sized sub sequence can end.

    On purpose I am avoiding further details as the top voted answer already explains it, but this technique eventually leads to a neat implementation using the set data structure (at least in c++).

    Here is the implementation in c++ (assuming strictly increasing longest sub sequence size is required)

    #include <bits/stdc++.h> // gcc supported header to include (almost) everything
    using namespace std;
    typedef long long ll;
    
    int main()
    {
      ll n;
      cin >> n;
      ll arr[n];
      set<ll> S;
    
      for(ll i=0; i<n; i++)
      {
        cin >> arr[i];
        auto it = S.lower_bound(arr[i]);
        if(it != S.end())
          S.erase(it);
        S.insert(arr[i]);
      }
    
      cout << S.size() << endl; // Size of the set is the required answer
    
      return 0;
    }
    
    0 讨论(0)
  • 2020-11-22 11:18

    Speaking about DP solution, I found it surprising that no one mentioned the fact that LIS can be reduced to LCS. All you need to do is sort the copy of the original sequence, remove all the duplicates and do LCS of them. In pseudocode it is:

    def LIS(S):
        T = sort(S)
        T = removeDuplicates(T)
        return LCS(S, T)
    

    And the full implementation written in Go. You do not need to maintain the whole n^2 DP matrix if you do not need to reconstruct the solution.

    func lcs(arr1 []int) int {
        arr2 := make([]int, len(arr1))
        for i, v := range arr1 {
            arr2[i] = v
        }
        sort.Ints(arr1)
        arr3 := []int{}
        prev := arr1[0] - 1
        for _, v := range arr1 {
            if v != prev {
                prev = v
                arr3 = append(arr3, v)
            }
        }
    
        n1, n2 := len(arr1), len(arr3)
    
        M := make([][]int, n2 + 1)
        e := make([]int, (n1 + 1) * (n2 + 1))
        for i := range M {
            M[i] = e[i * (n1 + 1):(i + 1) * (n1 + 1)]
        }
    
        for i := 1; i <= n2; i++ {
            for j := 1; j <= n1; j++ {
                if arr2[j - 1] == arr3[i - 1] {
                    M[i][j] = M[i - 1][j - 1] + 1
                } else if M[i - 1][j] > M[i][j - 1] {
                    M[i][j] = M[i - 1][j]
                } else {
                    M[i][j] = M[i][j - 1]
                }
            }
        }
    
        return M[n2][n1]
    }
    
    0 讨论(0)
  • 2020-11-22 11:23

    Here is my Leetcode solution using Binary Search:->

    class Solution:
        def binary_search(self,s,x):
            low=0
            high=len(s)-1
            flag=1
            while low<=high:
                  mid=(high+low)//2
                  if s[mid]==x:
                     flag=0
                     break
                  elif s[mid]<x:
                      low=mid+1
                  else:
                     high=mid-1
            if flag:
               s[low]=x
            return s
    
        def lengthOfLIS(self, nums: List[int]) -> int:
             if not nums:
                return 0
             s=[]
             s.append(nums[0])
             for i in range(1,len(nums)):
                 if s[-1]<nums[i]:
                    s.append(nums[i])
                 else:
                     s=self.binary_search(s,nums[i])
             return len(s)
    
    0 讨论(0)
  • 2020-11-22 11:24

    Here's another O(n^2) JAVA implementation. No recursion/memoization to generate the actual subsequence. Just a string array that stores the actual LIS at every stage and an array to store the length of the LIS for each element. Pretty darn easy. Have a look:

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    
    /**
     * Created by Shreyans on 4/16/2015
     */
    
    class LNG_INC_SUB//Longest Increasing Subsequence
    {
        public static void main(String[] args) throws Exception
        {
            BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
            System.out.println("Enter Numbers Separated by Spaces to find their LIS\n");
            String[] s1=br.readLine().split(" ");
            int n=s1.length;
            int[] a=new int[n];//Array actual of Numbers
            String []ls=new String[n];// Array of Strings to maintain LIS for every element
            for(int i=0;i<n;i++)
            {
                a[i]=Integer.parseInt(s1[i]);
            }
            int[]dp=new int[n];//Storing length of max subseq.
            int max=dp[0]=1;//Defaults
            String seq=ls[0]=s1[0];//Defaults
            for(int i=1;i<n;i++)
            {
                dp[i]=1;
                String x="";
                for(int j=i-1;j>=0;j--)
                {
                    //First check if number at index j is less than num at i.
                    // Second the length of that DP should be greater than dp[i]
                    // -1 since dp of previous could also be one. So we compare the dp[i] as empty initially
                    if(a[j]<a[i]&&dp[j]>dp[i]-1)
                    {
                        dp[i]=dp[j]+1;//Assigning temp length of LIS. There may come along a bigger LIS of a future a[j]
                        x=ls[j];//Assigning temp LIS of a[j]. Will append a[i] later on
                    }
                }
                x+=(" "+a[i]);
                ls[i]=x;
                if(dp[i]>max)
                {
                    max=dp[i];
                    seq=ls[i];
                }
            }
            System.out.println("Length of LIS is: " + max + "\nThe Sequence is: " + seq);
        }
    }
    

    Code in action: http://ideone.com/sBiOQx

    0 讨论(0)
  • 2020-11-22 11:25

    This can be solved in O(n^2) using dynamic programming.

    Process the input elements in order and maintain a list of tuples for each element. Each tuple (A,B), for the element i will denotes, A = length of longest increasing sub-sequence ending at i and B = index of predecessor of list[i] in the longest increasing sub-sequence ending at list[i].

    Start from element 1, the list of tuple for element 1 will be [(1,0)] for element i, scan the list 0..i and find element list[k] such that list[k] < list[i], the value of A for element i, Ai will be Ak + 1 and Bi will be k. If there are multiple such elements, add them to the list of tuples for element i.

    In the end, find all the elements with max value of A (length of LIS ending at element) and backtrack using the tuples to get the list.

    I have shared the code for same at http://www.edufyme.com/code/?id=66f041e16a60928b05a7e228a89c3799

    0 讨论(0)
  • 2020-11-22 11:25

    O(n^2) java implementation:

    void LIS(int arr[]){
            int maxCount[]=new int[arr.length];
            int link[]=new int[arr.length];
            int maxI=0;
            link[0]=0;
            maxCount[0]=0;
    
            for (int i = 1; i < arr.length; i++) {
                for (int j = 0; j < i; j++) {
                    if(arr[j]<arr[i] && ((maxCount[j]+1)>maxCount[i])){
                        maxCount[i]=maxCount[j]+1;
                        link[i]=j;
                        if(maxCount[i]>maxCount[maxI]){
                            maxI=i;
                        }
                    }
                }
            }
    
    
            for (int i = 0; i < link.length; i++) {
                System.out.println(arr[i]+"   "+link[i]);
            }
            print(arr,maxI,link);
    
        }
    
        void print(int arr[],int index,int link[]){
            if(link[index]==index){
                System.out.println(arr[index]+" ");
                return;
            }else{
                print(arr, link[index], link);
                System.out.println(arr[index]+" ");
            }
        }
    
    0 讨论(0)
提交回复
热议问题