codility абсолютное отличное количество от массива - PullRequest
11 голосов
/ 20 апреля 2011

поэтому я вчера прошел тест на собеседование и был проинформирован сегодня о том, что потерпел неудачу, к сожалению, ни администрация, ни работодатель не дали никакой другой информации о том, где я облажался, так что я был бы признателен за помощь в том, чтобы узнать, где я ошибся,я знаю, что codility уделяет большое внимание тому, как быстро работает программа и как она ведет себя в больших количествах.теперь я не копировал и вставлял вопросы, так что это приблизительно то, что я помню

  1. подсчитывает количество элементов в массиве, которые абсолютно различны, что это означает, если массив имел -3 и 3в нем эти числа не различны, потому что | -3 | = | 3 |.я думаю, что пример прояснит это лучше

a = {- 5, -3,0,1, -3} результат будет 4, потому что в этом массиве есть 4 абсолютно разных элемента.

В вопросе также указывалось, что a.length будет <= 10000, и, что наиболее важно, указывалось, что предполагается, что массив <strong>отсортирован в порядке возрастания , но я действительно не понимал, зачем нам нужноэто будет отсортировано

ЕСЛИ ВЫ ДУМАЕТЕ, ЧТО-ТО ЧТО-ТО ЗАПРОСИЛ, И Я ПОПРОБУЮ УДАЛИТЬ ВОПРОС ДАЛЬШЕ.

здесьмой код

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

    }

}

Ответы [ 31 ]

8 голосов
/ 20 апреля 2011

Если массив отсортирован, вы можете найти дубликаты, посмотрев по соседству.Для сравнения абсолютных значений нужно начинать как в начале, так и в конце.Это позволяет избежать создания новой структуры.

РЕДАКТИРОВАТЬ: IMHO HashMap / HashSet - это O (log (log (n)) из-за коллизий, это всего лишь O (1), если есть идеальная хеш-функция. Я хотел быЯ думал, что не создаю объект, который будет намного быстрее, но на моей машине он будет работать только в 4 раза быстрее.

Таким образом, вы можете видеть, что использование набора проще, понятнее и проще в обслуживании.быстрая и была бы лучшим решением в 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 нас, а использование набора - в среднем 1 270 029 нас., коэффициент = 4,5

Для 10 000 000 чисел, использование массива заняло в среднем 28 525 долларов США, использование набора заняло в среднем 126 591 нас, отношение = 4,4

Для 1 000 000 чисел использование массива заняло 2 846для нас в среднем, использование набора заняло в среднем 12 131 нас, отношение = 4,3

Для 100 000 чисел, использование массива заняло в среднем 297 нас, для использования набора в среднем нас было 1239, отношение = 4,2

для 10000 nUmbers, использование массива заняло в среднем 42 нас, использование набора заняло в среднем 156 нас, отношение = 3,7

Для 1000 чисел, использование массива заняло в среднем 8 нас, использование набора заняло в среднем 30 нас., ratio = 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, 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.

7 голосов
/ 20 апреля 2011

Следует обратить внимание на тот факт, что массив отсортирован в порядке возрастания .

Предположим, что есть только положительные числа, или вопрос был не о абсолютный отличный.

Вы можете посчитать число, выполнив итерацию по списку, и увеличить счетчик на единицу, если фактический элемент отличается от последнего.(и +1 для первого элемента)

Если вы понимаете это, вы можете добавить абсолютное отдельное ограничение.Например, улучшив алгоритм с помощью двух указателей: один начинается с начала, другой - с конца.Затем вы также должны позаботиться о том, чтобы оба указателя работали параллельно, чтобы оба указателя заканчивались на 0 или наименьшем абсолютном числе (положительном / отрицательном) - это немного усложнит весь процесс, но это возможно.*

1 голос
/ 13 августа 2012

это то, что я придумал, не уверен, что тот факт, что он содержит цикл for внутри while, считает это типичной ошибкой нуби.

    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;
    }
1 голос
/ 20 мая 2012
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;

}
1 голос
/ 20 июня 2013

Вот что я кодировал ..... Дайте мне знать, если это можно улучшить ....

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

    }

}
1 голос
/ 18 января 2012

Вот предложение 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
1 голос
/ 03 января 2012

Вот простое решение для этого.

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 out

[-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
0 голосов
/ 23 июня 2013
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)
0 голосов
/ 27 апреля 2013

В случае 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;
}
0 голосов
/ 20 апреля 2011

Ну, если быть абсолютно честным, вам нужно сделать лучше, чем это.

Судя по вопросу, я предполагаю, что в списке нет дубликатов.Опять же, очевидно, хитрость - это предварительно отсортированный список.Это означает, что, хотя +5 может быть в правом конце строки, -5 будет в левом конце строки, поскольку отрицательные числа сортируются в обратном направлении к их абсолютной величине.

Начало с обоих концов,работать внутрь.Если два числа -1 друг от друга, то это не является отличным.В противном случае они различаются и перемещают конец, который является абсолютно большим.

Идите до тех пор, пока не достигнете нуля или не столкнетесь со следующим списком - в этом случае все оставшееся в следующем списке воспринимайте какну.

Этот алгоритм не нуждается ни в хешах, ни в словарях, ни в структурах данных, а выполняется за O (n) раз, просматривая весь список ровно один раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...