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;
        
    }
}
相关推荐
aqiu1111111 小时前
【C++算法打怪专栏】LeetCode 402. 移掉 K 位数字(单调栈 + 贪心)
c++·算法·leetcode
第六种自由2 小时前
[路飞]_Leetcode 22. 括号生成
javascript·算法·leetcode
longlongzihan3 小时前
LeetCode 24.两两交换链表中的节点:虚拟头结点与指针
算法·leetcode·链表
Xin7703 小时前
LeetCode 105. 从前序与中序遍历序列构造二叉树(递归分治法)
leetcode
longlongzihan3 小时前
从LeetCode 19. 删除链表的倒数第 N 个结点深入理解“哨兵节点”
c++·算法·leetcode·链表
java_nnnn4 小时前
LeetCode刷题滑动窗口(长度最小的子数组)
算法·leetcode·职场和发展
yi0114 小时前
DAY27: LeetCode 110. 平衡二叉树 | 在递归中判断是否平衡
人工智能·笔记·python·算法·leetcode·二叉树·递归
Nil20814 小时前
leetcode 763划分字母区间
算法·leetcode·职场和发展
不会就选b15 小时前
算法日常・每日刷题--<动态规划>20
算法·leetcode·动态规划