How to determine the longest increasing subsequence using dynamic programming?

前端 未结 19 2336
醉梦人生
醉梦人生 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:34

    Simplest LIS solution in C++ with O(nlog(n)) time complexity

    #include <iostream>
    #include "vector"
    using namespace std;
    
    // binary search (If value not found then it will return the index where the value should be inserted)
    int ceilBinarySearch(vector<int> &a,int beg,int end,int value)
    {
        if(beg<=end)
        {
            int mid = (beg+end)/2;
            if(a[mid] == value)
                return mid;
            else if(value < a[mid])
                return ceilBinarySearch(a,beg,mid-1,value);
            else
                return ceilBinarySearch(a,mid+1,end,value);
    
        return 0;
        }
    
        return beg;
    
    }
    int lis(vector<int> arr)
    {
        vector<int> dp(arr.size(),0);
        int len = 0;
        for(int i = 0;i<arr.size();i++)
        {
            int j = ceilBinarySearch(dp,0,len-1,arr[i]);
            dp[j] = arr[i];
            if(j == len)
                len++;
    
        }
        return len;
    }
    
    int main()
    {
        vector<int> arr  {2, 5,-1,0,6,1,2};
        cout<<lis(arr);
        return 0;
    }
    

    OUTPUT:
    4

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

    Here are three steps of evaluating the problem from dynamic programming point of view:

    1. Recurrence definition: maxLength(i) == 1 + maxLength(j) where 0 < j < i and array[i] > array[j]
    2. Recurrence parameter boundary: there might be 0 to i - 1 sub-sequences passed as a paramter
    3. Evaluation order: as it is increasing sub-sequence, it has to be evaluated from 0 to n

    If we take as an example sequence {0, 8, 2, 3, 7, 9}, at index:

    • [0] we'll get subsequence {0} as a base case
    • [1] we have 1 new subsequence {0, 8}
    • [2] trying to evaluate two new sequences {0, 8, 2} and {0, 2} by adding element at index 2 to existing sub-sequences - only one is valid, so adding third possible sequence {0, 2} only to parameters list ...

    Here's the working C++11 code:

    #include <iostream>
    #include <vector>
    
    int getLongestIncSub(const std::vector<int> &sequence, size_t index, std::vector<std::vector<int>> &sub) {
        if(index == 0) {
            sub.push_back(std::vector<int>{sequence[0]});
            return 1;
        }
    
        size_t longestSubSeq = getLongestIncSub(sequence, index - 1, sub);
        std::vector<std::vector<int>> tmpSubSeq;
        for(std::vector<int> &subSeq : sub) {
            if(subSeq[subSeq.size() - 1] < sequence[index]) {
                std::vector<int> newSeq(subSeq);
                newSeq.push_back(sequence[index]);
                longestSubSeq = std::max(longestSubSeq, newSeq.size());
                tmpSubSeq.push_back(newSeq);
            }
        }
        std::copy(tmpSubSeq.begin(), tmpSubSeq.end(),
                  std::back_insert_iterator<std::vector<std::vector<int>>>(sub));
    
        return longestSubSeq;
    }
    
    int getLongestIncSub(const std::vector<int> &sequence) {
        std::vector<std::vector<int>> sub;
        return getLongestIncSub(sequence, sequence.size() - 1, sub);
    }
    
    int main()
    {
        std::vector<int> seq{0, 8, 2, 3, 7, 9};
        std::cout << getLongestIncSub(seq);
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-22 11:38

    This can be solved in O(n^2) using Dynamic Programming. Python code for the same would be like:-

    def LIS(numlist):
        LS = [1]
        for i in range(1, len(numlist)):
            LS.append(1)
            for j in range(0, i):
                if numlist[i] > numlist[j] and LS[i]<=LS[j]:
                    LS[i] = 1 + LS[j]
        print LS
        return max(LS)
    
    numlist = map(int, raw_input().split(' '))
    print LIS(numlist)
    

    For input:5 19 5 81 50 28 29 1 83 23

    output would be:[1, 2, 1, 3, 3, 3, 4, 1, 5, 3] 5

    The list_index of output list is the list_index of input list. The value at a given list_index in output list denotes the Longest increasing subsequence length for that list_index.

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

    Longest Increasing Subsequence(Java)

    import java.util.*;
    
    class ChainHighestValue implements Comparable<ChainHighestValue>{
        int highestValue;
        int chainLength;
        ChainHighestValue(int highestValue,int chainLength) {
            this.highestValue = highestValue;
            this.chainLength = chainLength;
        }
        @Override
        public int compareTo(ChainHighestValue o) {
           return this.chainLength-o.chainLength;
        }
    
    }
    
    
    public class LongestIncreasingSubsequenceLinkedList {
    
    
        private static LinkedList<Integer> LongestSubsequent(int arr[], int size){
            ArrayList<LinkedList<Integer>> seqList=new ArrayList<>();
            ArrayList<ChainHighestValue> valuePairs=new ArrayList<>();
            for(int i=0;i<size;i++){
                int currValue=arr[i];
                if(valuePairs.size()==0){
                    LinkedList<Integer> aList=new LinkedList<>();
                    aList.add(arr[i]);
                    seqList.add(aList);
                    valuePairs.add(new ChainHighestValue(arr[i],1));
    
                }else{
                    try{
                        ChainHighestValue heighestIndex=valuePairs.stream().filter(e->e.highestValue<currValue).max(ChainHighestValue::compareTo).get();
                        int index=valuePairs.indexOf(heighestIndex);
                        seqList.get(index).add(arr[i]);
                        heighestIndex.highestValue=arr[i];
                        heighestIndex.chainLength+=1;
    
                    }catch (Exception e){
                        LinkedList<Integer> aList=new LinkedList<>();
                        aList.add(arr[i]);
                        seqList.add(aList);
                        valuePairs.add(new ChainHighestValue(arr[i],1));
                    }
                }
            }
            ChainHighestValue heighestIndex=valuePairs.stream().max(ChainHighestValue::compareTo).get();
            int index=valuePairs.indexOf(heighestIndex);
            return seqList.get(index);
        }
    
        public static void main(String[] args){
            int arry[]={5,1,3,6,11,30,32,5,3,73,79};
            //int arryB[]={3,1,5,2,6,4,9};
            LinkedList<Integer> LIS=LongestSubsequent(arry, arry.length);
            System.out.println("Longest Incrementing Subsequence:");
            for(Integer a: LIS){
                System.out.print(a+" ");
            }
    
        }
    }
    
    0 讨论(0)
  • 2020-11-22 11:39

    Petar Minchev's explanation helped clear things up for me, but it was hard for me to parse what everything was, so I made a Python implementation with overly-descriptive variable names and lots of comments. I did a naive recursive solution, the O(n^2) solution, and the O(n log n) solution.

    I hope it helps clear up the algorithms!

    The Recursive Solution

    def recursive_solution(remaining_sequence, bigger_than=None):
        """Finds the longest increasing subsequence of remaining_sequence that is      
        bigger than bigger_than and returns it.  This solution is O(2^n)."""
    
        # Base case: nothing is remaining.                                             
        if len(remaining_sequence) == 0:
            return remaining_sequence
    
        # Recursive case 1: exclude the current element and process the remaining.     
        best_sequence = recursive_solution(remaining_sequence[1:], bigger_than)
    
        # Recursive case 2: include the current element if it's big enough.            
        first = remaining_sequence[0]
    
        if (first > bigger_than) or (bigger_than is None):
    
            sequence_with = [first] + recursive_solution(remaining_sequence[1:], first)
    
            # Choose whichever of case 1 and case 2 were longer.                         
            if len(sequence_with) >= len(best_sequence):
                best_sequence = sequence_with
    
        return best_sequence                                                        
    

    The O(n^2) Dynamic Programming Solution

    def dynamic_programming_solution(sequence):
        """Finds the longest increasing subsequence in sequence using dynamic          
        programming.  This solution is O(n^2)."""
    
        longest_subsequence_ending_with = []
        backreference_for_subsequence_ending_with = []
        current_best_end = 0
    
        for curr_elem in range(len(sequence)):
            # It's always possible to have a subsequence of length 1.                    
            longest_subsequence_ending_with.append(1)
    
            # If a subsequence is length 1, it doesn't have a backreference.             
            backreference_for_subsequence_ending_with.append(None)
    
            for prev_elem in range(curr_elem):
                subsequence_length_through_prev = (longest_subsequence_ending_with[prev_elem] + 1)
    
                # If the prev_elem is smaller than the current elem (so it's increasing)   
                # And if the longest subsequence from prev_elem would yield a better       
                # subsequence for curr_elem.                                               
                if ((sequence[prev_elem] < sequence[curr_elem]) and
                        (subsequence_length_through_prev >
                             longest_subsequence_ending_with[curr_elem])):
    
                    # Set the candidate best subsequence at curr_elem to go through prev.    
                    longest_subsequence_ending_with[curr_elem] = (subsequence_length_through_prev)
                    backreference_for_subsequence_ending_with[curr_elem] = prev_elem
                    # If the new end is the best, update the best.    
    
            if (longest_subsequence_ending_with[curr_elem] >
                    longest_subsequence_ending_with[current_best_end]):
                current_best_end = curr_elem
                # Output the overall best by following the backreferences.  
    
        best_subsequence = []
        current_backreference = current_best_end
    
        while current_backreference is not None:
            best_subsequence.append(sequence[current_backreference])
            current_backreference = (backreference_for_subsequence_ending_with[current_backreference])
    
        best_subsequence.reverse()
    
        return best_subsequence                                                   
    

    The O(n log n) Dynamic Programming Solution

    def find_smallest_elem_as_big_as(sequence, subsequence, elem):
        """Returns the index of the smallest element in subsequence as big as          
        sequence[elem].  sequence[elem] must not be larger than every element in       
        subsequence.  The elements in subsequence are indices in sequence.  Uses       
        binary search."""
    
        low = 0
        high = len(subsequence) - 1
    
        while high > low:
            mid = (high + low) / 2
            # If the current element is not as big as elem, throw out the low half of    
            # sequence.                                                                  
            if sequence[subsequence[mid]] < sequence[elem]:
                low = mid + 1
                # If the current element is as big as elem, throw out everything bigger, but 
            # keep the current element.                                                  
            else:
                high = mid
    
        return high
    
    
    def optimized_dynamic_programming_solution(sequence):
        """Finds the longest increasing subsequence in sequence using dynamic          
        programming and binary search (per                                             
        http://en.wikipedia.org/wiki/Longest_increasing_subsequence).  This solution   
        is O(n log n)."""
    
        # Both of these lists hold the indices of elements in sequence and not the        
        # elements themselves.                                                         
        # This list will always be sorted.                                             
        smallest_end_to_subsequence_of_length = []
    
        # This array goes along with sequence (not                                     
        # smallest_end_to_subsequence_of_length).  Following the corresponding element 
        # in this array repeatedly will generate the desired subsequence.              
        parent = [None for _ in sequence]
    
        for elem in range(len(sequence)):
            # We're iterating through sequence in order, so if elem is bigger than the   
            # end of longest current subsequence, we have a new longest increasing          
            # subsequence.                                                               
            if (len(smallest_end_to_subsequence_of_length) == 0 or
                        sequence[elem] > sequence[smallest_end_to_subsequence_of_length[-1]]):
                # If we are adding the first element, it has no parent.  Otherwise, we        
                # need to update the parent to be the previous biggest element.            
                if len(smallest_end_to_subsequence_of_length) > 0:
                    parent[elem] = smallest_end_to_subsequence_of_length[-1]
                smallest_end_to_subsequence_of_length.append(elem)
            else:
                # If we can't make a longer subsequence, we might be able to make a        
                # subsequence of equal size to one of our earlier subsequences with a         
                # smaller ending number (which makes it easier to find a later number that 
                # is increasing).                                                          
                # Thus, we look for the smallest element in                                
                # smallest_end_to_subsequence_of_length that is at least as big as elem       
                # and replace it with elem.                                                
                # This preserves correctness because if there is a subsequence of length n 
                # that ends with a number smaller than elem, we could add elem on to the   
                # end of that subsequence to get a subsequence of length n+1.              
                location_to_replace = find_smallest_elem_as_big_as(sequence, smallest_end_to_subsequence_of_length, elem)
                smallest_end_to_subsequence_of_length[location_to_replace] = elem
                # If we're replacing the first element, we don't need to update its parent 
                # because a subsequence of length 1 has no parent.  Otherwise, its parent  
                # is the subsequence one shorter, which we just added onto.                
                if location_to_replace != 0:
                    parent[elem] = (smallest_end_to_subsequence_of_length[location_to_replace - 1])
    
        # Generate the longest increasing subsequence by backtracking through parent.  
        curr_parent = smallest_end_to_subsequence_of_length[-1]
        longest_increasing_subsequence = []
    
        while curr_parent is not None:
            longest_increasing_subsequence.append(sequence[curr_parent])
            curr_parent = parent[curr_parent]
    
        longest_increasing_subsequence.reverse()
    
        return longest_increasing_subsequence         
    
    0 讨论(0)
  • 2020-11-22 11:40

    checkout the code in java for longest increasing subsequence with the array elements

    http://ideone.com/Nd2eba

    /**
     **    Java Program to implement Longest Increasing Subsequence Algorithm
     **/
    
    import java.util.Scanner;
    
    /** Class  LongestIncreasingSubsequence **/
     class  LongestIncreasingSubsequence
    {
        /** function lis **/
        public int[] lis(int[] X)
        {        
            int n = X.length - 1;
            int[] M = new int[n + 1];  
            int[] P = new int[n + 1]; 
            int L = 0;
    
            for (int i = 1; i < n + 1; i++)
            {
                int j = 0;
    
                /** Linear search applied here. Binary Search can be applied too.
                    binary search for the largest positive j <= L such that 
                    X[M[j]] < X[i] (or set j = 0 if no such value exists) **/
    
                for (int pos = L ; pos >= 1; pos--)
                {
                    if (X[M[pos]] < X[i])
                    {
                        j = pos;
                        break;
                    }
                }            
                P[i] = M[j];
                if (j == L || X[i] < X[M[j + 1]])
                {
                    M[j + 1] = i;
                    L = Math.max(L,j + 1);
                }
            }
    
            /** backtrack **/
    
            int[] result = new int[L];
            int pos = M[L];
            for (int i = L - 1; i >= 0; i--)
            {
                result[i] = X[pos];
                pos = P[pos];
            }
            return result;             
        }
    
        /** Main Function **/
        public static void main(String[] args) 
        {    
            Scanner scan = new Scanner(System.in);
            System.out.println("Longest Increasing Subsequence Algorithm Test\n");
    
            System.out.println("Enter number of elements");
            int n = scan.nextInt();
            int[] arr = new int[n + 1];
            System.out.println("\nEnter "+ n +" elements");
            for (int i = 1; i <= n; i++)
                arr[i] = scan.nextInt();
    
            LongestIncreasingSubsequence obj = new LongestIncreasingSubsequence(); 
            int[] result = obj.lis(arr);       
    
            /** print result **/ 
    
            System.out.print("\nLongest Increasing Subsequence : ");
            for (int i = 0; i < result.length; i++)
                System.out.print(result[i] +" ");
            System.out.println();
        }
    }
    
    0 讨论(0)
提交回复
热议问题