如何使用动态编程确定增长最长的子序列?

时间:2010-04-13 17:26:51

标签: algorithm computer-science dynamic-programming memoization lis

我有一组整数。我想使用动态编程找到该集合的longest increasing subsequence

20 个答案:

答案 0 :(得分:369)

好的,我将首先描述最简单的解决方案,即O(N ^ 2),其中N是集合的大小。还有一个O(N log N)解决方案,我也将对此进行描述。在“高效算法”一节中查看here

我将假设数组的索引从0到N-1。所以让我们将DP[i]定义为LIS(最长的增长子序列)的长度,它以索引为{{1}的元素结束}。要计算i,我们会查看所有索引DP[i]并同时检查j < iDP[j] + 1 > DP[i](我们希望它增加)。如果这是真的,我们可以更新array[j] < array[i]的当前最佳值。要查找数组的全局最优值,您可以从DP[i]获取最大值。

DP[0...N - 1]

我使用数组int maxLength = 1, bestEnd = 0; DP[0] = 1; prev[0] = -1; for (int i = 1; i < N; i++) { DP[i] = 1; prev[i] = -1; for (int j = i - 1; j >= 0; j--) if (DP[j] + 1 > DP[i] && array[j] < array[i]) { DP[i] = DP[j] + 1; prev[i] = j; } if (DP[i] > maxLength) { bestEnd = i; maxLength = DP[i]; } } 以后能够找到实际序列而不仅仅是它的长度。只需使用prev在循环中从bestEnd递归返回。 prev[bestEnd]值是停止的标志。


好的,现在更有效的-1解决方案:

O(N log N)定义为结束长度S[pos]的递增序列的最小整数。现在迭代输入集的每个整数pos并执行以下操作:

  1. 如果X&gt; X中的最后一个元素,然后将S追加到X的末尾。这实际上意味着我们找到了一个新的最大S

  2. 否则找到LIS中的最小元素,S而不是>=,并将其更改为X。 由于X随时可以排序,因此可以使用S中的二进制搜索找到该元素。

  3. 总运行时间 - log(N)整数和每个整数的二进制搜索 - N * log(N)= O(N log N)

    现在让我们举一个真实的例子:

    整数集合: N

    步骤:

    2 6 3 4 1 2 9 5 8

    因此LIS的长度为0. S = {} - Initialize S to the empty set 1. S = {2} - New largest LIS 2. S = {2, 6} - New largest LIS 3. S = {2, 3} - Changed 6 to 3 4. S = {2, 3, 4} - New largest LIS 5. S = {1, 3, 4} - Changed 2 to 1 6. S = {1, 2, 4} - Changed 3 to 2 7. S = {1, 2, 4, 9} - New largest LIS 8. S = {1, 2, 4, 5} - Changed 9 to 5 9. S = {1, 2, 4, 5, 8} - New largest LIS (S的大小)。

    要重建实际的5,我们将再次使用父数组。 让LIS成为parent[i]中索引为i的元素的前身,其结尾位于索引为LIS的元素。

    为了使事情更简单,我们可以保留数组i,而不是实际的整数,而是它们在集合中的索引(位置)。我们不保留S,但保留{1, 2, 4, 5, 8}

    输入[4] = 1 ,输入[5] = 2 ,输入[3] = 4 ,输入[7 ] = 5 ,输入[8] = 8

    如果我们正确更新父数组,实际的LIS是:

    {4, 5, 3, 7, 8}

    现在重要的是 - 我们如何更新父数组?有两种选择:

    1. 如果input[S[lastElementOfS]], input[parent[S[lastElementOfS]]], input[parent[parent[S[lastElementOfS]]]], ........................................ &gt; X中的最后一个元素,然后是S。这意味着最新元素的父元素是最后一个元素。我们只是将parent[indexX] = indexLastElement添加到X的末尾。

    2. 否则找到S中最小元素的索引,S而不是>=,并将其更改为X。这里X

答案 1 :(得分:53)

Petar Minchev的解释帮助我解决了问题,但是我很难解析所有内容,因此我使用过度描述性的变量名称和大量注释进行了Python实现。我做了一个天真的递归解决方案,O(n ^ 2)解决方案和O(n log n)解决方案。

我希望它有助于清理算法!

递归解决方案

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                                                        

O(n ^ 2)动态编程解决方案

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                                                   

O(n log n)动态编程解决方案

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         

答案 2 :(得分:19)

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

答案 3 :(得分:9)

以下C ++实现还包括一些使用名为prev的数组构建实际最长增长子序列的代码。

std::vector<int> longest_increasing_subsequence (const std::vector<int>& s)
{
    int best_end = 0;
    int sz = s.size();

    if (!sz)
        return std::vector<int>();

    std::vector<int> prev(sz,-1);
    std::vector<int> memo(sz, 0);

    int max_length = std::numeric_limits<int>::min();

    memo[0] = 1;

    for ( auto i = 1; i < sz; ++i)
    {
        for ( auto j = 0; j < i; ++j)
        {
            if ( s[j] < s[i] && memo[i] < memo[j] + 1 )
            {
                memo[i] =  memo[j] + 1;
                prev[i] =  j;
            }
        }

        if ( memo[i] > max_length ) 
        {
            best_end = i;
            max_length = memo[i];
        }
    }

    // Code that builds the longest increasing subsequence using "prev"
    std::vector<int> results;
    results.reserve(sz);

    std::stack<int> stk;
    int current = best_end;

    while (current != -1)
    {
        stk.push(s[current]);
        current = prev[current];
    }

    while (!stk.empty())
    {
        results.push_back(stk.top());
        stk.pop();
    }

    return results;
}

没有堆栈的实现只是反向向量

#include <iostream>
#include <vector>
#include <limits>
std::vector<int> LIS( const std::vector<int> &v ) {
  auto sz = v.size();
  if(!sz)
    return v;
  std::vector<int> memo(sz, 0);
  std::vector<int> prev(sz, -1);
  memo[0] = 1;
  int best_end = 0;
  int max_length = std::numeric_limits<int>::min();
  for (auto i = 1; i < sz; ++i) {
    for ( auto j = 0; j < i ; ++j) {
      if (s[j] < s[i] && memo[i] < memo[j] + 1) {
        memo[i] = memo[j] + 1;
        prev[i] = j;
      }
    }
    if(memo[i] > max_length) {
      best_end = i;
      max_length = memo[i];
    }
  }

  // create results
  std::vector<int> results;
  results.reserve(v.size());
  auto current = best_end;
  while (current != -1) {
    results.push_back(s[current]);
    current = prev[current];
  }
  std::reverse(results.begin(), results.end());
  return results;
}

答案 4 :(得分:3)

以下是从动态编程的角度评估问题的三个步骤:

  1. 递归定义:maxLength(i)== 1 + maxLength(j)其中0 < j&lt;我和数组[i]&gt;阵列[j]的
  2. 重复参数边界:可能有0到1 - 1个子序列作为参数传递
  3. 评估顺序:因为它正在增加子序列,所以必须从0到n
  4. 进行评估

    如果我们以序列{0,8,2,3,7,9}为例,在索引处:

    • [0]我们将后续{0}作为基本案例
    • [1]我们有1个新的子序列{0,8}
    • [2]试图通过将索引2处的元素添加到现有子序列来评估两个新序列{0,8,2}和{0,2} - 只有一个是有效的,因此添加第三个可能的序列{0, 2}仅限于参数列表 ...

    这是有效的C ++ 11代码:

    #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;
    }
    

答案 5 :(得分:1)

这是O(n ^ 2)算法的Scala实现:

object Solve {
  def longestIncrSubseq[T](xs: List[T])(implicit ord: Ordering[T]) = {
    xs.foldLeft(List[(Int, List[T])]()) {
      (sofar, x) =>
        if (sofar.isEmpty) List((1, List(x)))
        else {
          val resIfEndsAtCurr = (sofar, xs).zipped map {
            (tp, y) =>
              val len = tp._1
              val seq = tp._2
              if (ord.lteq(y, x)) {
                (len + 1, x :: seq) // reversely recorded to avoid O(n)
              } else {
                (1, List(x))
              }
          }
          sofar :+ resIfEndsAtCurr.maxBy(_._1)
        }
    }.maxBy(_._1)._2.reverse
  }

  def main(args: Array[String]) = {
    println(longestIncrSubseq(List(
      0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15)))
  }
}

答案 6 :(得分:1)

这是另一个O(n ^ 2)JAVA实现。没有递归/ memoization来生成实际的子序列。只是一个字符串数组,用于存储每个阶段的实际LIS,以及一个数组,用于存储每个元素的LIS长度。非常简单。看看:

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);
    }
}

行动准则:http://ideone.com/sBiOQx

答案 7 :(得分:0)

找到最长增长子序列(LIS)的O(NLog(N))递归DP方法


说明

此算法涉及创建节点格式为(a,b)的树。

a代表了我们目前正在考虑添加到有效子序列的下一个元素。

b表示剩余的子数组的起始索引,如果a附加到到目前为止的子数组末尾,则将根据该索引做出下一个决定。

算法

  1. 我们从无效的根(INT_MIN,0)开始,指向数组的索引零,因为此时子序列为空,即b = 0

  2. Base Case:如果1返回b >= array.length

  3. 遍历数组中从b索引到数组末尾的所有元素,即i = b ... array.length-1。 i)如果元素array[i]是当前greater than的{​​{1}},则有资格被视为到目前为止我们添加到子序列中的元素之一。 ii)递归到节点a,其中(array[i],b+1)是我们在a中遇到的元素,有资格被附加到到目前为止的子序列中。 2(i)是要考虑的数组的下一个索引。 iii)返回通过b+1循环获得的max长度。如果i = b ... array.length大于a中的任何其他元素,请返回i = b to array.length

  4. 计算以1构建的树的级别。最后,level是所需的level - 1。那是树的最长路径中的LIS的数量。

注意事项:由于从树上很清楚,因此该算法的记忆部分被忽略了。

随机示例 从数据库备忘值中获取标记为edges的节点。 enter image description here

Java实现

x

答案 8 :(得分:0)

使用O(NLog(N))方法查找最长递增子序列
让我们维护一个数组,其中ith元素是i大小的子序列可以终止的最小可能数。

我故意避免进一步的细节,因为最受好评的答案已经解释了这一点,但是这种技术最终导致了使用set数据结构(至少在c ++中)的简洁实现。

这是c ++中的实现(假设需要严格增加最长子序列的大小)

#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;
}

答案 9 :(得分:0)

我已经使用动态编程和备注化在Java中实现了LIS。我与代码一起完成了复杂度计算,即为什么是O(n Log(base2)n)。我认为理论上或逻辑上的解释都不错,但实践证明总是更好地理解。

package com.company.dynamicProgramming;

import java.util.HashMap;
import java.util.Map;

public class LongestIncreasingSequence {

    static int complexity = 0;

    public static void main(String ...args){


        int[] arr = {10, 22, 9, 33, 21, 50, 41, 60, 80};
        int n = arr.length;

        Map<Integer, Integer> memo = new HashMap<>();

        lis(arr, n, memo);

        //Display Code Begins
        int x = 0;
        System.out.format("Longest Increasing Sub-Sequence with size %S is -> ",memo.get(n));
        for(Map.Entry e : memo.entrySet()){

            if((Integer)e.getValue() > x){
                System.out.print(arr[(Integer)e.getKey()-1] + " ");
                x++;
            }
        }
        System.out.format("%nAnd Time Complexity for Array size %S is just %S ", arr.length, complexity );
        System.out.format( "%nWhich is equivalent to O(n Log n) i.e. %SLog(base2)%S is %S",arr.length,arr.length, arr.length * Math.ceil(Math.log(arr.length)/Math.log(2)));
        //Display Code Ends

    }



    static int lis(int[] arr, int n, Map<Integer, Integer> memo){

        if(n==1){
            memo.put(1, 1);
            return 1;
        }

        int lisAti;
        int lisAtn = 1;

        for(int i = 1; i < n; i++){
            complexity++;

            if(memo.get(i)!=null){
                lisAti = memo.get(i);
            }else {
                lisAti = lis(arr, i, memo);
            }

            if(arr[i-1] < arr[n-1] && lisAti +1 > lisAtn){
                lisAtn = lisAti +1;
            }
        }

        memo.put(n, lisAtn);
        return lisAtn;

    }
}

我运行了上面的代码-

Longest Increasing Sub-Sequence with size 6 is -> 10 22 33 50 60 80 
And Time Complexity for Array size 9 is just 36 
Which is equivalent to O(n Log n) i.e. 9Log(base2)9 is 36.0
Process finished with exit code 0

答案 10 :(得分:0)

最长的子序列(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+" ");
        }

    }
}

答案 11 :(得分:0)

时间复杂度为O(nlog(n))的C ++中最简单的LIS解决方案

#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;
}

输出:
    4

答案 12 :(得分:0)

这是我使用Binary Search的Leetcode解决方案:->

import React, { Component } from 'react';
import {connect} from 'react-redux';
import {withRouter} from 'react-router-dom';
import * as action from '../store/actions/index'

export class Wishlist extends Component {


    componentDidMount() {           
        this.props.fetchWishlist(window.localStorage.getItem('email'));


    render() {
        let wishListPageContent = '<div> Loading........</div>'
        let userWishlistDetails = this.props.wishlist
        console.log(userWishlistDetails);
        if (!this.props.showLoader) {
            wishListPageContent = (
            <div> wishlist component</div>

            )
        }           
        return (
            <div>
                {wishListPageContent}
            </div>
        );
    }
}

const mapStateToProps = state => {      
    return {
        userEmail:state.authState.userEmail,
        wishlist:state.wishlistState.wishList,
        isAuthSuccess:state.authState.isAuthSuccess,
        showLoader:state.wishlistState.showLoader 
    }
}

const mapDispatchToProps = dispatch => {
    return {
        fetchWishlist:(email)=>dispatch(action.fetchWishlist(email)),
        fetchMovieDetailsForWishlist:(movieList)=>dispatch(action.fetchMovieDetailsForWishlist(movieList))
    }
}

export default withRouter(connect(mapStateToProps,mapDispatchToProps)(Wishlist));

答案 13 :(得分:0)

def longestincrsub(arr1):
    n=len(arr1)
    l=[1]*n
    for i in range(0,n):
        for j in range(0,i)  :
            if arr1[j]<arr1[i] and l[i]<l[j] + 1:
                l[i] =l[j] + 1
    l.sort()
    return l[-1]
arr1=[10,22,9,33,21,50,41,60]
a=longestincrsub(arr1)
print(a)

尽管有一种方法可以在O(nlogn)时间内解决此问题(这可以在O(n ^ 2)时间内解决),但是这种方式仍然可以提供一种动态编程方法,这也很好。

答案 14 :(得分:0)

O(n ^ 2)java实现:

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]+" ");
        }
    }

答案 15 :(得分:0)

这可以使用动态编程在O(n ^ 2)中解决。

按顺序处理输入元素并维护每个元素的元组列表。每个元组(A,B),对于元素i将表示,A =在i处结束的最长增长子序列的长度,B =在列表[i]处结束的最长增长子序列中的列表[i]的前任的索引]

从元素1开始,元素1的元组列表将是[(1,0)] 对于元素i,扫描列表0..i并找到元素列表[k],使得列表[k]&lt; list [i],元素i的A值,Ai为Ak + 1,Bi为k。如果有多个这样的元素,请将它们添加到元素i的元组列表中。

最后,找到所有元素的最大值为A(LIS的长度以元素结尾),并使用元组回溯来获取列表。

我在http://www.edufyme.com/code/?id=66f041e16a60928b05a7e228a89c3799

分享了相同的代码

答案 16 :(得分:0)

使用数组元素

检查java中用于增长最长子序列的代码

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();
    }
}

答案 17 :(得分:0)

这是java O(nlogn)实现

import java.util.Scanner;

public class LongestIncreasingSeq {


    private static int binarySearch(int table[],int a,int len){

        int end = len-1;
        int beg = 0;
        int mid = 0;
        int result = -1;
        while(beg <= end){
            mid = (end + beg) / 2;
            if(table[mid] < a){
                beg=mid+1;
                result = mid;
            }else if(table[mid] == a){
                return len-1;
            }else{
                end = mid-1;
            }
        }
        return result;
    }

    public static void main(String[] args) {        

//        int[] t = {1, 2, 5,9,16};
//        System.out.println(binarySearch(t , 9, 5));
        Scanner in = new Scanner(System.in);
        int size = in.nextInt();//4;

        int A[] = new int[size];
        int table[] = new int[A.length]; 
        int k = 0;
        while(k<size){
            A[k++] = in.nextInt();
            if(k<size-1)
                in.nextLine();
        }        
        table[0] = A[0];
        int len = 1; 
        for (int i = 1; i < A.length; i++) {
            if(table[0] > A[i]){
                table[0] = A[i];
            }else if(table[len-1]<A[i]){
                table[len++]=A[i];
            }else{
                table[binarySearch(table, A[i],len)+1] = A[i];
            }            
        }
        System.out.println(len);
    }    
}

答案 18 :(得分:0)

这是O(n ^ 2)中的Java实现。我只是没有使用二进制搜索来找到S中的最小元素,即&gt; =而不是X.我只使用了for循环。使用二进制搜索会使复杂度为O(n logn)

public static void olis(int[] seq){

    int[] memo = new int[seq.length];

    memo[0] = seq[0];
    int pos = 0;

    for (int i=1; i<seq.length; i++){

        int x = seq[i];

            if (memo[pos] < x){ 
                pos++;
                memo[pos] = x;
            } else {

                for(int j=0; j<=pos; j++){
                    if (memo[j] >= x){
                        memo[j] = x;
                        break;
                    }
                }
            }
            //just to print every step
            System.out.println(Arrays.toString(memo));
    }

    //the final array with the LIS
    System.out.println(Arrays.toString(memo));
    System.out.println("The length of lis is " + (pos + 1));

}

答案 19 :(得分:0)

这可以使用动态编程在O(n ^ 2)中求解。相同的Python代码如下: -

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)

输入:5 19 5 81 50 28 29 1 83 23

输出为:[1, 2, 1, 3, 3, 3, 4, 1, 5, 3] 5

输出列表的list_index是输入列表的list_index。输出列表中给定list_index的值表示该list_index的最长增加子序列长度。

相关问题