【问题标题】:Maximum distance between two different element in an array数组中两个不同元素之间的最大距离
【发布时间】:2018-02-21 08:00:10
【问题描述】:

我有一个问题,我需要找到数组中两个不同元素之间的最大距离。

例如:给定一个数组 4,6,2,2,6,6,4 ,该方法应返回 5 作为最大距离。

我可以使用两个 for 循环来解决问题,但这不是优化的解决方案。我正在尝试通过在单个 for 循环中进行优化。

这是我目前的解决方案:

int [] A = {4,6,2,2,6,6,4};
int N = A.length;
int result = 0;

for (int i = 0; i < N; i++){
    for (int j = i; j < N; j++) {
        if(A[i] != A[j]){
            result = Math.max(result, j - i);
        }
    }
}

// tried below code but it is not efficient
//      for (int i = 0; i < N; i++){
//          
//          if(A[N-1] != A[i]){
//              result = Math.max(result, N-1-i);
//          }
//      }

System.out.println(result);

如何在时间复杂度方面做得更好?

【问题讨论】:

  • 怎么样有2个数组,原始数组A和反向数组R,对于A中的每个元素,获取A和R中的indexOf(element)。

标签: java arrays algorithm integer


【解决方案1】:

简单(不是嵌套)循环就够了,但是两种情况要分进去 帐户:最好的结果是

  4,6,2,2,6,6,4
    ^         ^ - moving first

  4,6,2,2,6,6,4
  ^         ^   - moving last

例如:[4, 2, 4, 4, 4] moving first 给出了答案,而[4, 4, 4, 2, 4] moving last 应该使用。

  int first = 0;
  int last = A.length - 1;

  // 1st case: moving "first"
  while (first < last) {
    if (A[first] == A[last])
      first++;
    else
      break;
  }

  int diff1 = last - first;

  first = 0;
  last = A.length - 1;

  // 2nd case: moving "last"
  while (first < last) {
    if (A[first] == A[last])
      last--;
    else
      break;
  }

  int diff2 = last - first;

  // result is the max between two cases
  int result = diff1 > diff2
    ? diff1
    : diff2;

所以我们有O(N) 时间复杂度。

编辑:让我们证明至少有一个索引是0length - 1。让我们通过矛盾来做到这一点。假设我们有这样的解决方案

  a, b, c, .... d, e, f, g
        ^ ..... ^  <- solution indexes (no borders)

c 左边的项目必须是d,否则我们可以采用ab 索引并有一个改进的 解决方案。 d 右侧的项目必须是 c 或者我们可以再次将最后一个索引推到右侧并获得更好的解决方案。所以我们有

  d, d, c .... d, c, c, c
        ^ .... ^  <- solution indexes 

现在,由于d &lt;&gt; cc..d 是一个解决方案)我们可以改进解决方案为

  d, d, c .... d, c, c, c
        ^ .... ^           <- solution indexes 
  ^       ....          ^  <- better solution

我们有一个矛盾(假设的解决方案不是一个 - 我们有更好的选择),这就是为什么至少一个索引必须是 0length - 1

现在我们有 2 个场景要测试:

  a, b, ..... y, z
     ^  ......   ^ <- moving first
  ^  ......   ^    <- moving last

我们可以将这两个条件组合成if,并且只有一个循环:

  int result = 0;

  for (int i = 0; i < A.length; ++i)
    if (A[i] != A[A.length - 1] || A[0] != A[A.length - 1 - i]) {
      result = A.length - i - 1;

      break;
    }

【讨论】:

  • 你能解释一下为什么我们需要移到最后吗?
  • @roger_that:非常同意,我很抱歉我的第一个简洁的回答。添加了示例和证明。
  • 感谢您的证明。我也是这么想的。但我觉得代码可以简化一点。你能看看我的回答吗?
【解决方案2】:

这可以在一个循环中完成

考虑一下。

与索引i 之间的最大差异可以在开始元素和ii 和最后一个元素之间

int main() {
    vector<int> v {4, 6, 2, 2, 6, 6, 4};
    int start = 0, end = v.size() -1;
    int result = 0;
    for(int i=0; i< v.size(); ++i)
    {
        if(v[i] != v[start])
        {
            result = max(result, i);
        }
        if(v[i] != v[end])
        {
            result = max(result, end - i);
        }
    }
    return result;
}

我们之所以能够实现O(N)算法是因为

考虑v = [4, 4, 2, 3, 4, 4]

在索引i = 0 处,我们检查是否可以找到最大可能距离,即与最后一个元素的距离,但由于它们相同,我们不能考虑它。

i = 0 这个数组的最大可能答案是 5。

[4, 4, 2, 3, 4, 4]
 ^

i = 1,我们再次检查数组的两端是否仍然相同,所以我们继续。

真正的节省来自我们不必检查每个其他条目 保持起点在i = 0

所以,在i = 2,我们发现可以用数组的结尾来获取最大值

[4, 4, 2, 3, 4, 4]
 ^     ^        ^
start  i       end

这与保持start 不变并保持运行器循环相同。

【讨论】:

  • 很好地实现了这个想法;我宁愿坚持 array A (如问题)
  • @DmitryBychenko 谢谢。我实际上是指用一个循环而不是两个 while 循环来执行此操作。
  • 如果你比较v[i] != v[end] || v[start] != v[end - i],你可以返回第一个差异——或者当v.size()/2 &lt;= i:所有元素相等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-21
  • 2014-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-29
  • 1970-01-01
相关资源
最近更新 更多