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

查找使数组的所有元素等于0的最小移动次数

养鸿运
2023-03-14

1.索引x处元素可以在一次移动中直接移动到x+1,x+2位置或x-1,x-2位置,之后移动计数将增加。

例如,在数组中,最小移动将为31:

  1. 索引4处的所有8个元素可以在总共16次移动中移动到索引0(因为所有8个元素都需要2次移动)。移动:16.
  2. 索引5中的3个元素可以在3步中移动到索引3(3个元素每步移动1步),索引5中剩余的5个元素可以在10步中移动到索引2(5个元素每步移动2步,所以总共移动10步)。移动=16+3+10=29。
  3. 索引6中的2个元素在2次移动中移动到索引7(每次移动1次)。移动=29+2=31。

下面是我的代码,但不在工作状态

int solution1(vector < int > & c) {

  int alen = c.size();
  if (alen == 0) return -1;

  int move = 0;
  int moved = 0;
  for (int j = 0; j < alen; ++j) {
    if (c[j] < 0) {
      for (int k = j + 1; k < alen; ++k) {
        moved = 0;
        if (c[k] > 0) {
          c[j] = 0 - c[j];
          if (c[j] <= c[k]) {
            c[k] = c[k] - c[j];
            moved = c[j];
            c[j] = 0;
          } else {
            c[j] = c[k] - c[j];
            moved = c[k];
            c[k] = 0;
          }
          if (k - j >= 2) {
            if ((k - j) % 2)
              move += ((k - j + 1) / 2) * moved;
            else
              move += ((k - j) / 2) * moved;
          } else {
            move += moved;
          }
          if (c[j] == 0) break;
        }
      }
    } else if (c[j] > 0) {
      for (int kk = j + 1; kk < alen; ++kk) {
        moved = 0;
        if (c[kk] < 0) {
          c[kk] = 0 - c[kk];
          if (c[j] <= c[kk]) {
            c[kk] = c[j] - c[kk];
            moved = c[j];
            c[j] = 0;
          } else {
            c[j] = c[j] - c[kk];
            moved = c[kk];
            c[kk] = 0;
          }
          if (kk - j >= 2) {
            move += ((kk - j) / 2) * moved;
          } else {
            move += moved;
          }
          if (c[j] == 0) break;

        }
      }
    }

  }
  if (move > 0) return move;
  else return -1;
}

共有1个答案

司徒宇
2023-03-14

给定的问题需要建设性的解决办法。由于移动的范围扩展到(x-2,x+2),我们保持了一个大小为2的adverse数组,它保持了当我们将偶数和奇数索引从i位置移动到第(i+1)位置时移动元素的成本。我们从左到右迭代给定的数组,并计算将所有仍然留在左边的元素移到索引i的左边的代价。这样的成本可以使用开销数组来计算(参考下面的代码)。如果在任何一步,有可能用正整数抵消掉一些负整数,那么我们首先提取那些元素,如果在中和过程的下一步中,他从i移动到(i+1),那么这些元素将花费我们+1。

观察的重点是,如果我们继续从左到右移动索引x处的元素,只会增加点(x+1)、(x+3)、(x+5)、……处移动的代价。下面是相同的运行代码:https://ideone.com/tfunng

int solve(vector<int> v) {
    vector<int> overhead(2,0);
    int num_of_moves = 0, sum = 0;
    for(int i = 0; i < v.size(); i++) {
        num_of_moves += overhead[i % 2];
        int left = abs(v[i]);
        if((sum > 0 && v[i] < 0) || (sum < 0 && v[i] > 0)) {
            int used = min(abs(sum), abs(v[i]));
            int diff = min(overhead[(i + 1) % 2], used);
            overhead[(i + 1) % 2] -= diff;
            overhead[i % 2] -= min(overhead[i % 2], (used - diff));
            left -= used;
        }
        sum += v[i];
        overhead[(i + 1) % 2] += abs(left);
    }

    assert(sum == 0);
    return num_of_moves;
}

该解决方案的整体运行时复杂度为O(n)。

 类似资料:
  • 我看到一个解决方案,我不能理解是什么立场背后的解决方案,我想理解为什么解决方案是正确的(什么立场背后的想法),问题是“最小移动到相等的数组元素”。我看到的解决方案是: 我不明白为什么元素之和减去最小元素乘以数组长度就能得到问题的解? 编辑:这是对问题的解释:给定一个大小为n的非空整数数组,求出使所有数组元素相等所需的最小移动次数,其中一个移动是将n-1个元素递增1。示例: 输入:[1,2,3]

  • 我正在阅读这个问题的极客为极客网站。

  • 给定任何自然数数组,例如:[2,1,2,3]查找数组是否可以转换为Max数组(打印-“是”)或如果不能(打印-“否”) 使其成为最大数组 - 将数组的每个元素转换为等于其最大元素。在上面的例子中,它将是[3,3,3,3],但是通过遵循这些规则 - 一次将任何两个元素增加1(正好是2个元素。不能一次增加一个或多个元素) 多次执行此操作,直到将每个元素转换为最大元素(如果可能,请打印“YES”,否则打

  • 我想在“价格”数组中找到最高的元素,然后在“字母”数组中打印相应的元素 我需要一些关于我能做什么的建议。我尝试过输出字母[索引],但由于我认为的范围,我遇到了一个错误。我对编码很陌生,所以这真的困扰着我。

  • 给定一个大小为n的数组,包含0和1以及两次运算,找出使所有元素都为0的最小运算次数。 操作: > < li> 如果第(I ^ 1)个元素为1,并且从第(I ^ 2)个到所有连续元素为0或不存在(如果I ^ 2 = n),则翻转第I个元素。(0 例如,上述操作适用于: 在这个元素上 1100年 或 在这个元素上 1011 n 例如,输入: 1,0,0,0 产量:15 解释: 1000 -