当前位置: 首页 > 知识库问答 >
问题:

通过删除一个数来计算最大点的算法

齐鹏程
2023-03-14

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

以下是如何解决它的解释:

算法

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);
    }

我无法理解这里是如何使用avideusing变量的,以及它是如何解决问题语句的。

你能帮我理解这一点吗。

共有1个答案

闻人昕
2023-03-14

我把那页上的问题看了一遍。该算法基于一个非常好的技巧。当您在应用算法之前首先处理输入时,解决这个问题是非常容易的。输入被重新组织到桶中。

假设您有输入: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] );
}
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 );
 }
 类似资料:
  • 我目前正在做一个赋值,在这个赋值中,我需要使用一个数组中顶点相连的图。我需要计算图中的每个节点,并尝试递归地这样做。 到目前为止,我一直在尝试这样做,但结果并不像我所希望的那样。我试图调试代码,似乎计数是按预期的方式工作的(计数每个非空节点)。问题似乎是,当递归堆栈结束时,比如countFrom达到了5,并且该方法返回5,堆栈中的下一个递归调用就不会“记住这一点”,而是返回它之前计算过的数量,比如

  • 给定一组数,找出任意数适合的最小倍数和 < li >集合中的数字可以多次使用(或根本不使用)以获得“总和” < li >这组数字可以是任何正十进制数(即< code>1,4,4.5 ) < li >给定/任意数阈值可以是任意小数(即< code>5 ) > < li> 找出给定数字能与最小余数相适应的倍数组合 找到一个数字可以四舍五入到的最小“总和” 每个组合中使用的实际数字本身对于这个特定的挑战

  • 问题内容: 我在Sqlite中有一个查询,其中涉及复杂的列计算,可以这样说: 我想将此计算选择为,但我还需要将其用作另一种计算的组成部分: 不幸的是,这会产生错误: 我知道我可以简单地重复计算: 但是,假设操作复杂且昂贵,是否有什么方法可以在以后重新引用它而不必重新计算呢? 问题答案: 您需要使用子查询。 结果

  • 我想知道实际上是如何工作的。我认为这是一种计算数组长度的简单方法,并希望在使用它之前适当地理解它。我对指针算术不是很有经验,但根据我的理解,给出了数组第一个元素的地址。将按地址转到数组的末尾。但是不应该给出这个地址的值吗。而是打印出地址。我真的很感激你帮我把指针的东西弄清楚。 下面是我正在研究的一个简单示例:

  • 我有一个分辨率为1,1的光栅图像。 我想将分辨率降低到4,4,但仍然具有构成新4,4像素的像素的最大值。 我可以通过使用降低分辨率: 但是,这将为您提供构成此新像素的每个像素的平均最大值。 我试图将光栅转换为矩阵,因此它采取以下形式: 是否有方法计算行1至4和列1至4内所有值的最大值? 这还需要应用于整个矩阵,该矩阵具有1000个行和列,返回到矩阵形式,如下所示:

  • 问题内容: 我在计算本月下一个最后一天何时发送预定的通知时遇到问题。 这是我的代码: 这是导致问题的线,我相信: 如何使用日历正确设置下个月的通知的最后一天? 问题答案: 这将返回当前月份的实际最大值。例如,现在是leap年的2月,因此它返回29作为。