【问题标题】:Longest increasing subsequence 2d最长递增子序列 2d
【发布时间】:2015-10-15 20:17:49
【问题描述】:

我有 n 个按固定顺序排列的 m 个整数数组。我需要找到一个最长递增的子序列,以使子序列中的每个元素都恰好属于其中一个数组。我能比 O(n2) 做得更好吗?

【问题讨论】:

  • 假设m 可以和n 一样大,并且您必须至少阅读所有需要的元素Lambda(n^2)。换句话说,你不能。

标签: algorithm subsequence


【解决方案1】:

根据@svs,这是不可能在小于 O(m * n) 的时间内实现的。但是,在实践中,一旦您知道不可能在其中找到更长的子序列,就可以通过终止对数组的迭代来减少平均最差时间。

简单循环:

maxList = []
for arr in arrays:
    last = arr[0] - 1
    tempList = []
    for element in arr:
        if element > last:
            tempList.append(element)
            if len(tempList) > len(maxList):
                    maxList = tempList

        else:
            tempList = [element]
        last = element

return (maxList, iters)

忽略冗余循环迭代:

maxList = []
for arr in arrays:
    if len(maxList) == len(arr):
        break

    last = arr[0] - 1
    tempList = []
    for (index, element) in enumerate(arr):
        if element > last:
            tempList.append(element)
            if len(tempList) > len(maxList):
                    maxList = tempList[:]
        else:
            tempList = [element]

        # if continuing looking down the array could not result in a longer
        # increasing sequence
        if (len(tempList) + (len(arr) - (index + 1)) <= len(maxList)):
            break

        last = element

return (maxList, iters)

【讨论】:

    【解决方案2】:

    是的,它可以通过动态编程和记忆来完成......复杂性将是 O(n Log(base2) n) 别名 O(nLogn)。为了证明这一点 - 我采用了一个外部静态复杂度变量(命名为复杂度)并在每次递归迭代中递增以表明复杂度将为 O(nLogn) -

    package com.company.dynamicProgramming;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class LongestIncreasingSequence {
    
        static int complexity = 0;    // <-- here it is init to 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++;                // <------ here it is incremented to cover iteration as well as recursion..
    
                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
    

    关键是,在每次递归中,我们都会计算第 i 个索引处的 LIS 是什么,并存储在 memo map 中。此外,当我们处于第 (i+1) 次迭代时 - 由于 memo map 的可用性,我们不需要重新计算(重复)整个 0 到第 i 个索引,它将复杂性从指数级降低到 nlogn 级。

    【讨论】:

      猜你喜欢
      • 2013-07-03
      • 2020-04-15
      • 1970-01-01
      • 2018-11-01
      • 2011-09-02
      • 2015-12-12
      相关资源
      最近更新 更多