593 · 石头游戏 II (区间dp石子合并 翻倍循环问题)

链接:石头游戏 II

题解:

cpp 复制代码
class Solution {
public:
    /**
     * @param arr: An integer array
     * @return: An integer
     */
    int stoneGame(vector<int> &arr) {
        int len = arr.size();
        if (len <= 1) {
            return 0;
        }

        int m = 2 * len;
        vector<int> a(m);
        for (int i = 0; i < m; ++i) {
            a[i] = arr[i % len];
        }

        vector<int> prefix(m + 1, 0);
        for (int i = 0; i < m; ++i) {
            prefix[i + 1] = prefix[i] + a[i];
        }

        // memo 必须是 m x m,因为 left/right 最大到 m-1
        vector<vector<int>> memo(m, vector<int>(m, -1));

        // 先算出整个 2n 区间的所有子区间结果
        dfs(a, 0, m - 1, memo, prefix);

        int result = INT_MAX;
        // 枚举所有长度为 len 的区间,取最小值
        for (int i = 0; i < len; ++i) {
            result = min(result, memo[i][i + len - 1]);
        }
        return result;
    }

    int dfs(const vector<int>& a, int left, int right,
            vector<vector<int>>& memo, vector<int>& prefix) {
        if (left == right) {
            memo[left][right] = 0;   // 注意是二维
            return 0;
        }
        if (left > right) {
            return 0;
        }
        if (memo[left][right] != -1) {
            return memo[left][right];
        }

        int result = INT_MAX;
        for (int i = left; i < right; ++i) {
            int l = dfs(a, left, i, memo, prefix);
            int r = dfs(a, i + 1, right, memo, prefix);
            // 原来写成了 l + f,应该是 l + r
            result = min(result, l + r + prefix[right + 1] - prefix[left]);
        }
        memo[left][right] = result;
        return result;
    }
};
cpp 复制代码
class Solution {
public:
    int stoneGame(vector<int> &arr) {
        int n = arr.size();
        if (n <= 1) return 0;

        int m = 2 * n;
        vector<int> a(m);
        for (int i = 0; i < m; ++i) {
            a[i] = arr[i % n];
        }

        vector<int> prefix(m + 1, 0);
        for (int i = 0; i < m; ++i) {
            prefix[i + 1] = prefix[i] + a[i];
        }

        vector<vector<int>> memo(m, vector<int>(m, -1));

        int result = INT_MAX;
        for (int i = 0; i < n; ++i) {
            result = min(result, dfs(i, i + n - 1, memo, prefix));
        }

        return result;
    }

    int dfs(int left, int right,
            vector<vector<int>>& memo,
            const vector<int>& prefix) {
        if (left == right) {
            return 0;
        }

        if (memo[left][right] != -1) {
            return memo[left][right];
        }

        int result = INT_MAX;
        for (int k = left; k < right; ++k) {
            int leftCost = dfs(left, k, memo, prefix);
            int rightCost = dfs(k + 1, right, memo, prefix);
            int mergeCost = prefix[right + 1] - prefix[left];
            result = min(result, leftCost + rightCost + mergeCost);
        }

        memo[left][right] = result;
        return result;
    }
}; 
cpp 复制代码
// 本题解信息来源于【九章算法】。请勿进行商业转载,非商业转载请注明出处。
public class Solution {
    /**
     * @param A an integer array
     * @return an integer
     */
    public int stoneGame2(int[] A) {
        // Write your code here
        int n = A.length;
        if (n <= 1)
            return 0;

        int[][] dp = new int[2 * n][2 * n];

        int[] sum = new int[2 * n + 1];

        for (int i = 1; i <= 2 * n; ++i) {
            sum[i] = sum[i - 1] + A[(i - 1) % n];
        }

        for (int i = 0; i < 2 * n; ++i) {
            dp[i][i] = 0;
        }

        for(int len = 2; len <= 2 * n; ++len)
            for(int i= 0;i < 2 * n && i + len - 1 < 2 * n; ++i) {
                int j = i + len - 1;
                dp[i][j] = Integer.MAX_VALUE;
                for (int k = i; k < j; ++k) {
                    if (dp[i][k] + dp[k+1][j] + sum[j + 1] - sum[i] < dp[i][j])
                        dp[i][j] = dp[i][k] + dp[k+1][j] + sum[j + 1] - sum[i];
                }
        }

        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < n; ++i)
            if (dp[i][i + n - 1] < ans)
                ans = dp[i][i + n - 1];
        return ans;
        
    }
}
相关推荐
文丑颜不良啊1 天前
LeetCode1481~1500题目解析
java·leetcode
文丑颜不良啊1 天前
LeetCode1381~1400题目解析
java·leetcode
Tisfy1 天前
LeetCode 3882.网格图中最小异或路径:动态规划
算法·leetcode·动态规划
A boy CDEF girl1 天前
算法题专栏:优选算法
数据结构·算法·leetcode
驭渊的小故事1 天前
LeetCode 算法题解:滑动窗口与数组合并的实战应用
算法·leetcode·职场和发展
文丑颜不良啊1 天前
LeetCode1501~1520题目解析
java·leetcode
Navigator_Z1 天前
LeetCode //C - 1311. Get Watched Videos by Your Friends
c语言·算法·leetcode
Pniubi2 天前
力扣42接雨水(动态规划法)
算法·leetcode·职场和发展
Pniubi2 天前
力扣46全排列(回溯(递归))
算法·leetcode·职场和发展
文丑颜不良啊2 天前
LeetCode1461~1480题目解析
java·leetcode