Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 具有最大和加约束的最长递增子序列-可以跳过允许的元素数_Algorithm_Recursion_Dynamic Programming - Fatal编程技术网

Algorithm 具有最大和加约束的最长递增子序列-可以跳过允许的元素数

Algorithm 具有最大和加约束的最长递增子序列-可以跳过允许的元素数,algorithm,recursion,dynamic-programming,Algorithm,Recursion,Dynamic Programming,具有最大和的最长递增子序列()是一个经典的算法问题,在web上有很多解决方案。然而,我只是遇到了这个问题的一个变体,不知道如何解决它 与原来的问题相比,现在您还得到了一个数字m,它表示您最多可以从连续子范围中跳过的元素数,以便找到具有最大和的LIS。例如,对于以下数组 [1200300,3,4,5,6] LIS为1,3,4,5,6,最大和为19。但是,如果m为1,则表示在连续子范围中最多可以跳过一个元素,以便查找LIS。因此,上述解决方案是不正确的,因为在1和3之间,跳过了两个元素(本例中为20

具有最大和的最长递增子序列()是一个经典的算法问题,在web上有很多解决方案。然而,我只是遇到了这个问题的一个变体,不知道如何解决它

与原来的问题相比,现在您还得到了一个数字m,它表示您最多可以从连续子范围中跳过的元素数,以便找到具有最大和的LIS。例如,对于以下数组

[1200300,3,4,5,6]

LIS为1,3,4,5,6,最大和为19。但是,如果m为1,则表示在连续子范围中最多可以跳过一个元素,以便查找LIS。因此,上述解决方案是不正确的,因为在1和3之间,跳过了两个元素(本例中为200、300)。新的解决方案应该是3,4,5,6,因为在连续的子范围中没有跳过任何元素。问题是在给定数组和数字m时,查找具有最大和的LIS并返回子序列(而不是子序列的和或长度)。我已经被这个问题困扰了好几天,所以非常感谢您的帮助

编辑:O(n^2)解决方案现在已经足够好了,因为我完全不知道从哪里开始


编辑:m是整个数组可以跳过的累积步骤,而不是两个单独的递增子序列之间可以跳过的步骤。

这个问题可以通过使用动态规划技术来解决

调用输入数组
data
length
n

假设我们有一个数组
dp[n][n+1]
哪个条目
dp[i][j]
存储最近的索引,从
i
dp[i][j]
,从
i
开始的递增子序列的长度是
j
。如果我们有这个
dp
,您的问题的结果是直接的

现在,如何计算特定
j
dp[i][j]
?将
i
从索引
n-1
向后移动到
0
,假设我们维护另一个数组
list[n+1]
,其中
list[i]
存储所有索引
k
,其子序列从
k
开始,长度
i
。我们需要维护
list[j]
的属性:
list[j]
是递减列表,元素位于
list[j]
中的
x
y
,然后
data[x]>data[y]
当且仅当
x
。如果我们有
list[j]
对于每个长度
j
,对于
dp[i][j+1]
,我们只需要在
list[j]
中进行二进制搜索,以找到列表[j]中大于数据[i]的最小元素

int[][]dp = new int[n][n + 1];
fill(dp, -1);
List<Integer>[]lists = new List[n + 1];
for(int i = n - 1; i >= 0; i--){
    for(int j = 1; j <= n; j++){
        if(j == 1){
            dp[i][j] = i;

        }else if(!list[j - 1].isEmpty()){
            int index = binary search in list[j - 1] to get the nearest index that greater than data[i];
            dp[i][j] = dp[index][j - 1];

        }
        if(dp[i][j] == -1)
           continue;
        while(data[list[j].peekLast()] <= data[i]){
        //Remove all entries which is smaller than i in list, we can easily see that all entries which is smaller than i can only end at point at least as near as end point of i.
           list[j].pollLast();
        }
        if(list[j].isEmpty() || dp[list[j].peekLast()][j] > dp[i][j]){
        //Only add entry to list if result of new entry is nearer. 
           list[j].add(i);
        }
    }
}
int[]dp=newint[n][n+1];
填充(dp,-1);
列表[]列表=新列表[n+1];
对于(int i=n-1;i>=0;i--){

对于(int j=1;j顺便说一句,原来的LIS问题可以用O(n^2)或O(nlgn)来解决。对于这个问题,即使是O(n^2)解决方案也对我有好处。是O(n^2 log n)好吗?我不确定我是否完全理解你。你提到:如果我们有这个dp,你问题的结果是直接的。我不确定如果建立了这个dp,如何得到结果。再举一个例子,如果输入数组是[1200300,4100,50,5,6,7,8],m是1,结果是[5,6,7,8]。如果m是2,结果是[4,5,6,7,8]如果m是4,结果是[1,4,5,6,7,8]。你的算法能得到这个答案吗?@OptimusPrime使用该输入数组,因此,对于索引0,dp[0][1]=0,dp[0][2]=1,dp[0][3]=2,dp[0][4]=7,dp[0][5]=8。对于从0开始且长度为3的序列,它将从0开始并在dp 0][3结束。因此需要删除的字符数为0。如果我们需要一个从0开始且长度为4的序列,则需要删除的字符数为(dp[0][4]-0+1)-4=3。基本上,使用
dp
,我们知道段的长度以及该段中递增序列的长度,计算需要删除的字符数是很简单的。