【问题标题】:Most efficient way to remove consectuive elements from an array? Java从数组中删除连续元素的最有效方法?爪哇
【发布时间】:2020-06-05 08:06:18
【问题描述】:

我正在尝试以最有效的方式解决这个问题。

给定一个整数数组,不断删除三个连续相同的整数,直到数组中不再有三个连续相同的元素,并返回这些元素出现的次数。

例如 int[] {4,4,7,7,6,6,6,7,4} 将返回 3。当我们删除连续 6 的 int 数组时,变为 {4,4,7,7,7, 4} 在下一次迭代中,连续的 7 被删除,剩下 {4,4,4} 等等。

int[] {3,4,4,5,5,3} 将返回 0。

我已经尝试了十几次使用不同的集合,但有人说我的代码需要很多操作并且速度太慢。所以我只想使用数组,但我被卡住了。这是我的代码:

    public static int getNumberOfRepetitions(int[] arr) {

    int[] arr2 = new int[arr.length];
    int counter= 0;
    int index = 0;

    for (int x= 0;x<arr.length;x++) {
        if (x < arr.length - 2) {
            if (arr[x] == arr[x + 2] && arr[x] == arr[x + 2]) {
                counter++;
                x = x + 2;
                continue;
            }
            arr2[index] = arr[x];
            index++;
        }
        if (x < arr.length - counter * 3) {
            arr = arr2;
            arr2 = new int[arr.length];
            index = 0;
            x = -1;
        }
    }
    return counter;
}

算法迭代一个数组并将项目添加到第二个数组,如果有连续的元素,它会添加到一个计数器并跳过它们。在最后一次迭代中,arr 设置为 arr2 并且 for 循环应该重置。

到目前为止,我无法弄清楚如何终止代码,所以我得到了一个无限循环。我是编程新手,不胜感激。

【问题讨论】:

  • "当我们移除连续6的int数组时变成{4,4,7,7,7,4}"为什么最后7和4交换了位置?应该是{4,4,7,7,4,7},不是吗?
  • @kaya3 是的,你是对的,我的错。
  • 这里的逻辑运算对我来说没有意义:if (arr[x] == arr[x + 2] && arr[x] == arr[x + 2])。请检查您是否有错字。

标签: java arrays algorithm loops for-loop


【解决方案1】:

您的逻辑有几处错误。这里没有指出它们中的每一个,而是一种新方法:

private static int getNumberOfRepetitions(int[] arr) {
    int[] arr2 = new int[arr.length];
    int counter= 0;
    int j = 0;
    for (int i : arr) {
        arr2[j++] = i;
        if (j > 2) {
            if (arr2[j - 1] == arr2[j - 2] && arr2[j - 1] == arr2[j - 3]) {
                counter++;
                j -= 3;
            }
        }
    }
    return counter;
}

在这里,我们将元素一个一个地添加到一个新数组中,并为该数组维护一个索引。当新数组中有 3 个元素时,比较最后 3 个元素。如果相等,则将索引 ('j') 减 3。

【讨论】:

  • 如果您有任何问题,请告诉我。
  • 哇,这么简单的解决方案。 +1 --- 比my large answer 短得多。感觉我应该删除我的长答案,但是这个答案有 O(n) 空间复杂度,而我的有 O(1) 空间复杂度,所以我会留下我的大约。 --- 不过,为了代码简单,我更喜欢这个。
  • 谢谢@Andreas,这对你来说意义重大!
  • @HarshalParekh 哇,解决方案可以这么简单!非常感谢。
【解决方案2】:

有人告诉我,我的代码需要太多操作而且太慢了。

这是正确的,因为您实际上可以在不修改数组的情况下做到这一点。

由于这是一项需要你完成的任务,我将向你展示如何做到这一点,而无需编写任何代码。

  1. 将计数器初始化为0,并从数组的开头开始迭代。

  2. 找到下一个(第一个)三元组。
    如果没有找到,你就完成了,所以返回计数器值。

          start
            │  end
            │   │
    4,4,7,7,6,6,6,7,4
    
  3. 您找到了要删除的三元组,因此将计数器加 1。

  4. 比较周围的值。首先比较前后的值。
    如果不同,请跳至第 7 步。

          start
            │  end
            │   │
    4,4,7,7,6,6,6,7,4
          └───────┘ are they equal?
    
  5. 当周围的值相等时,级联三元组有两种可能性,一个是之前的额外值,或者是之后的额外值。
    如果之前/之后的额外值都与周围的值不同,请跳至步骤 7。

          start                                start
            │  end                               │  end
            │   │                    O R         │   │
    4,4,7,7,6,6,6,7,4                        4,7,6,6,6,7,7,4,4
        └─┴───────┘ are they equal?            └───────┴─┘ are they equal?
    
  6. 展开要移除的序列,返回第3步重复级联搜索。

      start                       start
        │        end                │        end
        │         │       O R       │         │
    4,4,7,7,6,6,6,7,4             4,7,6,6,6,7,7,4,4
    
      start                       start
        │        end                │        end
        │         │       O R       │         │
    4,4,7,7,6,6,6,7,4             4,7,6,6,6,7,7,4,4
    └─┴─────────────┘             └─────────────┴─┘   are they equal?
    
  7. 现在我们需要寻找一个更复杂的不相交三元组。

    12344433255666527
     ││└┴┘││││││││││   simple triplet found (step 2-3)
     │└───┴┘││││││││   surrounding triplet found (step 4-6)
     │      │││└┴┘││   another simple triplet found
     │      │└┴───┘│   surrounding triplet found
     └──────┴──────┘   disjoint triplet found
    

    为此,我们需要跟踪之前删除的序列。

      ┌ prevStart
      │    ┌ prevEnd
      │    │ ┌ start
      │    │ │    ┌ end
    12344433255666527
     └──────┴──────┘   are they equal?
    

    如果前一个结束是新开始之前的2个位置,并且之前,之间和之后的3个值相等,那么我们找到了一个不相交的三元组。 展开要删除的序列以包括先前序列、当前序列和新三元组,然后返回步骤 3 重复级联搜索。

  8. 您现在已找到要删除的部分,并将计数器增加了适当的次数,因此从 end 位置开始,返回第 2 步以搜索下一个三元组。

如您所见,数组永远不会被修改,我们只是在数组中处理索引值。这需要更多代码,而不是简单地修改数组并重试,但新代码运行得更快,因为我们不必复制数组元素。

祝你好运。 ?

【讨论】:

  • 优秀的解释和那些图表!
  • @dariosicty 非常感谢,它帮助了我,我得到了有效的解决方案,我会尽快发布!
【解决方案3】:

这是一种递归方法的尝试。这类似于数组展平或查找匹配的括号,但复杂的是,我们最多可以将三个元素绑定到已删除的部分。

经过少量测试的 JavaScript 代码(欢迎反例/错误):

// Returns [count, leftmostIndex]
function f(A, i=0, same=1){
  // Base case, end of list
  if (i > A.length - 1)
    return [0, A.length];
  
  // We can remove this block
  if (A[i] == A[i+1] && same == 2){
    let [count, j] = f(A, i + 2, 1);
    return [count + 1, j];
  }
    
  // Same but the count is less than
  // three, keep accumulating
  if (A[i] == A[i+1])
    return f(A, i + 1, same + 1);
  
  // Next element is different,
  // see if the next section has
  // collapsed blocks
  let [count, j] = f(A, i + 1, 1);
  
  // There is no available element
  // to try and accumulate
  if (j > A.length - 1)
    return [count, i];
    
  // The next available element
  // is the same
  if (A[i] == A[j]){
    // We've reached a count of three,
    // remove this block
    if (same == 2){
      return [count + 1, j + 1];

    // Haven't reached a count of
    // three, try one more section
    } else {
      let [count2, j2] = f(A, j + 1, 1);
      if (A[i] == A[j2])
        return [1 + count + count2, j2 + 1];
      else
        return [count + count2, i];
    }
        
  // The next available element is
  // different
  } else {
    return [count, i];
  }
}

var As = [
  [4,4,7,7,6,6,6,7,4],
  [5,7,7,7,8,4,4,5,5,6,6,6,6,6,6,5,4]
];

for (let A of As){
  console.log(JSON.stringify(A));
  console.log(JSON.stringify(A.map((_, i) => i)));
  console.log(JSON.stringify(f(A)));
}

【讨论】:

    猜你喜欢
    • 2018-03-31
    • 1970-01-01
    • 2012-10-22
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 1970-01-01
    • 2011-02-24
    相关资源
    最近更新 更多