codility绝对不同于数组的计数

时间:2011-04-20 12:32:20

标签: c# java python c++ algorithm

所以我昨天接受了抄袭面试,并且今天被告知我失败了,不幸的是我没有得到任何其他信息,无论是鳕鱼也不是雇主,我在哪里搞砸了所以我会感谢一些帮助,知道我哪里出错了。我知道codility非常重视程序运行的速度以及它对大数字的行为方式。现在我没有复制粘贴问题所以这就是我记得的大概

  1. 计算数组a中绝对不同的元素数,这意味着如果数组中有-3和3,则这些数字不明显,因为| -3 | = | 3 |。我认为一个例子可以更好地清除它
  2. A = { - 5,-3,0,1,-3} 结果将是4,因为此数组中有4个绝对不同的元素。

    这个问题还说a.length会是< = 10000,最重要的是它声明假设数组按升序排序但我真的不明白为什么我们需要它待分类

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

    这是我的代码

    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));
    
        }
    
    }
    

34 个答案:

答案 0 :(得分:8)

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

编辑:恕我直言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我们,使用Set平均花费1,270,029我们,比率= 4.5

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

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

对于100,000个数字,使用数组平均花费297 us,使用Set平均花费1,239 us,比率= 4.2

对于10,000个数字,使用数组平均花费42 us,使用Set平均花费156 us,比率= 3.7

对于1,000个数字,使用数组平均花费8 us,使用Set平均花费30 us,比率= 3.6


在@Kevin K的观点上,即使Integer的哈希值是唯一的,它甚至可以发生冲突,它可以映射到容量受限的同一个桶。

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,1405,1375,1337, 1307,1255,1221,1187,1153,1134,1100,1066,1032,1016,986,956,926,881,851,821,791,747,713,687,653,610,576,550,516, 508,478,440,410,373,343,305,275,239,205,171,137,102,68,34,0]

值的顺序相反,因为HashMap已生成LinkedList。

答案 1 :(得分:7)

您应该注意数组按升序排序这一事实。

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

如果实际元素与上一个元素不同,您可以通过迭代列表来计算数字,并将计数器递增1。 (和第一个元素+1)

如果您了解这一点,则可以添加绝对不同约束。例如,通过两个指针改进算法,一个从开始开始,一个从结束开始。然后你还要注意两个指针的工作方式是并行的,这样两个指针都会以0或absoulte最低数字(正/负)结束 - 这会使整个东西复杂化一些,但这是可能的。

答案 2 :(得分:1)

下面是我编码的内容.....让我知道它是否可以改进....

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;}
        }

    }

}

答案 3 :(得分:1)

这就是我提出的,不确定它是否包含一个for循环的事实,并认为它是典型的noobie错误。

    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;
    }

答案 4 :(得分:1)

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;

}

答案 5 :(得分:1)

这是我刚刚练习的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

答案 6 :(得分:1)

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

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));

}

}

out put是

[-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

答案 7 :(得分:0)

基于二进制搜索的快速解决方案

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));
    }
}

答案 8 :(得分:0)

public static int 解决方案(int[] A) {

      Map<Integer, Long> map= Arrays.stream(A).boxed().collect(Collectors.groupingBy(Function.identity(),Collectors.counting()));
      int size=map.entrySet().size();
      return size;
    }

答案 9 :(得分:0)

由于问题中还有 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() 函数返回不同绝对值的数量。

答案 10 :(得分:0)

使用Java 8非常简单明了。

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

答案 11 :(得分:0)

更多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;
}

}

答案 12 :(得分:0)

这是我的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;
    }
}

答案 13 :(得分:0)

//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));

}
}

答案 14 :(得分:0)

Scala很容易做到:

object Solution {
    def solution(A: Array[Int]): Int = {

        return(A.map(v => math.abs(v)).distinct.length)
    }
}

此处链接到PHOAS to FOAS

答案 15 :(得分:0)

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

O(N)解决方案,不使用套装,不使用Sort,灵感来自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的Bit操作进行了一些研究,我发现下一个解决方案对我而言表现更好,它占用的空间更少,CPU周期更少:

import 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

答案 16 :(得分:0)

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();
    }
}

答案 17 :(得分:0)

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;
}

答案 18 :(得分:0)

以下是两个实现的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

答案 19 :(得分:0)

这是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

答案 20 :(得分:0)

这是我的ruby版本100/100关于编码的测试,根据编码测试案例,具有相同绝对值[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 

答案 21 :(得分:0)

这是一个递归算法,它将在一次传递中返回列表中的绝对唯一条目,即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));
    }
}
}

答案 22 :(得分:0)

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)

答案 23 :(得分:0)

对于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. 再次浏览数组,如果邻居没有相同的值,请计数。
  4. 以下是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;
    }
    

答案 24 :(得分:0)

这里有时间复杂度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;
}

答案 25 :(得分:0)

.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);

答案 26 :(得分:0)

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;
    }

}

答案 27 :(得分:0)

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

但你应该提到这一点,并建议有一个更有效的解决方案,如从两端遍历列表(已经回答)。也许你会有一个额外的观点来讨论两种解决方案的优点。

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

  • 10000个数字
  • 小于2毫秒
  • ~100毫秒,1000000

答案 28 :(得分:0)

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);
    }
}

答案 29 :(得分:0)

这是我的版本。你觉得怎么样?

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);
  }
}

答案 30 :(得分:0)

请查看下面的实施,这比Peter的快得多。

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;

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

答案 31 :(得分:-1)

int[] arr= new int[]{-5,-5,-6,-6,-6};
Set<Integer> newSet = new HashSet<Integer>();
for(int i=0;i<arr.length;i++)
  newSet.add(Math.abs(arr[i]));    

System.out.println(newSet.size());

答案 32 :(得分:-1)

嗯,说实话,你需要比这更好。

从问题来看,我认为该列表不包含重复项。再次,显然诀窍是预先排序的列表。这意味着虽然+5可能位于该行的右端,但-5将位于该行的左端,因为负数与其绝对幅度相反排序。

从两端开始,向内工作。如果两个数字彼此为-1,则它不是明显的。否则,它们是截然不同的,并且移动绝对更大的结束。

直到你达到零,或者你进入下一个列表 - 在这种情况下,将下一个列表中的所有内容都视为不同。

这个算法不需要哈希,没有字典,没有数据结构,并且在O(n)时间内运行,只需要整个列表一次。

答案 33 :(得分:-1)

解决方案是使用数组排序的事实。你可以做的是分别有两个指针指向数组的开头和结尾。然后根据abs值,减少/增加结束指针/开始指针。与此同时,你必须按顺序跟踪重复的元素,如{3,3,3,4}(3应该计算一次)。

总之,它不会太复杂,我认为在C中有20-25个位置。