【问题标题】:Triangle: Determine if an array includes a triangular triplet (Codility)三角形:判断一个数组是否包含三角形三元组(Codility)
【发布时间】:2017-07-04 18:19:30
【问题描述】:

这是来自 Codility 的三角问题:

给出了一个由 N 个整数组成的零索引数组 A。
三元组 (P, Q, R) 是三角形的,如果 0 ≤ P

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

写一个函数:

int solution(vector<int> &A);  

给定一个由 N 个整数组成的零索引数组 A,返回 1 如果此数组存在三角形三元组并返回 0 否则。

例如,给定数组 A 使得:
A[0] = 10, A[1] = 2, A[2] = 5, A[3] = 1, A[4] = 8, A[5] = 20 三元组 (0, 2, 4) 是三角形的,函数应该返回 1。

给定数组 A 使得:
A[0] = 10, A[1] = 50, A[2] = 5, A[3] = 1
函数应该返回 0。

假设:

N 是 [0..100,000] 范围内的整数;
数组 A 的每个元素都是范围内的整数 [−2,147,483,648..2,147,483,647]。

这是我在 C++ 中的解决方案:

int solution(vector<int> &A) {
    if(A.size()<3) return 0;

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

    for(int i=0; i<A.size()-2; i++){
        //if(A[i] = A[i+1] = A[i+2]) return 1;
        if(A[i]+A[i+1]>A[i+2] && A[i+1]+A[i+2]>A[i] && A[i+2]+A[i]>A[i+1]){
            return 1;
        }
    }
    return 0;
}

我已经检查了那里的 cmets,所有解决方案似乎都与我的相似。
然而,虽然其他人声称获得了 100%,但我只获得了 93% 的分数。
我得到了所有的测试用例,除了一个:

extreme_arith_overflow1
溢出测试,3 MAXINTs

我假设这个案例有一些这样的输入:
[2147483647, 2147483647, 2147483647]

所以我将它添加到自定义测试用例中,结果显然应该是 1,而答案却是 0。
我也试过[1900000000, 1900000000, 1900000000],答案还是0。
但是,[1000000000, 1000000000, 1000000000] 正确答案为 1。

谁能告诉我为什么会出现这个结果?
非常感谢。

【问题讨论】:

  • 听起来像是正常的整数溢出。 en.wikipedia.org/wiki/Integer_overflow
  • 制作 long long int 的向量
  • 刚刚查了一下:这个例子中的 int 是 32 位,long int 保证 32 位,在 Unix 上可能是 64,而 long long int 保证 64,所以这就是使用 long long int 的原因在这个情况下。感谢您的帮助!
  • 不错的解决方案。我有同样的结果。我通过将每个比较的一侧转换为(长)来修复它。所以在你的行中,我会在三个地方这样做:if((long)A[i]+A[i+1]&gt;A[i+2] &amp;&amp; ...

标签: c++ algorithm math integer-overflow


【解决方案1】:

我的 Java 解决方案为 100/100,时间复杂度为 O(N*log(N))

用cmets解释逻辑

// you can also use imports, for example:
// import java.util.*;

// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");
import java.util.Arrays;

class Solution {

    public int solution(int[] A) {

    int N = A.length;
    if (N < 3) return 0;
    Arrays.sort(A);

    for (int i = 0; i < N - 2; i++) {

        /**
         * Since the array is sorted A[i + 2] is always greater or equal to previous values
         * So A[i + 2] + A[i] > A[i + 1] ALWAYS
         * As well ass A[i + 2] + A[i + 1] > A[i] ALWAYS
         * Therefore no need to check those. We only need to check if A[i] + A[i + 1] > A[i + 2]?
         * Since in case of A[i] + A[i + 1] > MAXINT the code would strike an overflow (ie the result will be greater than allowed integer limit)
         * We'll modify the formula to an equivalent A[i] > A[i + 2] - A[i + 1]
         * And inspect it there
         */
        if (A[i] >= 0 && A[i] > A[i + 2] - A[i + 1]) {

            return 1;
        }
    }

    return 0;
}

基本上,当您检查X + Y 整数值时,如果大于整数限制,代码将在溢出时失败。因此,我们可以简单地检查等效语句 if X &gt; Z - Y,而不是检查 if X + Y &gt; Z(简单的数学不是吗?)。或者,您可以始终使用long,但这将是一个更糟糕的解决方案记忆。

还要确保跳过负数,因为三角形不能有负边值。

干杯

【讨论】:

  • 是的,但是,我可以看到每个人都在左右说“如果数组已排序......”。为什么要对数组进行排序?你怎么知道,当你对一个数组进行排序时,三角形边缘将与原始数组相同。您确实明白,对数组进行排序并在排序后的数组上搜索三角形就像“在全新的数组上搜索三角形”,因为索引会混合(影响 P
  • 这就是我的意思,索引现在混淆了,排序后无法知道P
  • 或者在排序之前我们可以克隆数组。从排序数组中找到三元组后,我们需要搜索它们的索引以确保它们满足 P
  • 或者也许这只是问题中的一个错误,因为人们说他们在没有 P
  • @cool 你读错了任务。没有人关心元素有什么索引,问题很简单,是否存在三角形三元组?元素的顺序在三角形中没有意义。
【解决方案2】:

Java 100%:

public int solution(int[] A){
        Arrays.sort(A);

        for(int i=0;i<A.length-2;i++){
            if(  
                 ((long)A[i] + (long)A[i+1] > A[i+2]) &&  
                 ((long)A[i+1] + (long)A[i+2] > A[i]) &&
                 ((long)A[i] + (long)A[i+2] > A[i+1]) 
               )
            return 1;   
        }
        return 0;
    }

【讨论】:

  • 我真的不明白,因为任务说:A triplet (P, Q, R) is triangular if 0 ≤ P &lt; Q &lt; R &lt; N and A[P] + A[Q] &gt; A[R], A[Q] + A[R] &gt; A[P], A[R] + A[P] &gt; A[Q]. 所以这意味着,indizes 必须按升序排列。通过排序,您正在分配新的 indizes。我弄错了吗?
  • 没关系,因为数组中的任何 3 个项目都将肯定满足 0
  • 如果定义只说它们必须不同,你怎么能假设 Q = P + 1 和 R = P + 2?
  • António - 如果存在 P+1 != Q 或 Q+1 != R 的三角形,那么也必须存在 P+1 = Q 和 Q+1 = R 的三角形。 : 因为 A[Q] > A[Q-1] 我们知道 A[Q] + A[R] > A[Q - 1]。由于 A[Q] + A[P] > A[R] 和 A[Q - 1] > A[P] 我们知道 A[Q] + A[Q - 1] > A[R]。由于 A[P] + A[R] > A[Q] 和 A[Q-1] > A[P] 我们知道 A[P] + A[R] > A[Q]。 (你可以用 Q+1 代替 R 做类似的证明)
【解决方案3】:

这是我用 Python 编写的干净解决方案。我在 Codility 获得了 100% 的分数。 这种逻辑可以适应任何其他编程语言。

注意:如果数组是排序的,你只需要检查两个连续元素之和是否大于下一个元素(A[i] + A [i+1] > A[i+2]),因为在那种情况下,其他两个条件 (A[i+1]+A[i+2] > A[i], A[i]+A[ i+2] > A[i+1]) 永远为真。

希望对你有帮助。

def solution(A):

    #edge case check
    if len(A) < 3:
        return 0

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

【讨论】:

  • 0+1>2, 1+2>0, 2+0>1 1+2>3, 2+3>1, 3+1>2 .... 这些是需要的组合来解决这个问题。
  • @Fran Sandi,你不需要#'edge case 检查,它已经包含在 for 循环中。您可以争辩说,在 len(A)
【解决方案4】:

这里有几个问题

  1. 三角形的边不能为 0,因为它是长度。您必须添加该检查,否则您将无法通过这种极端情况。即不会得到 100%。

  2. 由于您可以拥有所有 INT_MAX 或 LONG_MAX 的输入数组(请参阅 http://www.cplusplus.com/reference/climits/),因此您需要将总和存储在 double 或 long long 中。

  3. 您不必在这里检查所有三个条件,即

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

    如果你已经对数组进行了排序

    A[Q] + A[R] > A[P] &&
    A[R] + A[P] > A[Q]

    总是正确的,因为 0 ≤ P A[P] + A[Q] > A[R]。

您已经对 A.size() https://github.com/naveedrasheed/Codility-Solutions/blob/master/Lesson6_Sorting/triangle.c 添加了一个 C 实现。 您可以将其与解决方案进行比较。

【讨论】:

    【解决方案5】:

    我这里用了3个for循环(不对数组进行排序)来解决这个问题。

    public static int solution(int[] A) {
    
        for (int p = 0; p < A.length; p++) {
            for (int q = p + 1; q < A.length; q++) {
                for (int r = q + 1; r < A.length; r++) {
    
                    if ((A[p] + A[q] > A[r]) && (A[q] + A[r] > A[p]) && (A[r] + A[p] > A[q])) {
                        System.out.println(A[p] + "  " + A[q] + " " + A[r]);
                        return 1;
                    }
                }
            }
        }
        return 0;
    }
    

    【讨论】:

      【解决方案6】:

      诀窍是在数组中找到一个小于数组中其他两个之和的数字,因此对数组进行排序然后搜索该数字即可解决。转换为 long 有时总和的值会超过允许的整数

      public int solution(int[] A) {
             int n = A.length;
             if(n<3){
                 return 0;
             }
             Arrays.sort(A);
             for(int i=2; i<n; i++){
                 if(A[i]<(long)A[i-1]+(long)A[i-2])
                 return 1;
             }
             return 0;
          }
      

      【讨论】:

        【解决方案7】:

        我在 C# 中的解决方案得分为 100。

            using System;
            
            class Solution {
                public int solution(int[] A) {
                    // write your code in C# 6.0 with .NET 4.5 (Mono)
                    if(A.Length) <3)
                       return 0;
        
                    Array.Sort(A);
                    int p,q,r;
                    for(int i=A.Length-1;i>1; i--){
                        p = A[i];
                        q = A[i-1];
                        r = A[i-2];
                        if(p+q>r && q+r > p && r+p > q)
                            return 1;
                    }
                    return 0;
                }
            }
        

        【讨论】:

          【解决方案8】:

          JavaScript 中的简单解决方案。

          注意:我排除了任何边可以为 0 或更少的选项。其余的都是一样的。

          function solution(A) {
              if (A.length < 3) return 0;
          
              A.sort((a, b) => (a - b));
          
              for (i = A.length - 1; i >= 0; i--) {
                  if (A[i - 2] <= 0) return 0;
          
                  if (
                      A[i] + A[i - 1] > A[i - 2] &&
                      A[i] + A[i - 2] > A[i - 1] &&
                      A[i - 1] + A[i - 2] > A[i]
                      ) return 1;
              }
              return 0;
          }
          

          【讨论】:

          • 您的答案可以通过添加有关代码的作用以及它如何帮助 OP 的更多信息来改进。
          【解决方案9】:

          我对这个问题的解决方案,用 Swift 编写。

          public func Triangle(_ A : inout [Int]) -> Int {
          
              A.sort()
          
              for i in 1..<A.count-1 {
                  if(A[i] + A[i-1] > A[i+1]) {
                      print("Triangle has edges: \(A[i-1]), \(A[i]), \(A[i+1])")
                      return 1
                  }
              }
              return 0
          }
          
          A = [10,2,5,1,8,20]
          print("Triangle: ", Triangle(&A))
          

          【讨论】:

          • c++解决方案溢出时会崩溃,所以你不会得到任何积分。
          【解决方案10】:

          或者您可以更改 if 子句,如下所示

          if(A[i]>A[i+2]-A[i+1] && A[i+1]>A[i]-A[i+2] && A[i+2]>A[i+1]-A[i])
          

          用减法代替加法。

          【讨论】:

            【解决方案11】:

            100% 有效,在不同场景下进行了测试。

            我认为上述解决方案并未涵盖所有可能性 结合 P,Q,R

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

            索引组合

            0+1>2, 1+2>0, 2+0>1

            1+2>3, 2+3>1, 3+1>2

            ....

            这些是解决此问题所需的组合。

            //Triangle
                /**
                 * A[P] + A[Q] > A[R],
                   A[Q] + A[R] > A[P],
                   A[R] + A[P] > A[Q]
                 */
                public int triangleSolution(int[] A) {
                int status = 0;
                for(int i=0; i<A.length; i++) {
                    int[] B = removeTheElement(A, i);
                    for(int j=0; j<B.length; j++) {
                        int[] C = removeTheElement(B, j);
                        for(int k=0; k<C.length; k++) {
                            if((A[i] + B[j] > C[k]) &&
                               (B[j] + C[k] > A[i]) &&
                               (C[k] + A[i] > B[j])) {
                                return 1;
                            }
                        }
                    }
                }
                return status;
            }
            
                // Function to remove the element 
                public int[] removeTheElement(int[] arr, int index) 
                { 
                    // Create another array of size one less 
                    int[] anotherArray = new int[arr.length - 1]; 
            
                    // Copy the elements except the index 
                    // from original array to the other array 
                    for (int i = 0, k = 0; i < arr.length; i++) { 
            
                        // if the index is 
                        // the removal element index 
                        if (i == index) { 
                            continue; 
                        } 
            
                        // if the index is not 
                        // the removal element index 
                        anotherArray[k++] = arr[i]; 
                    } 
            
                    //Java >8
                    //IntStream.range(0, arr.length).filter(i -> i != index).map(i -> arr[i]).toArray();
            
                    return anotherArray;
                }
            

            【讨论】:

            • 当然还有更多情况,但是如果您对数组进行排序,则不必检查它,而不是 O(N^3) 您将有 O(N*log2(N))。跨度>
            • 如果我们对数组排序,那么a_p a_q a_r + a_q > a_p,因为a_r是最大的三倍。剩余条件:a_p + a_q > a_r 如果你取 p,q,r 不连续 2 第一个不等式仍然为真,但如果三角形存在,则最后一个 p 和 q 将满足剩余的不等式。
            【解决方案12】:
            //My solution in C++ it avoid overflow
            
            inline int Triangle(vector<int> &A) {
            
                if(A.size() < 3) return 0;
                sort(A.begin(), A.end());
                for(int i = 0; i < (int)A.size() - 2; ++i){
                    int P = A[i], Q = A[i + 1], R =A[i + 2];
                    if(( R - P - Q < 0) && ( P - Q - R < 0) && (Q - R - P < 0))
                       return 1;
                }
                return 0;
            }
            

            【讨论】:

              【解决方案13】:

              Ruby 100% 解决方案

              def solution(a)
                arr = a.select{|x| x >=0 }.sort
                arr.each_with_index do |p, pi|
                  arr[(pi+1)..-1].each_with_index do |q, qi|
                    arr[(qi+pi+2)..-1].each do |r|
                      break if p+q <=r
                      break if p+r <=q
                      break if r+q <=p
                      return 1
                    end
                  end
                end
                0
              end
              

              【讨论】:

                【解决方案14】:

                我的 java 解决方案 100/100 我们不比较加法,而是比较减法,因为我们可能有一个 Integer.MAX_VALUE,我们将得到损坏的数据。 p>

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

                【讨论】:

                  【解决方案15】:

                  这是 javascript 解决方案(TC: O(N*log(N)) ,以防万一你们想要:)。

                  function solution(A) {
                      if(A.length<3) return 0;
                  
                      A.sort((a,b)=>b - a);
                  
                      for(let i = 0,j = i+1;j < A.length-1;j++){
                          let p = A[j],q = A[j+1],r = A[i]
                  
                          if(r - p > q) i++;
                          else if(r - p < q) return 1;
                      }
                  
                      return 0;
                  }
                  

                  【讨论】:

                    【解决方案16】:

                    排序现在不起作用,这是 Codility 修复的错误。现在,我正在使用这段代码来获得 93%

                    你可以看到下面的结果:

                    Codility test Results

                    0

                     public static int solution(int[] unfilteredArray) {
                        int[] array = filterLessThanOneElements(unfilteredArray);
                    
                        for(int i = 0; i <= (array.length - 3) ; i++) {
                            long p = array[i];
                            for(int j = i+1; j <= (array.length - 2); j++) {
                                long q = array[j];
                                for(int k = j+1; k <= (array.length - 1); k++) {
                                    long r = array[k];
                                    if((p + q > r) && (q + r > p) && (r + p > q)) {
                                        return 1;
                                    }
                                }
                            }
                        }
                    
                        return 0;
                    }
                    
                    // The mose efficient way to remove duplicates
                    // TIME COMPLEXITY : O(N)
                    private static int[] filterLessThanOneElements(int[] unfilteredArray) {
                        int k = 0;
                        for(int i = 0; i < unfilteredArray.length; i++) {
                            if(unfilteredArray[i] > 0) {
                                unfilteredArray[k++] = unfilteredArray[i];
                            }
                        }
                        return Arrays.copyOfRange(unfilteredArray, 0, k);
                    }
                    

                    【讨论】:

                      【解决方案17】:

                      简单的变化:首先,您观察到负整数不能成为三角形三元组的一部分。这意味着您可以将所有 int 转换为 unsigned int,并且不会再有任何溢出。

                      【讨论】:

                        【解决方案18】:

                        100/100 JavaScript 解决方案

                        function solution(A) {
                            let l = A.length;
                            if (l < 3) {
                                return 0;
                            }
                            A.sort((a, b) => a - b);
                            for (let i = 0; i < l - 2; i++) {
                                let [p, q, r] = [A[i], A[i + 1], A[i + 2]];
                                if (p + q > r && q + r > p && r + p > q) {
                                    return 1;
                                }
                            }
                            return 0;
                        }
                        

                        【讨论】:

                          【解决方案19】:

                          如果您不想使用 Array.sort,则以下内容可以 100% 的正确性和 100% 的性能以及复杂性检测到 O(N*log(N))。

                          class Solution {
                          public int solution(int[] A) {
                              int ans = 0;
                              int p1 = -1;
                              int p2 = -1;
                              int p1Pos = 0;
                              int p2Pos = 1;
                              int cur = -1;
                          
                              if(A.length > 2){
                                  p1 = A[0];
                                  p2 = A[1];
                          
                                  for(int i = p2Pos + 1; i < A.length; i++){
                                      if(p1 > p2){
                                          p2 = A[p1Pos];
                                          p1 = A[p2Pos];
                                          A[p2Pos] = p2;
                                          A[p1Pos] = p1;
                                      }
                                      cur = A[i];
                                      //System.out.println(p1 + " " + p2 + " " + cur);
                                      if(p1 > -1 && p2 > -1){
                                          //the test for a triangle
                                          if (cur > -1 && 
                                              ((p1 == p2 && p2 == cur) || 
                                              ((p1 + p2 > cur) && (p1 + cur > p2) && ( cur + p2 > p1)))){
                                              return 1;
                                          //bubble sort...sort of
                                          }else if (p2 > cur){
                                              A[p2Pos] = cur;
                                              A[i] = p2;
                                              if(p1 < cur){
                                                  p1 = cur;
                                                  p1Pos = p2Pos;
                                              }
                          
                                              p2Pos = i;
                                          
                                          } else if(cur > -1 
                                              &&(p1 + p2 <= cur) ){
                                                  p2Pos++;
                                                  p1Pos++;
                          
                                                  p1=p2;
                                                  p2=cur;
                                          }
                                      }else{
                                          //find the first two positive numbers
                                          if((p2 < 0 || p1 < 0) && cur > -1){
                                              if(p1 < 0){
                                                  p1 = cur;
                                                  p1Pos = i;
                                              }else{
                                                  p2 = A[i];
                                                  p2Pos = i;
                                              }
                                          }
                                      }
                                  }
                              }
                          
                              return ans;
                            }
                          }
                          

                          当我做这个时,我想也许我可以通过修改冒泡排序来解决这个问题。我选择了两个枢轴点(p1 和 p2),同时确保 p2 > p1。 当我遍历数组时,我确保如果 p2 > cur,p2 会冒泡,如果 p1 > cur,p1 也会冒泡。此外,我注意到具有负数的三个点的任何组合都不能是三角形。所以我忽略了负面因素。我还意识到,如果数组恰好包含三个且只有最大整数,我就会遇到问题。为了解决这个问题,我测试了 p1 == p2 == cur。诚然,使用 BigInteger 解决它可能会更好。

                          【讨论】:

                            【解决方案20】:

                            javascript 100% 上代码

                            function solution(a) {
                            if (a.length < 3) {
                                return 0;
                            }
                            
                            a.sort((a, b) => a - b);
                            
                            for (let i = 0; i < a.length - 2; i++) {
                                if (a[i] + a[i + 1] > a[i + 2]) {
                                    return 1;
                                }
                            }
                            
                            return 0;
                            }
                            

                            【讨论】:

                              【解决方案21】:

                              我的 100% JavaScript 解决方案,时间复杂度为 O(N*log(N)):

                              function solution(A) {
                              
                                  A.sort((a, b) => a - b);
                                
                                  for (let i = 0, len = A.length - 2; i < len; i++) {
                                      const [P, Q, R] = [A[i], A[i + 1], A[i + 2]];
                                      if (P + Q > R && Q + R > P && R + P > Q) {
                                          return 1;
                                      }
                                  }
                                  
                                  return 0;
                              
                              }
                              

                              【讨论】:

                                【解决方案22】:

                                因为integer overflow

                                试试这个:

                                int a1 = 1900000000;
                                int a2 = 1900000000;
                                int sum = a1+a2;  // sum will be -494967296
                                

                                编辑:使用 long long int。

                                long long int sum01 = A[i] + A[i+1];
                                long long int sum12 = A[i+1] + A[i+2];
                                long lont int sum02 = A[i] + A[i+2];
                                
                                if (sum01 > A[i+2] && sum12 > A[i] && sum02 > A[i+1])
                                    return 1;
                                

                                【讨论】:

                                • 我不相信使用减法会改变任何事情,因为它也会溢出(比如INT_MIN - INT_MAX
                                • 是的,你是对的。在这种情况下,请使用 long long int。
                                猜你喜欢
                                • 1970-01-01
                                • 2023-03-18
                                • 1970-01-01
                                • 2014-08-01
                                • 2011-10-30
                                • 2014-04-21
                                • 1970-01-01
                                • 2013-04-24
                                • 1970-01-01
                                相关资源
                                最近更新 更多