从只有 3 个有效移动的数组中制作最大长度升序子数组

Posted

技术标签:

【中文标题】从只有 3 个有效移动的数组中制作最大长度升序子数组【英文标题】:Making Maximum Length Ascending Sub array from an array with only 3 valid moves 【发布时间】:2019-09-04 16:04:24 【问题描述】:

我需要用 DP 解决这个问题,问题是: 我们有一个数组,我们想在两个条件下创建一个最大大小的升序子数组:

    我们可以从左到右遍历数组一次。 我们只有两个有效的移动来创建这个子数组: 我们可以忽略遍历中数组中的下一个元素 我们可以将下一个元素放在数组的末尾或开头,并且该数组必须按升序排列

例如:

输入:arr[ ] = 0 , 3 , 10 , 7 , 6 , 5 , 14

输出:5

子数组是5 , 6, , 7 , 10 , 14

本例的解决方案是,从 10 开始,然后将 7 放在左侧,然后将 6 和 5 放在左侧,然后将 14 放在 10 的右侧

这意味着我们可以通过这个条件从左到右扩展数组

【问题讨论】:

【参考方案1】:

这是一个经典的 dp 问题,用自上而下的方法很简单。

让我们定义我们的状态 dp[c][dec][inc] - 我们现在正在查看位置 c 的元素,我们构建的序列后面的元素是位置 dec,并且前面的元素序列在位置 inc。

所以现在我们可以遍历到:

dp[c+1][dec][inc] 通过跳过当前元素 dp[c+1][c][inc] 将当前元素放在后面(仅当 a[c] dp[c+1][dec][c] 将当前元素放在前面(仅当 a[c] >= a[inc] 时有效)

示例代码(C++):

const int n = 7;
int a[] = 0, 0, 3, 10, 7, 6, 5, 14;
int dp[n+1][n+1][n+1];

int solve(int c, int dec, int inc)

    if(c > n)return 0;
    if(dp[c][dec][inc] != -1)return dp[c][dec][inc];

    dp[c][dec][inc] = solve(c+1,dec,inc); //skip element
    if(inc==0 && dec==0) //if our sequence is empty, try appending element to sequence
        dp[c][dec][inc] = max(dp[c][dec][inc], 1 + solve(c+1,c,c));
    else if(a[c] >= a[inc])//we can extend our array [dec, ..., inc] because current element can be put to front
        dp[c][dec][inc] = max(dp[c][dec][inc], 1 + solve(c+1,dec,c));
    else if(a[c] <= a[dec])//we can extend our array [dec, ..., inc] because current element can be put to back
        dp[c][dec][inc] = max(dp[c][dec][inc], 1 + solve(c+1,c,inc));

    return dp[c][dec][inc];


int main()

    memset(dp, -1, sizeof dp);
    cout<<solve(1,0,0);

复杂度 O(n^3)

【讨论】:

以上是关于从只有 3 个有效移动的数组中制作最大长度升序子数组的主要内容,如果未能解决你的问题,请参考以下文章

(c++) 如何有效地制作升序(dyn.solution)

返回一个整数数组最大子数的和

leetcode第53题最大子数和

数组中的第K个最大元素

返回一个整数数组最大子数的和

返回一个整数数组最大子数的和