区间DP总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_36346463/article/details/79347486

Scramble String

Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.

Below is one possible representation of s1 = "great":

    great
   /    \
  gr    eat
 / \    /  \
g   r  e   at
           / \
          a   t

To scramble the string, we may choose any non-leaf node and swap its two children.

For example, if we choose the node "gr" and swap its two children, it produces a scrambled string "rgeat".

    rgeat
   /    \
  rg    eat
 / \    /  \
r   g  e   at
           / \
          a   t

We say that "rgeat" is a scrambled string of "great".

Similarly, if we continue to swap the children of nodes "eat" and "at", it produces a scrambled string "rgtae".

    rgtae
   /    \
  rg    tae
 / \    /  \
r   g  ta  e
       / \
      t   a

We say that "rgtae" is a scrambled string of "great".

Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.


class Solution {
public:
    /**
     * @param s1: A string
     * @param s2: Another string
     * @return: whether s2 is a scrambled string of s1
     */
    bool isScramble(string &s1, string &s2) {
        // write your code here
        int n1 = s1.size();
        int n2 = s2.size();
        if (n1 != n2) {
            return false;
        }
        vector<vector<vector<bool>>> dp(n1 + 1, vector<vector<bool>>(n1 + 1, vector<bool>(n1 + 1, false)));
        for (int k = 1; k <= n1; k++) {
            for (int i = 0; i + k - 1 < n1; i++) {
                for (int j = 0; j + k - 1 < n1; j++) {
                    if (k == 1) {
                        dp[i][j][k] = (s1[i] == s2[j]);
                    } else {
                        for (int x = 1; x < k; x++) {
                            bool cond1 = dp[i][j][x] && dp[i + x][j + x][k - x];
                            bool cond2 = dp[i][j + k - x][x] && dp[i + x][j][k - x];
                            dp[i][j][k] = cond1 || cond2 || dp[i][j][k];
                        }
                    }
                }
            }
        }
        return dp[0][0][n1];
    }
};

吹气球

有n个气球,编号为0n-1,每个气球都有一个分数,存在nums数组中。每次吹气球i可以得到的分数为 nums[left] * nums[i] * nums[right],left和right分别表示i气球相邻的两个气球。当i气球被吹爆后,其左右两气球即为相邻。要求吹爆所有气球,得到最多的分数。

样例

给出 [4, 1, 5, 10]
返回 270

nums = [4, 1, 5, 10] burst 1, 得分 4 * 1 * 5 = 20
nums = [4, 5, 10]    burst 5, 得分 4 * 5 * 10 = 200 
nums = [4, 10]       burst 4, 得分 1 * 4 * 10 = 40
nums = [10]          burst 10, 得分 1 * 10 * 1 = 10

总共的分数为 20 + 200 + 40 + 10 = 270


class Solution {
public:
    /**
     * @param nums: A list of integer
     * @return: An integer, maximum coins
     */
    int maxCoins(vector<int> &nums) {
        // write your code here
        int n = nums.size();
        if (n == 0) {
            return 0;
        }
        vector<int> arr(n + 2, 0);
        for (int i = 0; i < n; i++) {
            arr[i + 1] = nums[i];
        }
        arr[0] = 1;
        arr[n + 1] = 1;
        vector<vector<int>> dp(n + 2, vector<int>(n + 2, 0));
        for (int k = 1; k <= n; k++) {
            for (int i = 1; i + k - 1 <= n; i++) {
                int j = i + k - 1;
                for (int x = i; x <= j; x++) {
                    int midvalue = arr[i - 1] * arr[x] * arr[j + 1];
                    dp[i][j] = max(dp[i][j], dp[i][x - 1] + dp[x + 1][j] + midvalue);
                }
            }
        }
        return dp[1][n];
    }
};

Maximum Subarray III

Given an array of integers and a number k, find k non-overlapping subarrays which have the largest sum.

The number in each subarray should be contiguous.

Return the largest sum.

Notice

The subarray should contain at least one number

Example

Given [-1,4,-2,3,-2,3], k=2, return 8

/* 这题属于动态规划里比较难的一题。首先定义状态,f[i][j]表示:在前i个元素中取出j个不重叠的子数组的和的最大值(也就
     * 要将前i个元素组成的数组划分成j个部分,每个部分求最大子数组,然后相加)。状态定义好了之后,需要找到状态之间的关
     * ,也就是求动态转移方程。可以将f[i][j]拆分成两部分来看,第一部分是f[x][j - 1],x为j - 1~ i
     * - 1之间的任意值,表示前x个元素中取j - 1个子数组的和的最大值。第二部分是[x, x + 1, ..., i -
     * 1]数组,求这个数组的maximum subarray(可以理解为在数组[0, 1, ..., x - 1, x, ..., i-
     * 1]中任意切一刀,分成两部分。index为x - 1的地方就是那一刀切的地方,第一部分是[0, 1, ..., x - 1],第二部分是[x, x +
     * 1, ..., i - 1])。由此得到动态转移方程为:f[i][j] = f[x][j - 1] + maxSubarray([x, x + 1, ..., i - 1])。求max
     * subarray的方法可以参考maximum subarray那道题。
     */
    int maxSubArray2(vector<int> &nums, int k) {
        // write your code here
        if (nums.size() == 0 || k == 0 || k > nums.size()) {
            return 0;
        }
        int n = nums.size();
        vector<vector<int>> dp(n + 1, vector<int>(k + 1, INT_MIN));
        // init
        for (int i = 0; i <= n; i++) {
            dp[i][0] = 0;
        }
        for (int j = 1; j <= k; j++) {
            for (int i = j; i <= n; i++) {
                int cur_sum = 0;
                int max_sum = INT_MIN;
                for (int x = i - 1; x >= j - 1; x--) {
                    cur_sum = max(cur_sum + nums[x], nums[x]);
                    max_sum = max(max_sum, cur_sum);
                    dp[i][j] = max(dp[i][j], dp[x][j - 1] + max_sum);
                }
            }
        }
        return dp[n][k];
    }





猜你喜欢

转载自blog.csdn.net/weixin_36346463/article/details/79347486