【问题标题】:codility absolute distinct count from an arraycodility 数组中的绝对不同计数
【发布时间】:2011-08-09 11:24:51
【问题描述】:

所以我昨天参加了 codility 面试测试,今天被告知我失败了,不幸的是,无论是 codility 还是雇主都没有向我提供任何其他信息,说明我在哪里搞砸了,所以我希望能帮助我知道我哪里出错了.我知道 codility 非常重视程序运行的速度以及它对大量数据的行为方式。现在我没有复制粘贴问题,所以这是我记得的大致内容

  1. 计算数组 a 中绝对不同的元素数量,这意味着如果数组中有 -3 和 3,这些数字不不同,因为|-3|=|3|。我认为一个例子会更好地澄清它

a={-5,-3,0,1,-3} 结果将是 4,因为该数组中有 4 个绝对不同的元素。

问题还指出 a.length 将 数组按升序排序 但我真的不明白为什么我们需要它排序

如果您认为我遗漏了一些问题,我会尝试进一步澄清问题。

这是我的代码

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;


public class test2 {

    int test(int[] a){
        Set<Integer> s=new HashSet<Integer>();

        for(int i=0;i<a.length;i++){
            s.add(Math.abs(a[i]));

        }
        return s.size();

    }

    public static void main(String[] args) {
        test2 t=new test2();
        int[] a={1,1,1,2,-1};
        System.out.println(t.test(a));

    }

}

【问题讨论】:

  • 如果 a={-5,-3,0,1,-3} = 4 那么 a={-5,-5,-6,-6,-6} = 0 或 1 ?如果为 0,则 'a={-5,-3,0,1,-3}' 应返回 3
  • 为什么 {-5,-5,-6,-6,-6} = 0 甚至 1。它是 2 -> |-5| = 5 和 |-6| = 6

标签: c# java python c++ algorithm


【解决方案1】:

如果数组已排序,您可以通过查看邻居来找到重复项。要比较绝对值需要从开始和结束开始。这样可以避免创建新结构。

编辑:恕我直言,HashMap/HashSet 由于冲突而为 O(log(log(n)),如果有完美的散列函数,则只有 O(1)。我原以为不要创建更快的对象但在我的机器上似乎只有 4 倍的速度。

总而言之,您可以看到使用 Set 更简单、更清晰且更易于维护。它仍然非常快,并且在 98% 的情况下都是最佳解决方案。

public static void main(String[] args) throws Exception {
    for (int len : new int[]{100 * 1000 * 1000, 10 * 1000 * 1000, 1000 * 1000, 100 * 1000, 10 * 1000, 1000}) {
        int[] nums = new int[len];
        for (int i = 0; i < len; i++)
            nums[i] = (int) (Math.random() * (Math.random() * 2001 - 1000));
        Arrays.sort(nums);

        long timeArray = 0;
        long timeSet = 0;
        int runs = len > 1000 * 1000 ? 10 : len >= 100 * 1000 ? 100 : 1000;
        for (int i = 0; i < runs; i++) {
            long time1 = System.nanoTime();
            int count = countDistinct(nums);
            long time2 = System.nanoTime();
            int count2 = countDistinctUsingSet(nums);
            long time3 = System.nanoTime();
            timeArray += time2 - time1;
            timeSet += time3 - time2;
            assert count == count2;
        }
        System.out.printf("For %,d numbers, using an array took %,d us on average, using a Set took %,d us on average, ratio=%.1f%n",
                len, timeArray / 1000 / runs, timeSet / 1000 / runs, 1.0 * timeSet / timeArray);
    }
}

private static int countDistinct(int[] nums) {
    int lastLeft = Math.abs(nums[0]);
    int lastRight = Math.abs(nums[nums.length - 1]);
    int count = 0;
    for (int a = 1, b = nums.length - 2; a <= b;) {
        int left = Math.abs(nums[a]);
        int right = Math.abs(nums[b]);
        if (left == lastLeft) {
            a++;
            lastLeft = left;
        } else if (right == lastRight) {
            b--;
            lastRight = right;
        } else if (lastLeft == lastRight) {
            a++;
            b--;
            lastLeft = left;
            lastRight = right;
            count++;
        } else if (lastLeft > lastRight) {
            count++;
            a++;
            lastLeft = left;
        } else {
            count++;
            b--;
            lastRight = right;
        }
    }
    count += (lastLeft == lastRight ? 1 : 2);
    return count;
}

private static int countDistinctUsingSet(int[] nums) {
    Set<Integer> s = new HashSet<Integer>();
    for (int n : nums)
        s.add(Math.abs(n));
    int count = s.size();
    return count;
}

打印

对于 100,000,000 个数字,使用数组平均花费 279,623 us,使用 Set 平均花费 1,270,029 us,ratio=4.5

对于 10,000,000 个数字,使用数组平均花费 28,525 us,使用 Set 平均花费 126,591 us,ratio=4.4

对于 1,000,000 个数字,使用数组平均花费 2,846 us,使用 Set 平均花费 12,131 us,ratio=4.3

对于 100,000 个数字,使用数组平均需要 297 us,使用 Set 平均需要 1,239 us,ratio=4.2

对于 10,000 个数字,使用数组平均需要 42 us,使用 Set 平均需要 156 us,ratio=3.7

对于 1000 个数字,使用数组平均需要 8 我们,使用集合平均需要 30 我们,比率=3.6


在@Kevin K 的观点上,即使整数也可能发生冲突,即使它的哈希值是唯一的,它可以映射到同一个桶,因为容量有限。

public static int hash(int h) {
    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

public static void main(String[] args) throws Exception {
    Map<Integer, Integer> map = new HashMap<Integer, Integer>(32, 2.0f);
    for (int i = 0; i < 10000 && map.size() < 32 * 2; i++) {
        if (hash(i) % 32 == 0)
            map.put(i, i);
    }
    System.out.println(map.keySet());
}

打印

[2032, 2002, 1972, 1942, 1913, 1883, 1853, 1823, 1763, 1729, 1703, 1669, 1642, 1608, 1582, 1548, 1524, 1494, 1456, 1426, 1370 1307、1255、1221、1187、1153、1134、1100、1066、1032、1016、986、956、926、881、851、821、791、747、713、687、653、05、510、576、56 508、478、440、410、373、343、305、275、239、205、171、137、102、68、34、0]

因为 HashMap 已经生成为 LinkedList,所以这些值的顺序是相反的。

【讨论】:

  • 但即使我创建了一个新结构,我仍然需要同样的时间来解决问题
  • 它可能看起来是相同的时间量,但是如果您对多达 10,000 个条目的大型数组进行测量,您会发现存在非常大的相对差异。但是,您是对的,简单的解决方案通常是最好的且足够快。
  • @stephen: HashSet 的插入和查找都是 O(1)。
  • @peter:我的意思是至少两次。
  • 天啊,我忘了!没有哈希码冲突,但当然地图只有有限数量的桶 :) 感谢您抽出时间来回答,对于造成的混乱,我们深表歉意!
【解决方案2】:

您应该注意数组是按升序排序的

让我们假设只有正数,或者问题与绝对不同。

如果实际元素与最后一个元素不同,您可以通过遍历列表来计算 Number,并将计数器加一。 (第一个元素 +1)

如果您理解这一点,您可以添加 absolute distinct 约束。例如,通过两个指针改进算法,一个从开头开始,一个从结尾开始。然后你还必须注意两个指针并行工作,以便两个指针都以 0 或绝对最低数字(正/负)结束 - 这会使整个事情变得复杂一点,但这是可能的。

【讨论】:

  • 我确实理解我的算法会浪费空间但需要同样多的时间来解决这一事实。网站代码并没有太多空间和运行时间
  • @yahh 好吧,我认为在采访中真正重要的是最好的方法。这意味着在空间和内存方面。具有两个指针的 Ralphs 方法在 O(n) 中运行并占用 O(1) 内存。这是你能做的最好的。所以这显然是正确的答案。我想只有完美的答案才能给出分数。
  • 顺便说一句:我从那些采访/测试中了解到,代码中的错误是没有问题的。如果您的代码无法编译,那就没有背后的算法/想法那么有趣了!在大多数面试中,你在一张纸上写代码,通常即使是最好的程序员也会犯语法错误等。
  • yahh:您的代码实际上更慢。 java.util.HashSet 只有在哈希函数完美且不发生冲突的情况下才具有恒定时间 add()。否则它是 O(bucket length),所以在最坏的情况下你有 O(n^2) 的性能。
  • @blaze:我不应该假设当对原语使用散列函数时它会完美地工作。
【解决方案3】:
int count(vector<int> &A) {

    int len = B.size();
    if (len <= 0)
        return 0;

    // make a copy and calc absolutes of all items
    vector<int> B = vector<int>(A);
    for (int i = 0; i < len; i++) {
        if (B[i] < 0) 
        B[i] = -B[i];
    }

    // and sort so we have a simple absolute count
    sort(B.begin(), B.end());

    int result = 1; //count first number always
    for (int j = 1; j < len; j++) {
        if (B[j] != B[j-1])
            result++;
    }
    return result;

}

【讨论】:

    【解决方案4】:

    这是一个简单的解决方案。

    public class test{
    
    public static int dis(Integer[] arr) {
        out.println(Arrays.asList(arr));
        if (arr.length == 0) {
            return 0;
        }
        int i = 0;
        int j = arr.length - 1;
        int c = 0;
        while (i <= j) {
            if ((j != arr.length - 1) && (Math.abs(arr[j]) == Math.abs(arr[j + 1]))) {
                out.println("skipping J==" + j);
                j--; continue;
            }
            if ((i != 0) && (Math.abs(arr[i]) == Math.abs(arr[i - 1]))) {
                out.println("skipping I==" + i);
                i++; continue;
            }
            if (Math.abs(arr[i]) < Math.abs(arr[j])) {
                j--;
                c++;
            }
            else if (Math.abs(arr[i]) > Math.abs(arr[j])) {
                i++; c++;
            }
            else {
                i++; j--; c++;
            }
    
            out.println("I=" + i + " J=" + j + " C=" + c);
        }
        return c;
    }
    
    
    
    
    public static void main(String[] arg){
    
    //Integer[] a = {34,2,3,4,3,-2,3};
    //out.println("distinct elements are" + dis(a));
    Integer[] aa={-5,-3,0,1,3};
    out.println("distinct elements count " + dis(aa));
    Integer[] ab={-5,-3,0,1,3, 4, 6, 7};
    out.println("distinct elements count " + dis(ab));
    Integer[] ac={-5};
    out.println("distinct elements count " + dis(ac));
    Integer[] acc={9};
    out.println("distinct elements count " + dis(acc));
    Integer[] ad={9,9,9};
    out.println("distinct elements count " + dis(ad));
    Integer[] ae={-5,-5};
    out.println("distinct elements count " + dis(ae));
    Integer[] aee={1,5,5,5,5};
    out.println("distinct elements count " + dis(aee));
    Integer[] af={-9, -6, -5, -5, -5, -5, -3, -3, 0, 0, 1, 5, 6, 7, 7, 8};
    out.println("distinct elements count " + dis(af));
    
    }
    

    }

    输出是

    [-5, -3, 0, 1, 3]
    distinct elements count 4
    [-5, -3, 0, 1, 3, 4, 6, 7]
    distinct elements count 7
    [-5]
    distinct elements count 1
    [9]
    distinct elements count 1
    [9, 9, 9]
    distinct elements count 1
    [-5, -5]
    distinct elements count 1
    [1, 5, 5, 5, 5]
    distinct elements count 2
    [-9, -6, -5, -5, -5, -5, -3, -3, 0, 0, 1, 5, 6, 7, 7, 8]
    distinct elements count 8
    

    【讨论】:

    • 但是第一组输入正确答案是5!
    【解决方案5】:

    这是我想出的,不确定它是否在 while 中包含一个 for 循环这一事实是否认为这是典型的新手错误。

        private int getDistict(int[] myaa) {
            int dupcount=0;
            int i = 0;
            int j = myaa.length - 1;
            while (i < j) {
        //      check neighbors 
                if(Math.abs(myaa[i]) == Math.abs(myaa[i+1])) {
                    dupcount++;
                    i++;
                    continue;
                }
    //      check the other side
                if(myaa[i] < 0) {
                    for(int k = j; Math.abs(myaa[i]) <= Math.abs(myaa[k]); k-- ) {
                        if(Math.abs(myaa[i])==Math.abs(myaa[k])){
                            dupcount++;
                        }
                    }               
                }
                i++;
            }
            return myaa.length - dupcount;
        }
    

    【讨论】:

      【解决方案6】:

      这是我的代码.....如果可以改进,请告诉我......

      import java.util.Arrays;
      import java.util.HashSet;
      
      /********
      Joel 
      Jun 19, 2013
       ********/
      
      public class CodilityTest {
      
          private int[] inputArray;
          public static int count=0;
      
          public void setInput(int [] givenIP){
              this.inputArray= new int[givenIP.length];
              for(int i=0; i<givenIP.length;i++)
              { inputArray[i] = givenIP[i];}
          }
      
          public int[] getInput(){
              return this.inputArray;
          }
      
          public CodilityTest(){
              count=0;
          }
      
          public static void main(String[] args) throws Exception {
              // TODO Auto-generated method stub
      
              CodilityTest o_tc = new CodilityTest();
      
              int [] x = {1,2,-3,4,-5,-11,-2,3,-4,5};
              int [] y = new int[0];
              o_tc.setInput(x);
              o_tc.getOutput(x);
              System.out.println(count);
      
              CodilityTest o_tc1 = new CodilityTest();
              o_tc1.getOutput(y);     
          }
      
          public void getOutput(int [] givenInput)
          {
              if(givenInput == null)
              {System.out.println("Please Enter some variables Sir."); return;}
      
              if(givenInput.length<1)
              {System.out.println("Please Enter some variables Sir."); return; }
      
              if(givenInput.length < 2)
              {count+=1; return;}
      
              HashSet<Integer> o_hs = new HashSet<Integer>();
              for(int numCount=0; numCount<givenInput.length;numCount++)
              {           
                  if(o_hs.add(Math.abs(givenInput[numCount])))
                  {count+=1;}
              }
      
          }
      
      }
      

      【讨论】:

        【解决方案7】:

        您的解决方案至少是最简单的方法之一(更具可读性,更易于维护)。它肯定不是最有效的(也不是最差的),如果不用于时间关键的代码应该是可以接受的。

        但是您应该提到这一点并建议有一个更有效的解决方案,例如从两端遍历列表(如已回答的那样)。也许您会在讨论这两种解决方案的优势时获得额外的积分。

        测试了您的解决方案(在旧(慢)笔记本电脑上):

        • 10000 个数字小于 2 毫秒
        • ~450 ms for 1000000

        【讨论】:

          【解决方案8】:

          这是我刚刚练习的一个python提案:

          def abs_distinct(A):
              if not A:
                  return -1
              #assume A is sorted
              n = len(A)
              left_cursor = 0
              right_cursor = n-1
              left_value = A[0]
              right_value = A[n-1]
              nb_abs_distinct = len(set([abs(left_value),abs(right_value)]))
          
              while left_value != right_value:
                  # case 1: decrease right_cursor down to the next different value
                  if abs(left_value) < abs(right_value):
                      while A[right_cursor] == right_value:
                          right_cursor -= 1
                      right_value = A[right_cursor]
                      if abs(right_value) != abs(left_value):
                          nb_abs_distinct += 1
                  # case 2: increase left_cursor to the next different value
                  elif abs(left_value) > abs(right_value):
                      while A[left_cursor] == left_value:
                          left_cursor += 1
                      left_value = A[left_cursor]
                      if abs(left_value) != abs(right_value): 
                          nb_abs_distinct += 1
          
                  else:
                      while abs(left_value) == abs(right_value):
                          left_cursor += 1
                          left_value = A[left_cursor]
                      nb_abs_distinct += 1
          
              return nb_abs_distinct
          

          【讨论】:

          • 您在 codility 的服务器上获得了 78%:▶example example test✔OK expand allCorrectness tests ▶one_element✔OK ▶two_elements✔OK ▶same_elements✔OK ▶simple✔OK ▶simple_no_zero✘RUNTIME ERROR 测试程序终止于退出代码 1 ▶simple_no_same✔OK ▶simple_no_negative✔OK ▶simple_no_positive✔OK ▶arith_overlow✔OK ▶medium_chaotic1✘RUNTIME ERROR 测试程序以退出代码 1 终止 ▶medium_chaotic2✔OK 展开所有性能测试 ▶long_sequence_no_negative✔OK ▶long_sequence_no_positive✔OK ▶long_sequence✘RUNTIME错误测试程序以退出代码 1 终止
          【解决方案9】:

          请在下面找到比彼得更快的实现。

          if (A == null || A.length == 0) {
            return 0;
          } else if (A.length == 1 || A[0] == A[A.length - 1]) {
            return 1;
          }
          
          int absDistinct = 0;
          int leftCurrent;
          int leftNext;
          int rightCurrent;
          int rightPrevious;
          
          for (int i = 0, j = A.length; i < j; ) {
          
            leftCurrent = A[i];
            rightCurrent = A[j];
            leftNext = A[i + 1];
            rightPrevious = A[j - 1];
          
            if (leftCurrent + rightCurrent == 0) {
              while (A[i] - A[i + 1] == 0) {
                i++;
              }
              while (A[j] - A[j - 1] == 0) {
                j--;
              }
              i++;
              j--;
              absDistinct++;
            } else {
              if (leftCurrent + rightCurrent < 0) {
                if (leftCurrent - leftNext != 0) {
                  absDistinct++;
                }
                i++;
              } else {
                if (rightCurrent - rightPrevious != 0) {
                  absDistinct++;
                }
                j--;
              }
            }
          }
          
          return absDistinct;
          

          数字的分布很重要。但是如果会有很多相同数字的序列,这个算法会表现得更好。这表明算法复杂性并不是唯一需要克服的障碍。当您拥有具有适当复杂性的算法时,这可能只是其中一种选择。算法的线性校正仍然是可能的。输入的特性有时也很重要。

          【讨论】:

            【解决方案10】:
            class Program
            {
                static int CountArray(int[] MyIntArray)
                {
                    int countNum = 0;
                    int[] TempIntArray = new int[MyIntArray.Length];
                    for (int i = 0; i < MyIntArray.Length; i++)
                    {
                        TempIntArray[i] = Math.Abs(MyIntArray[i]);
                    }
                    var queryResults = from n in TempIntArray 
                                       select n;
                    countNum = queryResults.Distinct().ToArray().Length;
                    return countNum;
                }
            
                static void Main(string[] args)
                {
                    Console.WriteLine("demoX6FVFB-KX8");
                    Random randomNumber = new Random();
                    int[] TheArray = new int[100];
                    for (int j = 0; j < TheArray.Length; j++)
                    {
                        TheArray[j] = randomNumber.Next(-50, 50);
                    }
                    int counta = Program.CountArray(TheArray);
                    Console.WriteLine(counta);
                }
            }
            

            【讨论】:

              【解决方案11】:

              这是我的版本。你怎么看?

              int count(vector<int> testVector){
              
                for(unsigned int i = 0; i < testVector.size(); i++){
                  // empty array, return 0
                  if(testVector.empty()) return 0;
              
                  // one number left, must be unique, return 1;
                  if(testVector.size() == 1) return 1;
              
                  // neighbour elements are the same, delete first element
                  if(testVector[0] == testVector[1]) {
                      testVector.erase(testVector.begin());
                      return count(testVector);
                  }
              
                  // absolute value of first and last element identical, delete first element
                  if(abs(testVector[0]) == abs(testVector[testVector.size() - 1])){
                      testVector.erase(testVector.begin());
                      return count(testVector);
                  }
              
                  // if absolute value of beginning is greater than absolute value of end, delete beginning, otherwise end
                  if(abs(testVector[0]) > abs(testVector[testVector.size() - 1])){
                      testVector.erase(testVector.begin());
                  } else {
                      testVector.erase(testVector.end() - 1);
                  }       
                  // increase counter and recurse
                  return 1 + count(testVector);
                }
              }
              

              【讨论】:

                【解决方案12】:

                这是一个递归算法,它将在一次传递中返回列表中的绝对唯一条目,即 O(n) 时间。它依赖于数组已排序且未使用 java.util.Set 的事实。

                考虑这个示例数组 {-5,-5,-3,0,1,3}

                • 由于数组已排序,因此数组两端的两个元素之一将具有绝对最大值:-5
                • 同样,由于数组已排序,如果该元素要匹配,它将是它的邻居,或者是多个匹配的邻居。
                • 因此,对于 -5,我们对其邻居进行一次检查:它们是相等的。 -5 是重复的,所以删除它,不要增加我们的运行总数和递归。

                {-5,-3,0,1,3} 现在我们选择 -5,它是唯一的,因此将运行总数增加到 1,然后将其删除。

                {-3,0,1,3} 如果两端绝对值相等,去掉一个就行,哪一个都无所谓,只要是一个就行。先说一下。我们不会增加运行总计,因为我们删除的值是重复的。

                {0,1,3} 现在我们选择 3,其唯一的运行总数变为 2。

                {0,1} 选择 1,其唯一的,运行总数 3。

                {0} 大小为 1,值唯一,递增累计并返回。 4 正确!

                package com.codility.tests;
                
                import java.util.ArrayList; 
                import java.util.Arrays;
                import java.util.List;
                
                public class AbsDistinct {
                
                /**
                 * Count the number of absolute distinct elements in an array.
                 * The array is sorted in ascending order.
                 */
                private static int countAbsDistinct(List<Integer> list, int count) {
                    int lastIndex = list.size() - 1;
                    if (lastIndex == -1) { // zero size list, terminate
                        return 0;
                    }
                    if (lastIndex == 0) { // one element list, terminate
                        return ++count;
                    }
                    if (Math.abs(list.get(0)) == Math.abs(list.get(lastIndex))) {
                        // doesn't matter which end is removed, but to remove _only_ 1
                        list.remove(0);
                    } else if (Math.abs(list.get(0)) > Math.abs(list.get(lastIndex))) {
                        // if different to its nighbour, its unique hence count it
                        if (list.get(0) != list.get(1)) {
                            count++;
                        }
                        // now that its been accounted for, remove it
                        list.remove(0);
                    } else {
                        // same logic but for the other end of the list
                        if (list.get(lastIndex) != list.get(lastIndex - 1)) {
                            count++;
                        }
                        list.remove(lastIndex);
                    }
                    return countAbsDistinct(list, count);
                }
                
                public static void main(String[] args) {
                    if (args.length == 0) { // just run the tests
                        List<Integer> testList = new ArrayList<Integer>(Arrays.asList(-9, -6, -5, -5, -5, -5, -3, -3, 0, 0, 1, 5, 6, 7, 7, 8));
                        List<Integer> empty = new ArrayList<Integer>();
                        List<Integer> singleElement = new ArrayList<Integer>(Arrays.asList(1));
                        List<Integer> sameElement = new ArrayList<Integer>(Arrays.asList(1, 1, 1, 1, 1, 1));
                        System.out.println("test array: " + countAbsDistinct(testList, 0));
                        System.out.println("empty array: " + countAbsDistinct(empty, 0));
                        System.out.println("single element array: " + countAbsDistinct(singleElement, 0));
                        System.out.println("same element array: " + countAbsDistinct(sameElement, 0));
                    } else {
                        List<String> argStringList = new ArrayList<String>(Arrays.asList(args));
                        List<Integer> argList = new ArrayList<Integer>();
                        for (String s : argStringList) {
                            argList.add(Integer.parseInt(s));
                        }
                        System.out.println("argument array: " + countAbsDistinct(argList, 0));
                    }
                }
                }
                

                【讨论】:

                  【解决方案13】:
                  import java.util.Arrays;
                  
                  public class DistinctNumbers {
                  
                      public static void main(String[] args) {
                  
                         int[][] tests = new int[][] {
                                                   {-5,-3, 0, 1, 3},    //4
                                                   {-5,-5,-5,-5,-5},   // 1
                                                   { 1, 2, 3, 4, 5},   // 5
                                                   { 1},               // 1
                                                   { 1, 2},            // 2
                                                   { 1, 1},            // 1
                                          };
                  
                         for (int[] test : tests) {
                             int count = findDistinctNumberCount( test );
                             System.out.println(count);
                         }
                  
                      }
                  
                      static int findDistinctNumberCount(int[] numbers) {
                  
                          // 1. make everything abs.
                          for (int i=0; i<numbers.length; i++) {
                            if (numbers[i] <0) {
                                numbers[i] = Math.abs(numbers[i]);
                            }
                          }
                  
                          // 2. sort them
                          Arrays.sort(numbers);
                  
                          // 3. find
                          int count = numbers.length;
                  
                          for (int i=0; i<numbers.length; i++) {
                  
                              // skip if not distinct (equal)
                              i = skipIfNeededAndGentNextIndex(i, numbers);
                  
                          }
                  
                          return count;
                  
                      }
                  
                      public static int skipIfNeededAndGentNextIndex(int currentIndex, int[] numbers) {
                  
                          int count = numbers.length;
                  
                          int nextIndex = currentIndex;
                  
                          if ( (nextIndex + 1) != numbers.length)  {
                  
                              nextIndex += 1;
                  
                              while(numbers[currentIndex] == numbers[nextIndex]) {
                  
                                  count -= 1;
                  
                                  if ( (nextIndex + 1) != numbers.length) {
                                      nextIndex += 1;
                                  } else {
                                      break;
                                  }
                  
                              }
                  
                          }
                  
                          return count;
                      }
                  
                  }
                  

                  【讨论】:

                    【解决方案14】:

                    .NET C#:

                    static int absoluteDistinctNumbers(int[] arr)
                    {
                        int same = 0;
                        int l = 0;
                        int r = arr.Length - 1;
                    
                        while (l < r)
                        {
                            if (Math.Abs(arr[l]) == Math.Abs(arr[r]))
                                ++same;
                    
                            if (Math.Abs(arr[l]) > Math.Abs(arr[r]))
                                ++l;
                            else
                                --r;
                        }
                    
                        return arr.Length - same; 
                    }
                    

                    这个解决方案有问题吗?它看起来比其他的要简单得多……我花了大约 10 分钟,所以我很确定我做错了什么,但我不知道是什么……我的测试:

                    var arr = new int[] { 4, 2, 1, 1, -1, -5 };
                    var result = absoluteDistinctNumbers(arr);
                    Debug.Assert(4 == result);
                    
                    arr = new int[] { 1, -1 };
                    result = absoluteDistinctNumbers(arr);
                    Debug.Assert(1 == result);
                    
                    arr = new int[] { };
                    result = absoluteDistinctNumbers(arr);
                    Debug.Assert(0 == result);
                    
                    arr = new int[] { 2 };
                    result = absoluteDistinctNumbers(arr);
                    Debug.Assert(1 == result);
                    
                    arr = new int[] { 3, 3, -3 };
                    result = absoluteDistinctNumbers(arr);
                    Debug.Assert(1 == result);
                    
                    arr = new int[] { 2, 0, 0, 0 };
                    result = absoluteDistinctNumbers(arr);
                    Debug.Assert(2 == result);
                    

                    【讨论】:

                      【解决方案15】:

                      在 Java 的情况下,Arrays.sort() 方法的平均性能最好。时间复杂度的期望被称为 O(N*log2N)。那为什么不使用呢?

                      这里有一个解决方案。

                      1. 遍历数组,将所有负数转换为绝对数。 例如,从 {-5, -3, 0, 1, 3} 到 {5, 3, 0, 1, 3}。
                      2. 用户 Arrays.sort() 重新排列数组。 例如,从 {5, 3, 0, 1, 3} 到 {0, 1, 3, 3, 5}。
                      3. 再次遍历数组,如果邻居的值不同,则向上计数。

                      这里是Java的源代码。

                      int countDistinct(int[] A) {
                      
                          int size = A.length;
                          if(size == 0) {
                              return 0;
                          }
                          for(int i = 0; i < size; i++) {
                              if(A[i] < 0) {
                                  A[i] = (-1) * A[i];
                              }
                          }
                      
                          Arrays.sort(A);
                      
                          int count = 1;
                          for(int i = 0; i < size - 1; i++) {
                              if(A[i] != A[i + 1]) {
                                  count++;
                              } 
                          }
                      
                          return count;
                      }
                      

                      【讨论】:

                        【解决方案16】:
                        def solution1(A):
                            indneg = -1
                            lena = len(A)
                            lneg = list()
                            lpos = list()
                        
                            for i in range(lena-1):
                                if A[i] != A[i+1]:
                                    if A[i] < 0:
                                        lneg.append(A[i])
                                    else:
                                        lpos.append(A[i])
                            print(lneg)
                            print(lpos)
                        
                            deltalen = 0
                        
                            for i in lneg:
                                if -i in lpos: deltalen +=1
                        
                            return(len(lneg)+len(lpos)-deltalen)
                        

                        【讨论】:

                          【解决方案17】:

                          这是我对 codility 的 ruby​​ 版本 100/100 测试,基于 codility 测试用例,具有相同绝对值 [3,-3] 或 [3,3] 的数组应返回 1, 这是示例列表link

                          def absolute(a)
                              b = Hash.new(0)
                              a.each do |x|
                                  x = x.abs
                                  b[x] += 1
                              end 
                              return b.size
                          end 
                          

                          【讨论】:

                            【解决方案18】:

                            这里是python实现: 可能与公认的解决方案差别不大,但它基于两个指针的想法。

                            def distinct(items):
                                l=0
                                r=len(items)-1
                                count=len( set( [abs( items[l] ),abs( items[r] )] ) )
                                a=1
                                b=r-1
                                while(a<b):
                                    if items[a]==items[l]:
                                        a+=1
                                    elif items[b]==items[r]:
                                        b-=1
                                    elif abs(items[a])==abs(items[b]):
                                        count+=1
                                        l=a
                                        r=b
                                        a+=1
                                        b-=1
                                    else:
                                        count+=2
                                        l=a
                                        r=b
                                        a+=1
                                        b-=1
                                if(abs(items[a])!=abs(items[l]) and abs(items[a])!=abs(items[r]) and abs(items[b])!=abs(items[l]) and abs(items[b])!=abs(items[r])):
                                    count+=1
                                return count
                            

                            【讨论】:

                              【解决方案19】:

                              以下是这两种实现的 C++ 代码,其中的代码生成随机排序的整数向量:

                              #include <vector>
                              #include <set>
                              #include <iostream>
                              #include <random>
                              #include <cstdlib>
                              using namespace std;
                              int main(int argc, char** argv) {
                              
                                  // generate a vector with random negative and positive integers, then sort it
                                  // vector<int> vQ2{ -5, -4, -4, -2, 0, 3, 4, 5, 5, 7, 12, 14};
                                  vector<int> vQ2;
                                  std::default_random_engine e;
                                  std::uniform_int_distribution<> d(-10, 10);
                                  std::function<int()> rnd = std::bind(d, e);
                                  for(int n=0; n<10; ++n)
                                      vQ2.push_back(rnd());
                                  sort(vQ2.begin(),vQ2.end());
                              
                                  // set (hashfunction) solution (hash)
                                  set<int> sQ2;
                                  for_each(vQ2.cbegin(),vQ2.cend(),[&sQ2](const int input) -> void { sQ2.insert( std::abs(input) ); } );
                                  cout << sQ2.size() << endl;
                              
                                  // pointers-meeting-in-the-middle solution        
                                  int absUniqueCount = 0;
                                  vector<int>::iterator it1 = vQ2.begin();
                                  vector<int>::iterator it2 = prev(vQ2.end());
                                  int valueIt1Prev = *it1;
                                  int valueIt2Prev = *it2;
                                  while(valueIt1Prev <= valueIt2Prev)
                                  {
                                      ++absUniqueCount;
                                      while(valueIt1Prev == *it1 && abs(valueIt1Prev) >= abs(valueIt2Prev))
                                      {   advance(it1,1); } // using advance in case of non contiguous memory container (e.g. list)
                                      while(valueIt2Prev == *it2 && abs(valueIt2Prev) >= abs(valueIt1Prev))
                                      {   advance(it2,-1); } 
                                      valueIt1Prev = *it1;
                                      valueIt2Prev = *it2;
                                  }
                                  copy(vQ2.cbegin(),vQ2.cend(),ostream_iterator<int>(cout,",")); cout << endl;
                                  cout << absUniqueCount << endl;
                              
                                  return 0;
                              }
                              

                              这给出了:

                              6
                              -9,-8,-8,-8,-5,0,4,4,6,6,
                              6
                              

                              【讨论】:

                                【解决方案20】:

                                JavaScript:100/100

                                function solution(A) {
                                    var count = 1,
                                        len = A.length,
                                        S = A.map(function(x){ return Math.abs(x) }).sort();
                                
                                    for(var i=1;i<len;i++) {
                                        if(S[i] != S[i-1]) count++;        
                                    }
                                
                                    return count;
                                }
                                

                                【讨论】:

                                  【解决方案21】:

                                  这里时间复杂度 O(n) 和 O(1) 内存的最短版本:

                                  int countAbsDistinct(int[] A) {
                                      int start = 0;
                                      int end = A.length - 1;
                                      if (end == -1) { // zero size list
                                          return 0;
                                      }
                                  
                                      int c = 1; // at least one abs distinct for non-empty array
                                      while(A[start]<A[end]){
                                          int l = Math.abs(A[start]);
                                          int r = Math.abs(A[end]);
                                      c++;
                                  
                                          if (r>=l){
                                              while(A[end]==list.get(--end)); // move left until different value
                                          }
                                          if (l>=r){
                                              while(A[start]==list.get(++start)); // move right until different value
                                          }
                                      }
                                      if(start>end){ // if last movements made start index bigger than end
                                          c--;
                                      }
                                      return c;
                                  }
                                  

                                  【讨论】:

                                    【解决方案22】:

                                    100/100 Java O(N)

                                    public class Distinct {
                                    
                                        public static int solution(int[] A) {
                                    
                                            Set<Integer> set = new HashSet<>();
                                            for (int i : A) {
                                                set.add(i);
                                            }
                                            return set.size();
                                        }
                                    }
                                    

                                    【讨论】:

                                      【解决方案23】:

                                      Java 100/100 https://codility.com/demo/results/demoMTWUSD-S9M/

                                      一个不使用集合和不使用排序的 O(N) 解决方案,灵感来自于 Programming Pearls 书,第 1 章:

                                      public int solutionWithoutSetCountUntilInputLength(int[] A) {
                                             int length = A.length;
                                             int inputLimit = 1000000;
                                             int[] positives = new int[inputLimit];
                                             int[] negatives = new int[inputLimit]; // should be length - 1 not counting zero
                                      
                                             for (int element : A) {
                                                 if ( element >=0 ) {
                                                     ++positives[element];
                                                 } else {
                                                     int abs = element * -1;
                                                     ++negatives[abs];
                                                 }
                                             }
                                      
                                             int countDistincts = 0;
                                      
                                             for (int i: A) {
                                                 if (i >= 0 ) {
                                                     if ( positives[i] >= 1 ) {
                                                         ++countDistincts;   
                                                         positives[i] = 0;
                                                     }
                                                 } else {
                                                     if ( negatives[i * -1] >= 1 ) {
                                                         ++countDistincts;   
                                                         negatives[i * -1] = 0;
                                                     }
                                                 }
                                             }        
                                             return countDistincts ;
                                         }
                                      

                                      我正在考虑改进最后一个答案,是我对 Java 的位操作进行了一些研究,我发现下一个解决方案对我来说性能更好,它使用更少的空间和更少的 CPU 周期:

                                      导入 java.util.Set;

                                      public class Distinct {
                                      public int solution(int[] A) {
                                              // first part for negatives, second part for positives and adding 1
                                              // to count the zero as part of the positives section
                                              int offset = 1_000_000;
                                              BitSet bitSet = new BitSet( (offset * 2) + 1 );
                                      
                                              for (int element : A ) {
                                                  int index = element >= 0 ? offset + element : (element * -1);
                                                  bitSet.set(index);
                                              }
                                      
                                              return bitSet.cardinality();
                                          }
                                      }
                                      

                                      这是代码链接 100/100: https://codility.com/demo/results/demoN57YUC-G9Z/

                                      您可以在此处查看我的其他尝试: Distinct

                                      【讨论】:

                                        【解决方案24】:

                                        在 Scala 中很容易做到:

                                        object Solution {
                                            def solution(A: Array[Int]): Int = {
                                        
                                                return(A.map(v => math.abs(v)).distinct.length)
                                            }
                                        }
                                        

                                        这里是test的链接。

                                        【讨论】:

                                          【解决方案25】:
                                          //java code scored 100/100 
                                          class Solution{
                                          public int solution(int[] A){
                                          int distinct = 0;
                                          Arrays.sort(A);
                                              if (A.length == 0){
                                                  distinct= 0;
                                                 }
                                              else{
                                                  distinct= 1;
                                              }
                                          
                                           for(int i=1; i<A.length;i++){
                                              if(A[i] == A[i-1]){continue;}
                                              else {
                                              distinct +=1;
                                              }
                                          }
                                          return distinct;
                                          }
                                          public static void main(String[] args){
                                          int A [] = {2,1,1,2,3,1};
                                          System.out.println(solution(A));
                                          
                                          }
                                          }
                                          

                                          【讨论】:

                                          • 欢迎来到 SO 并感谢您发布答案。请考虑扩展它并解释您的代码。
                                          【解决方案26】:

                                          这是我的 c# 解决方案,在性能和正确性方面获得了 100/100。它为问题提供了一个简单的解决方案。

                                          using System;
                                          
                                          class Solution {
                                              public int solution(int[] A) {
                                                  int arrLength = A.Length;
                                          
                                                  Array.Sort(A);
                                          
                                                  int[] arrNegative = new int[1000002];
                                          
                                                  int[] arrPositive = new int[1000002];
                                          
                                                  int i,counter = 0,holder = 0;
                                          
                                                  bool zero = false;
                                          
                                                  for (i=0; i < arrLength; i++){     
                                                      if(A[i]<0){
                                                          holder = Math.Abs(A[i]);
                                                          if(arrNegative[holder]==0) arrNegative[holder] = holder;   
                                                      }
                                                      else{
                                                          if(A[i]==0) zero = true;
                                          
                                                          if(arrPositive[A[i]]==0) arrPositive[A[i]] = A[i];
                                                      }
                                                  }
                                          
                                                  foreach(int c in arrNegative){
                                                      if(c!=0) counter++;
                                                  }
                                          
                                                  foreach(int c in arrPositive){
                                                      if(c!=0) counter++;
                                                  }
                                          
                                                  if(zero) counter++;
                                          
                                                  return counter;
                                              }
                                          }
                                          

                                          【讨论】:

                                            【解决方案27】:

                                            更 Catterpalistic C# 解决方案,得分为 100/100。

                                            从以下链接获得提示。 https://codesays.com/2014/solution-to-abs-distinct-by-codility/

                                             using System;
                                            
                                            class Solution {
                                            public int solution(int[] A) {
                                                // write your code in C# 6.0 with .NET 4.5 (Mono)
                                                var head = 0; 
                                                var tail = A.Length -1;
                                                var absCount = 1;
                                                var current = A[0] > 0 ? A[0] : -A[0];
                                                while(head <= tail)
                                                {
                                                    var former = A[head] > 0 ? A[head] : -A[head];
                                                    if(former == current)
                                                    {
                                                        head ++;
                                                        continue;
                                                    }
                                            
                                                    var latter = A[tail] > 0 ? A[tail] : -A[tail];
                                                    if(latter == current)
                                                    {
                                                        tail--;
                                                        continue;
                                                    }
                                            
                                                    if(former >= latter)
                                                    {
                                                        current = former;
                                                        head ++;
                                                    }
                                                    else 
                                                    {
                                                        current = latter;
                                                        tail--;
                                            
                                                    }
                                            
                                                    absCount++;
                                                }
                                            
                                                return absCount;
                                            }
                                            

                                            }

                                            【讨论】:

                                              【解决方案28】:

                                              Java 8 非常简单明了。

                                              return (int) Arrays.stream(A).map(Math::abs)
                                                          .distinct().count();
                                              

                                              【讨论】:

                                                【解决方案29】:

                                                基于二分搜索的解决方案

                                                import java.util.Arrays;
                                                
                                                public class AbsoluteDistinct {
                                                
                                                    private int absoluteDistinct(int[] a) {
                                                        if (a.length == 0 || a.length == 1) return a.length;
                                                
                                                        Arrays.sort(a);
                                                
                                                        int dist = 1;
                                                        int N = a.length;
                                                        for (int i = 0; i < N; i++) {
                                                            if (i + 1 == N) break;
                                                            int temp = Math.abs(a[i]);
                                                            if (temp == Math.abs(a[i+1])) continue;
                                                            if (Arrays.binarySearch(a, (i + 1), N, temp) < 0) dist++;
                                                        }
                                                        
                                                        return dist;
                                                    }
                                                
                                                
                                                    public static void main(String[] args) {
                                                        //generate array of 1 Million random values
                                                        int LIMIT = 1000000;
                                                        int[] a = new int[LIMIT];
                                                        for (int i = 0; i < LIMIT; i++) {
                                                            int r = (int) (Math.random() * (LIMIT + LIMIT + 1)) - LIMIT;
                                                            a[i] = r;
                                                        }
                                                        //print absolute distinct numbers 
                                                        System.out.println(new AbsoluteDistinct().absoluteDistinct(a));
                                                    }
                                                }
                                                

                                                【讨论】:

                                                  【解决方案30】:

                                                  由于问题中还有 Python 标记,所以下面是我在 Python 中的简单解决方案,它可能对未来的用户有用,并且在 Codility 上获得 100% 的分数、正确性和性能:

                                                  def solution(N):
                                                  
                                                    list_of_absolute_values = list(map(lambda x:abs(x), N))
                                                  
                                                    return len(set(list_of_absolute_values))
                                                  

                                                  在函数的第一行,map() 将所有值转换为它们的绝对值。然后,我们通过删除重复项的set() 函数返回不同绝对值的数量。

                                                  【讨论】:

                                                    猜你喜欢
                                                    • 2015-02-19
                                                    • 1970-01-01
                                                    • 2019-02-28
                                                    • 2022-01-23
                                                    • 1970-01-01
                                                    • 1970-01-01
                                                    • 1970-01-01
                                                    • 2016-07-12
                                                    • 2014-09-29
                                                    相关资源
                                                    最近更新 更多