【问题标题】:Algorithm to calculate maximum points by deleting a number通过删除数字来计算最大点的算法
【发布时间】:2018-08-24 17:36:42
【问题描述】:

我正在经历这个leetcode algorithm,我试图通过阅读解释来理解它,因为两天以来我多次阅读,但我无法理解程序是如何解决的。

这是问题陈述:

给定一个整数数组 nums,你可以对 数组。

在每个操作中,您选择任何 nums[i] 并删除它以获得 nums[i] 点。之后,您必须删除每个等于 nums[i] - 1 的元素或 nums[i] + 1.

你从 0 分开始。返回你可以得到的最大点数 通过应用此类操作赚取收益。

示例 1:输入:nums = [3, 4, 2] 输出:6 解释:删除 4 到 获得 4 分,因此 3 也被删除。然后,删除2赚取 2分。共获得 6 分。

解决方法如下:

算法

对于 nums 中的每个唯一值 k 按递增顺序,让我们维护 避免和使用的正确值,代表答案如果 我们不分别取或取 k。

如果新值 k 与之前的最大值 prev 相邻, 那么我们必须取k的答案是(k的点值)+避免, 而如果我们不能取 k,答案​​是 max(avoid, using)。 类似地,如果 k 与 prev 不相邻,则答案如果我们必须取 k 是 (k 的点值) + max(avoid, using),如果我们得到答案 不能取 k 为最大值(避免,使用)。

最后,最佳答案可能会或可能不会使用中的最大值 nums,所以我们返回 max(avoid, using)。

以及对应的Java程序:

public int deleteAndEarn(int[] nums) {
        int[] count = new int[10001];
        for (int x: nums) count[x]++;
        int avoid = 0, using = 0, prev = -1;

        for (int k = 0; k <= 10000; ++k) if (count[k] > 0) {
            int m = Math.max(avoid, using);
            if (k - 1 != prev) {
                using = k * count[k] + m;
                avoid = m;
            } else {
                using = k * count[k] + avoid;
                avoid = m;
            }
            prev = k;
        }
        return Math.max(avoid, using);
    }

我无法理解这里如何使用 avoidusing 变量以及它如何解决问题陈述。

你能帮我理解一下吗?

【问题讨论】:

  • 你有没有用调试器单步调试代码来观察“目标函数”是如何工作的?
  • 你不明白它是如何解决的或者代码是如何对应的吗?
  • @Micromuncher,是的,尝试使用 Eclipse IDE 进行调试
  • @juvian,我根据解释理解了代码。但我无法理解解释。

标签: java algorithm


【解决方案1】:

我解决了该页面上的问题。 该算法基于一个非常好的技巧。在应用算法之前先处理输入,很容易解决这个问题。 输入被重新组织成桶。

假设您有输入:1 1 2 3 3 2 2 4 4 4

你可以把它重新组织成

(Two 1s), (Three 2s), ( Two 3s), (Three 4s)

现在根据问题,如果您选择任何桶,您应该放弃包含 (bucket-element-value - 1 ) 和 (bucket-element-value + 1 ) 的桶,它们实际上是与该桶相邻的桶。

现在的问题归结为在您无法获得相邻存储桶值的约束条件下,您将如何选择存储桶以获得最大总和?

这很简单 - 当您浏览存储桶时,您可以使用存储桶做两件事。要么避免它,要么使用它。

如果你避免它,你可以达到的最大数量是多少 - 这取决于你对前一个做了什么。

amountWhenAvoided[i] = Math.max( amountWhenAvoided[i-1], amountWhenTaken[i-1] );

如果你使用它,你能达到的最大量是多少?你得到了那个桶的价值+你离开/避开前一个桶时得到的任何东西。

amountWhenTaken[i] = amountWhenAvoided[i-1] + valueOfBucket[i]

一旦你到达桶的尽头,答案将是:

Math.max( amountWhenTaken[n], amountWhenAvoided[n] )

你可以这样编码:

public int deleteAndEarn( int[] nums ) {
  //reorganize.
  int[] valueOfBucket= new int[10001] //This is the maximum size of the buckets.

  for ( int num : nums ) {
     valueOfBucket[num] += num; //Populate each bucket.
  }

  //Now go through each bucket - remember - a bucket could be empty that's fine.
  int[] amountWhenTaken = new int[n];
  int[] amountWhenAvoided = new int[n];
  amountWhenTaken[0] = 0; //Because there are no buckets to start with - buckets start from 1
  amountWhenAvoided[0] = 0;
  for ( int i = 1; i <= n; i++ ) {
     amountWhenAvoided[i] = Math.max( amountWhenAvoided[i-1], amountWhenTaken[i-1] );
     amountWhenTaken[i] = amountWhenAvoided[i-1] + valueOfBucket[i];
  }
  return Math.max( amountWhenTaken[n], amountWhenAvoided[n] );
}

如果你观察上面的代码,真的不需要用数组来做。因为数组中的当前元素依赖于它的前一个元素,所以我们可以只用两个变量来做到这一点让我们称它们为avoiding, using 那么第二个for循环可以写成:

public int deleteAndEarn( int[] nums ) {
      //reorganize.
      int[] valueOfBucket= new int[10001] //This is the maximum size of the buckets.

      for ( int num : nums ) {
         valueOfBucket[num] += num; //Populate each bucket.
      }

      //Now go through each bucket - remember - a bucket could be empty that's fine.
      int using_prev = 0;
      int avoiding_prev = 0;
      int avoiding_curr = 0;
      int using_curr = 0;
      for ( int i = 1; i <= n; i++ ) {
         avoiding_curr = Math.max( avoiding_prev, using_prev);
         using_curr = avoiding_prev + valueOfBucket[i];
         avoiding_prev = avoiding_curr;
         using_prev = using_curr;
      }
      return Math.max( avoiding_curr, using_curr );
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-12
    • 2021-01-23
    • 1970-01-01
    • 2021-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    相关资源
    最近更新 更多