最长递增子序列 2d
Longest increasing subsequence 2d
我有 n 个按固定顺序排列的 m 整数数组。我需要找到一个最长的递增子序列,使得子序列中的每个元素都恰好属于一个数组。我能比 O(n2) 做得更好吗?
与@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)
是的,它可以通过动态规划和记忆来完成...复杂度为 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) 次迭代时 - 由于备忘地图可用性,我们不需要重新计算(递归)整个 0 到第 i 个索引,并且它将复杂性从指数级降低到 nlogn 级。
我有 n 个按固定顺序排列的 m 整数数组。我需要找到一个最长的递增子序列,使得子序列中的每个元素都恰好属于一个数组。我能比 O(n2) 做得更好吗?
与@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)
是的,它可以通过动态规划和记忆来完成...复杂度为 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) 次迭代时 - 由于备忘地图可用性,我们不需要重新计算(递归)整个 0 到第 i 个索引,并且它将复杂性从指数级降低到 nlogn 级。