【问题标题】:How to know that a triangle triple exists in our array?如何知道我们的数组中存在三角形三元组?
【发布时间】:2011-07-20 10:59:24
【问题描述】:

我一直在解决以下面试练习题:
我要写一个函数:

int triangle(int[] A);

如果存在一个三元组 (P, Q, R) 使得0 < P < Q < R < N 组成,那么给定一个由N 组成的零索引数组A 返回1

A[P] + A[Q] > A[R],  
A[Q] + A[R] > A[P],  
A[R] + A[P] > A[Q].

如果这样的三元组不存在,函数应该返回0。假设0 < N < 100,000。假设数组的每个元素都是[-1,000,000..1,000,000]范围内的整数。

例如,给定数组A,这样

A[0]=10, A[1]=2, A[2]=5, A[3]=1, A[4]=8, A[5]=20

该函数应返回1,因为三元组(0, 2, 4) 满足所有必需条件。

对于数组A 这样

A[0]=10, A[1]=50, A[2]=5, A[3]=1

函数应该返回0

如果我执行三重循环,这将非常非常慢(复杂性:O(n^3))。我在想也许可以用来存储数组的额外副本并对其进行排序,并对特定数字使用二进制搜索。但我不知道如何解决这个问题。
有什么想法吗?

【问题讨论】:

  • (0, 2, 4) 不适合:0 + 2 不 > 4。
  • 他提到索引号作为答案... 10 , 5 , 8
  • 第一个条件是指PR Q的值还是索引?因为,如果 P
  • 这怎么能被标记为painless

标签: c++ math geometry


【解决方案1】:

首先进行快速排序,这通常需要 nlogn。 你可以通过二分查找省略第三个循环,它可以取 log(n)。 所以总的来说,复杂度降低到 n^2log(n)。

【讨论】:

  • 是的,我以前试过这个。并且仍然出现超时错误:-) 它期望比 n^2 log(n) 更好的解决方案。
【解决方案2】:

首先,您可以对序列进行排序。对于排序后的序列,只需检查 A[i] + A[j] > A[k] 是否为 i < j < k,因为 A[i] + A[k] > A[k] > A[j] 等,所以其他 2 个不等式自动为真。

(从现在开始,i < j < k。)

接下来,检查A[i] + A[j] > A[j+1] 就足够了,因为其他A[k] 更大(所以如果不等式适用于某些k,它也适用于k = j + 1)。

接下来,检查A[j-1] + A[j] > A[j+1] 就足够了,因为其他A[i] 甚至更小(所以如果不等式适用于某些i,它也适用于i = j - 1)。

因此,您只需进行线性检查:您需要检查至少一个 j A[j-1] + A[j] > A[j+1] 是否成立。

一共O(N log N) {sorting} + O(N) {check} = O(N log N)


解决关于负数的评论:确实,这是我在原始解决方案中没有考虑的。考虑到负数不会对解产生太大影响,因为没有负数可以是三角形三元组的一部分。事实上,如果A[i]A[j]A[k] 形成一个三角形三元组,那么A[i] + A[j] > A[k]A[i] + A[k] > A[j],这意味着2 * A[i] + A[j] + A[k] > A[k] + A[j],因此2 * A[i] > 0,所以A[i] > 0 和对称A[j] > 0A[k] > 0.

这意味着我们可以安全地从序列中删除负数和零,这是在排序后在O(log n) 中完成的。

【讨论】:

  • 这是完全错误的。您应该检查给定数组是否存在索引 p、q、r 的三元组,而不是您重新排序的数组。
  • @useless:不。显然,如果三元组存在于排序数组中,它必须存在于原始数组中(只需将索引映射回来并对它们进行排序)。您可以看到问题是对称的 w.r.t。索引交换。
  • 我不认为这只是 O(NlogN)。请提供代码看看是O(NlogN)还是O(N^3)
  • @user838204:很明显,排序是 O(N log N)。在每次迭代中准确访问 3 个数据项的数组的线性扫描显然是 O(n)。你觉得算法的哪一部分可疑?
  • "检查 A[i] + A[j] > A[k] for i A[k] " 如果 A[i] 为负数,A[i] + A[k]
【解决方案3】:

红宝石呢

def check_triangle (_array)
  for p in 0 .. _array.length-1
    for q in p .. _array.length-1
      for r in q .. _array.length-1
        return true if _array[p] + _array[q] > _array[r] && _array[p] + _array[r] > _array[q] && _array[r] + _array[q] > _array[p]
      end
    end
  end

  return false
end

只需将其移植到您选择的语言中

【讨论】:

  • 在问题中没有提到时间复杂度,但在 Codility 的真正问题中,要求解决方案必须为 O(NlogN),因此您的解决方案不适合。
【解决方案4】:

这是 Vlad 提出的算法的一个实现。现在的问题需要避免溢出,因此转换为long long

#include <algorithm>
#include <vector>

int solution(vector<int>& A) {

    if (A.size() < 3u) return 0;

    sort(A.begin(), A.end());

    for (size_t i = 2; i < A.size(); i++) {
        const long long sum = (long long) A[i - 2] + (long long) A[i - 1];
        if (sum > A[i]) return 1;
    }

    return 0;

}

【讨论】:

    【解决方案5】:

    在 Java 中:

    public int triangle2(int[] A) {
    
        if (null == A)
            return 0;
        if (A.length < 3)
            return 0;
    
        Arrays.sort(A);
    
        for (int i = 0; i < A.length - 2 && A[i] > 0; i++) {
            if (A[i] + A[i + 1] > A[i + 2])
                return 1;
        }
    
        return 0;
    
    }
    

    【讨论】:

    • 这个编码测试失败了,记住P
    • @RaySuelzer 你在说什么? n*logn 复杂度要求让你尖叫
    • @async 是的,但是再次读取条件...A triplet (P, Q, R) is triangular if 0 ≤ P &lt; Q &lt; R &lt; N and...等。当您编写Arrays.sort(A) 时,您只是丢失了原始索引..
    【解决方案6】:

    100/100 php 解决方案:http://www.rationalplanet.com/php-related/maxproductofthree-demo-task-at-codility-com.html

    function solution($A) {
        $cnt = count($A);
        sort($A, SORT_NUMERIC);
        return max($A[0]*$A[1]*$A[$cnt-1], $A[$cnt-1]*$A[$cnt-2]*$A[$cnt-3]);
    }
    

    【讨论】:

    【解决方案7】:

    Python:

    def solution(A):
        A.sort()
        for i in range(0,len(A)-2):
            if A[i]+A[i+1]>A[i+2]:
                return 1
        return 0
    

    排序:对数线性复杂度 O(N log N)

    【讨论】:

      【解决方案8】:

      我有另一种计算三角形的方法。它的时间复杂度是O(N**3),处理长数组需要很长时间。

      Private Function solution(A As Integer()) As Integer
          ' write your code in VB.NET 4.0
          Dim result, size, i, j, k As Integer
              size = A.Length
              Array.Sort(A)
              For i = 0 To Size - 3
                  j = i + 1
                  While j < size
                      k = j + 1
                      While k < size
                          If A(i) + A(j) > A(k) Then
                              result += 1
                          End If
                          k += 1
                      End While
                      j += 1
                  End While
              Next
              Return result
      End Function
      

      【讨论】:

      • 请看一下上面的代码。它提供了 100% 的正确性,但在代码性方面的性能为 25%,请参见链接:codility.com/demo/results/demoA8XYRV-2ET。任何人都可以建议我进行更改以获得 100% 的性能。提前谢谢你。
      【解决方案9】:

      PHP 解决方案:

      function solution($x){
          sort($x);
          if (count($x) < 3) return 0; 
          for($i = 2; $i < count($x); $i++){
              if($x[$i] < $x[$i-1] + $x[$i-2]){
                  return 1;
              }
          }
      
          return 0;
      }
      

      【讨论】:

        【解决方案10】:

        对我来说,从 Vlad 解决方案中反转循环似乎更容易理解。

        方程 A[j-1] + A[j] > A[j+1] 可以改为 A[k-2]+A[k-1]>A[k]。用文字解释,最后两个最大数的和应该大于当前被检查的最大值(A[k])。如果最后两个最大数(A[k-2]和A[k-1])相加的结果不大于A[k],我们可以进入循环的下一次迭代。

        此外,我们可以添加 Vlad 提到的负数检查,并提前停止循环。

        int solution(vector<int> &A) {
            sort(A.begin(),A.end());
            for (int k = A.size()-1; k >= 2 && A[k-2] > 0 ; --k) {
                if ( A[k-2]+A[k-1] > A[k] )
                    return 1;
            }
            return 0;
        }
        

        【讨论】:

          【解决方案11】:

          这是我在 C# 中的解决方案,它获得 90% 的正确性(测试 extreme_arith_overflow1 -overflow test, 3 MAXINTs- 返回错误答案)和 100% 的性能。

          private struct Pair
          {
              public int Value;
              public int OriginalIndex;
          }
          
          private static bool IsTriplet(Pair a, Pair b, Pair c)
          {
              if (a.OriginalIndex < b.OriginalIndex && b.OriginalIndex < c.OriginalIndex)
              {
                  return ((long)(a.Value + b.Value) > c.Value
                          && (long)(b.Value + c.Value) > a.Value
                          && (long)(c.Value + a.Value) > b.Value);
              }
              else if (b.OriginalIndex < c.OriginalIndex && c.OriginalIndex < a.OriginalIndex)
              {
                  return ((long)(b.Value + c.Value) > a.Value
                              &&(long)(c.Value + a.Value) > b.Value
                              && (long)(a.Value + b.Value) > c.Value);
              }
              // c.OriginalIndex < a.OriginalIndex && a.OriginalIndex < b.OriginalIndex
              return ((long)(c.Value + a.Value) > b.Value
                          && (long)(a.Value + b.Value) > c.Value
                          && (long)(b.Value + c.Value) > a.Value);
          }
          
          public static int Triplets(int[] A)
          {
              const int IS_TRIPLET = 1;
              const int IS_NOT_TRIPLET = 0;
          
              Pair[] copy = new Pair[A.Length];
          
              // O (N)
              for (var i = 0; i < copy.Length; i++)
              {
                  copy[i].Value = A[i];
                  copy[i].OriginalIndex = i;
              }
          
              // O (N log N)
              Array.Sort(copy, (a, b) => a.Value > b.Value ? 1 : (a.Value == b.Value) ? 0 : -1);
          
              // O (N)
              for (var i = 0; i < copy.Length - 2; i++)
              {
                  if (IsTriplet(copy[i], copy[i + 1], copy[i + 2]))
                  {
                      return IS_TRIPLET;
                  }
              }
          
              return IS_NOT_TRIPLET;
          }
          

          【讨论】:

            【解决方案12】:
            public static int solution(int[] A) {
                // write your code in Java SE 8
                long p, q, r;
                int isTriangle = 0;
            
                Arrays.sort(A);
                for (int i = 0; i < A.length; i += 1) {
            
                    if (i + 2 < A.length) {
                        p = A[i];
                        q = A[i + 1];
                        r = A[i + 2];
                        if (p >= 0) {
                            if (Math.abs(p) + Math.abs(q) > Math.abs(r) && Math.abs(q) + Math.abs(r) > Math.abs(p) && Math.abs(r) + Math.abs(p) > Math.abs(q))
                                return 1;
                        }
                    } else return 0;
            
            
                }
            
                return isTriangle;
            
            }
            

            上述实现在时间复杂度上是线性的。这个概念很简单,使用他们给出的公式提取一系列已排序元素的三元组。

            【讨论】:

              【解决方案13】:

              这是一个简单的 java 解决方案,分数为 100/100

              class Solution {
                public int solution(int[] A) {
                  // write your code in Java SE 8
                  Arrays.sort(A);
                  for (int i = 0; i < A.length - 2; ++i) {
                    long a = A[i] + (long) A[i + 1];
                    long b = A[i + 2];
                    if (a > b) {
                      return 1;
                    }
                  }
                  return 0;
                }
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2022-08-12
                • 1970-01-01
                • 1970-01-01
                • 2014-02-12
                • 2013-09-22
                • 1970-01-01
                • 2015-11-14
                相关资源
                最近更新 更多