Java 两人硬币博弈:动态规划中的最优序列追踪

Java 两人硬币博弈:动态规划中的最优序列追踪,java,algorithm,memory,runtime,dynamic-programming,Java,Algorithm,Memory,Runtime,Dynamic Programming,两名玩家轮流选择一枚外围硬币。最后,我们计算两名球员得到的分数之间的差异,假设他们发挥最佳。例如列表{4,3,2,1}, 最佳顺序为4,3,2,1。然后我会得到4+2=6分,对手得到4分。 现在我开发了一个算法,如下所示: 我的工作是打印出分数,以及索引中的最佳顺序。所以在数组{4,3,2,1}中,最佳序列是0,1,2,3 最大运行时间和内存不应超过n^2。 因此,我采用自下而上的方法实现了上述算法,这意味着在I*j表中,根据我的算法,子问题会一个接一个地解决,直到唯一的主要问题出现在右上角(其

两名玩家轮流选择一枚外围硬币。最后,我们计算两名球员得到的分数之间的差异,假设他们发挥最佳。例如列表{4,3,2,1}, 最佳顺序为4,3,2,1。然后我会得到4+2=6分,对手得到4分。 现在我开发了一个算法,如下所示:

我的工作是打印出分数,以及索引中的最佳顺序。所以在数组{4,3,2,1}中,最佳序列是0,1,2,3

最大运行时间和内存不应超过n^2。 因此,我采用自下而上的方法实现了上述算法,这意味着在I*j表中,根据我的算法,子问题会一个接一个地解决,直到唯一的主要问题出现在右上角(其中I=0,j=n-1)。它可以计算分数,但我不知道如何在运行时跟踪最佳序列,因为当我逐子问题计算子问题时,只有分数会被保存并用于下一个问题,而导致最终结果的序列很难跟踪

我试图创建成对或多维数组列表来记录序列及其对应的备忘[I][j]。。。。。。好吧,它们工作了,但是需要的内存将大于n^2,这在我的任务中是不允许的

那么,有没有更好的想法,不需要那么多的内存空间

任何帮助都将不胜感激,干杯

我的代码:

public int maxGain(int[] values) {

    int n = values.length;
    int [][] memo = new int[n][n];

    for (int i = 0; i < n; i++)
        memo[i][i] = values[i];

    for (int i = 0, j = 1; j < n; i++, j++)
        memo[i][j] = Math.max(values[i], values[j]);

    for (int k = 2; k < n; k++) {
        for (int i = 0,  j = k; j < n; i++, j++) {
            int a = values[i] + Math.min(memo[i + 2][j], memo[i + 1][j - 1]);
            int b = values[j] + Math.min(memo[i + 1][j - 1], memo[i][j - 2]);
            memo[i][j] = Math.max(a, b);
        }
    }

    return memo[0][n - 1];
}
public int maxGain(int[]值){
int n=值。长度;
int[][]备忘录=新的int[n][n];
对于(int i=0;i
我猜您的问题与类似,只是需要做一些小改动:

JAVA O(N)存储器 对于第二种解决方案,空间复杂度可能为
N

类解决方案{
公共布尔值最大增益(int[]nums){
如果(nums==null)
返回true;
int length=nums.length;
int[]dp=新的int[长度];
对于(int i=length-1;i>=0;i--){
对于(int j=i;j-1;
}
}
参考文献

你只挑最大的元素,对手也一样吗?@ HyRik4贪婪的方法在这里不起作用,考虑下面的输入[1, 2, 9,2 ]。第一个玩家最好在第一步中选择1,而不是2。@Igor我会在第一步中选择9。@Henrik4请看问题的第一句:>两个玩家轮流选择一个外部硬币。@Igor什么是外部硬币?这不是我担心的,因为我已经成功地计算了分数,我将编辑这个问题并添加我的src代码,这样你们会更好地理解:)我编辑了这个问题,我希望你们能理解我的意思。是的,我在寻找最大为O(n^2)的空间复杂度。感谢详细的答案,他们将其优化为O(n)复杂度,这是令人惊讶的!如何根据我的src代码打印出最佳序列?这就是我想问的,比如arr[4,7,2,3],最优结果的索引顺序是[3,0,1,2]。
class Solution {
    public boolean maxGain(int[] nums) {
        int length = nums.length;
        int[][] dp = new int[length][length];

        for (int i = 0; i < length; i++)
            dp[i][i] = nums[i];

        for (int l = 1; l < length; l++)
            for (int i = 0; i < length - l; i++) {
                int j = i + l;
                dp[i][j] = Math.max(nums[i] - dp[i + 1][j], nums[j] - dp[i][j - 1]);
            }

        return dp[0][length - 1] > -1;
    }
}
class Solution:
    def max_gain(self, nums):
        length = len(nums)
        memo = [[-1 for _ in range(length)] for _ in range(length)]

        @functools.lru_cache(None)
        def f():
            def helper(nums, i, j):
                if i > j:
                    return 0

                if i == j:
                    return nums[i]

                if memo[i][j] != -1:
                    return memo[i][j]

                cur = max(nums[i] + min(helper(nums, i + 2, j), helper(nums, i + 1, j - 1)),
                          nums[j] + min(helper(nums, i, j - 2), helper(nums, i + 1, j - 1)))

                memo[i][j] = cur
                return cur

            score = helper(nums, 0, length - 1)
            total = sum(nums)
            return 2 * score >= total

        return f()
class Solution {
    public boolean maxGain(int[] nums) {
        if (nums == null)
            return true;

        int length = nums.length;
        int[] dp = new int[length];

        for (int i = length - 1; i >= 0; i--) {
            for (int j = i; j < length; j++) {
                if (i == j)
                    dp[i] = nums[i];

                else
                    dp[j] = Math.max(nums[i] - dp[j], nums[j] - dp[j - 1]);
            }
        }

        return dp[length - 1] > -1;
    }
}