Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / Задачка на собеседовании. Коллекции. / 25 сообщений из 42, страница 1 из 2
22.07.2014, 17:22
    #38703182
whizzzkey
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Приветствую, получил вот такую задачку на собеседовании на Java-junior'a, меня немного ввела в ступор тем что просто перебрать не можем, тогда каким образом искать дубликаты? Если не трудно объясните решение данной задачи. Благодарю.

Дан класс com.noname.User, модифицировать его не можем. Нужно написать утилитный метод
public static List<User> findDuplicates(Collection<User> collA, Collection<User> collB);
который возвращает дубликаты: юзеров, которые есть в обеих коллекциях. Одинаковыми считаем юзеров, у которых совпадают все 3 поля: username, email, passwordHash.
По производительности: метод findDuplicates должен работать не больше нескольких секунд, если на вход получает 2 коллекции по 100 тысяч элементов в каждой. То есть, простой перебор в цикле не подойдёт.
Пользоваться можно только стандартными классами Java SE


public final class User {

private String username;

private String email;

private byte[] passwordHash;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public byte[] getPasswordHash() {
return passwordHash;
}

public void setPasswordHash(byte[] passwordHash) {
this.passwordHash = passwordHash;
}
}
...
Рейтинг: 0 / 0
22.07.2014, 18:01
    #38703218
wst
wst
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Первое что пришло в голову - перегнать обе коллекции в списки, отсортировать со своим компаратором и проделать нечто вроде сортировки слиянием, но отбрасывая пользователей, которых нет в обоих списках.
Второе - преобразовывать юзеров из 1 коллекции в строки (склеить строковые представления всех полей) и запихивать пары строка-юзер в любую Map<String,User>, потом юзеров из 2 коллекции тоже перегонять в строку, смотреть есть ли такой ключ в мапе и если есть, то отдавать в список повторов.
Set-ы не предлагаю, ибо что деревянный что хешевый сделаны через отображения, так что отличий от варианта 2 не будет.
...
Рейтинг: 0 / 0
22.07.2014, 18:06
    #38703224
0FD
0FD
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
whizzzkey,


collA.retainsAll(new HashSet(collB));

а теперь взять исходник retainsAll и if (!c.contains(new _User(it.next())))
и у класса _User написать equal куда передается User
...
Рейтинг: 0 / 0
22.07.2014, 19:54
    #38703295
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Замечания к постановке.

1) Нам уже даны коллекции? Или их нужно наполнять. Во втором случае без перебора всех элементов нам не обойтись. Наполнение коллекции это O(n) сложная задача.

2) Если имплементация коллекции удачно подходит под работу с множествами (объединение вычитание) то можно из первого множества вычесть второе а потом перебрать в первом все кого нет во втором.

removeAll(Collection<?> c)

3) Но здесь подвох. Мы совершенно не знаем сколько будет дубликатов. 1 или сто тыщ и производительность операции вывода результата может быть также O(n) что сводит на нет все оптимизации.

Вообще здесь нужно препарировать моск товарищу который это адское задание придумал.
...
Рейтинг: 0 / 0
22.07.2014, 20:37
    #38703306
wst
wst
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Ограничение времени - несколько секунд на 100к юзеров, достаточно почти для всего, что лучше O(n^2).
...
Рейтинг: 0 / 0
22.07.2014, 20:48
    #38703309
Alexander A. Sak
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Может, еще надо уточнить на каком железе это должно работать?

Написал в лоб:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
   
   public static List<User> findDuplicates(Collection<User> collA, Collection<User> collB) {
      List<User> result = new ArrayList<User>();

      TreeSet<User> set = new TreeSet<User>(USER_COMPARATOR);
      set.addAll(collA);

      for (User user : collB) {
         if (set.contains(user)) result.add(user);
      }
      return result;
   }



При 100000 элементов в каждой коллекции затрачивается около 0.3с. Причем сначала ошибся, и вместо set.contains написал collA.contains . Результат был около 4с, что тоже отвечает условиям.
collA и collB -- ArrayList
...
Рейтинг: 0 / 0
22.07.2014, 21:23
    #38703329
Alexander A. Sak
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Навеяло опечаткой с collA.contains . Похоже, джавадоки-то врут. Про метод TreeSet.contains сказано:

джавадокreturns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)).
Однако для TreeSet c компаратором условие другое: comparator.compareTo(o, e)==0 .

И чтобы два раза не вставать.
Совсем тупой вложенный цикл по двум коллекциям занял около 220с.
...
Рейтинг: 0 / 0
23.07.2014, 10:33
    #38703612
ivanra
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Автор просил объяснить, между тем видим либо только решения, либо даже критику постановки задачи (для джуниора это недопустимо).
Между тем, все достаточно просто.
1) Решение в лоб - вложенный перебор коллеций, сложность O(n 2 )
Допустим, сравнение двух объектов в среднем займет 100 тактов, получаем:
100*100000*100000 = 10 12 тактов, при частоте 3*10 9 получаем порядка 300 секунд, явно не укладываемся в условия. Возможны различные оптимизации, но существенно от O(n 2 ) они не спасут
2) используем знания джуниора о коллекциях.
Джуниор должен знать, что для поиска дубликатов хорошо подходят множества, и наиболее эффективный поиск реализован в HashSet (O(1)), что позволит найти дубликаты за время O(n). Можно также использовать TreeSet с временем поиска O(ln(n)), что даст решение со сложностью O(n*ln(n)), но давайте сосредоточимся на первом варианте.
Для него нам не хватает методов, которые не были реализованы в изначальном классе: equals() и hashCode(). Решение - унаследовать изначальный класс, либо "обернуть", и там реализовать недостающие методы. Так как изначальный класс объявлен final, остается только возможность обертки:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
public class _User {
  public final User user;
  public _User(User user) {
    this.user=user;
  }
  @Override
  public boolean equals(Object object) {
    ...сравниваем внутренних user-ов
  }
  @Override
  public int hashCode() {
    ... вычисляем хеш из user-а
  }
  // для оптимизации тут можно добавить приватное поле hash, и выислять его только 1 раз, например, в конструкторе
}



Далее заполняем 2 множества объектами _User, находим дубликаты, используя операци над множествами, извлекаем из них исходные экземпляры User.

Прикинем расходы.
Память:
Допустим, объект класса _User (указатель на User, поле hash), а также расходы на его хранение в таблице составять порядка 100 байт. Таким образом, для хранения 2 вспомогательных множеств понадобится дополнительная память порядка 2*100*100000 ~ 20 мб
Время:
Допустим, итерация по исходной коллекции, создание объекта и вычисление хеша потребует порядка 1000 тактов. Тогда для заполнения 2 множеств потребуется 2*1000*100000 = 2*10 8 тактов, при частоте при частоте 3*10 9 получаем меньше 0.1 секунды.
Сам поиск займет O(n), тут сложно говорить о величине этого O, но в реальности оно небольшое. Допустим, 10 4 тактов. В этом случае весь поиск займет порядка 10 9 тактов, или меньше секунды.

Наиболее тонкий момент тут - написать хорошую хеш-функцию. Используем простые числа, либо берем из какой-нибудь библиотеки, например, apache commons
...
Рейтинг: 0 / 0
23.07.2014, 12:59
    #38703814
whizzzkey
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Благодарю всех за ответы!
...
Рейтинг: 0 / 0
25.07.2014, 16:15
    #38706161
mbiz
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Добрый день.
Во блин, моя задачка на родной sql.ru попала, приятно :)
Вообще, мы ищем синьора. Надо будет с HR поругаться, что вводят соискателей в заблуждение.
ivanra предельно точно и полно объяснил решение, и добавить нечего.
Или хеш (какой нибудь HashSet + определить методы equals и hashCode), или упорядоченный поиск (TreeSet + кастомный компаратор). Оба решения принимаются. Хотя, если человек предлагает второй вариант (TreeSet), я начинаю относиться к нему с подозрением.
...
Рейтинг: 0 / 0
25.07.2014, 17:09
    #38706240
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
whizzzkey,

автордолжен работать не больше нескольких секунд,

-- это интересный критерий ! Ещё никогда о таких подходах не слышал.
...
Рейтинг: 0 / 0
25.07.2014, 17:50
    #38706275
mbiz
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Я не спец в этом вопросе. Но вот набрал в поиске: http://goo.gl/zU47xh
Верхние два результата
авторКубок ОАО ``Концерн ``НПО ``Аврора'' по программированию (что бы это ни значило)
Пример задачи
Задано целое число n. Требуется найти число различных делителей n.
На ввод подается целое число n (1 ≤ n ≤ 109).
Следует вывести число различных делителей n.
Ограничения по времени: 0.1 сек.
Ограничения по памяти: 64 мегабайта.авторПравила Четырнадцатой Всероссийской командной олимпиады школьников по программированию
Жюри указывает ограничения на время работы программы на одном тесте и на размер доступной памяти в формулировках задач.
...
Рейтинг: 0 / 0
25.07.2014, 17:53
    #38706277
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
MasterZivwhizzzkey,

автордолжен работать не больше нескольких секунд,

-- это интересный критерий ! Ещё никогда о таких подходах не слышал.
Там несколько секунд будет ClassLoader будет прогружать деревище классов.
...
Рейтинг: 0 / 0
25.07.2014, 18:05
    #38706283
wst
wst
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Просто чтобы уточнить - "ищем синьора", но один из критериев - знает ли он хоть что-то о явовских коллекциях?
...
Рейтинг: 0 / 0
25.07.2014, 18:23
    #38706294
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Синьор не станет разговаривать на собеседовании о коллекциях.
...
Рейтинг: 0 / 0
25.07.2014, 18:34
    #38706302
mbiz
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
wstПросто чтобы уточнить - "ищем синьора", но один из критериев - знает ли он хоть что-то о явовских коллекциях?

Типа того. Незатратный для меня по времени способ провести первичный отсев. Многие соискатели, даже имеющие в резюме 10+ лет опыта разработки на Java, не справляются с этой детской задачкой на 20 минут (это если ещё и тесты писать).
...
Рейтинг: 0 / 0
25.07.2014, 18:45
    #38706307
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
mbiz Типа того. Незатратный для меня по времени способ провести первичный отсев. Многие соискатели, даже имеющие в резюме 10+ лет опыта разработки на Java, не справляются с этой детской задачкой на 20 минут (это если ещё и тесты писать).
м-да.
...
Рейтинг: 0 / 0
25.07.2014, 21:35
    #38706382
private
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
На собеседовании (по JavaScript правда, не по Java) преподаватель вуза или колледжа какого-то который преподавал для студентов веб программирование с многолетним опытом, и убедительным рассказом об опыте работы - не смог написать реализацию метода map :)
...
Рейтинг: 0 / 0
25.07.2014, 22:00
    #38706391
cdtyjv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
maytonСиньор не станет разговаривать на собеседовании о коллекциях.А о чем сеньер будет разговаривать?
...
Рейтинг: 0 / 0
25.07.2014, 22:02
    #38706392
забыл ник
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
cdtyjvmaytonСиньор не станет разговаривать на собеседовании о коллекциях.А о чем сеньер будет разговаривать?

Зп, обеды, личный водитель.. все как обычно :)
...
Рейтинг: 0 / 0
26.07.2014, 14:55
    #38706553
chpasha
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
privatemap :)
стесняюсь спросить, что делает метод map? карту гугла показывает?
...
Рейтинг: 0 / 0
26.07.2014, 14:59
    #38706556
mbiz
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Поправил немного описание:
бла-бла ... у которых совпадают все 3 поля: username, email, passwordHash.
Пользоваться можно только стандартными классами Java SE версии не выше 7 (восьмёрку я ещё ниасиливал, да и пока мало она в реальных проектах используется).
Алгоритм должен быть реализован более эффективно, чем простой перебор. В качестве приблизительного критерия можно использовать условие, что метод findDuplicates должен работать не больше нескольких секунд, если на вход получает 2 коллекции по 100 тысяч элементов в каждой. Мой вариант решения, поправьте, если он не совершенен :)
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
package com.noname;

import java.util.*;

public class UserUtils {

    public static List<User> findDuplicates(Collection<User> collA, Collection<User> collB) {
        if (collA == null || collB == null) {
            return Collections.emptyList();
        }

        Set<UserWrapper> wrapperSetB = new HashSet<>(collB.size());
        for (User userB : collB) {
            wrapperSetB.add(new UserWrapper(userB));
        }

        Set<UserWrapper> wrapperDuplicates = new HashSet<>();

        for (User userA : collA) {
            UserWrapper sample = new UserWrapper(userA);
            if (wrapperSetB.contains(sample)) {
                wrapperDuplicates.add(sample);
            }
        }

        List<User> duplicates = new ArrayList<>(wrapperDuplicates.size());
        for (UserWrapper wrapper : wrapperDuplicates) {
            duplicates.add(wrapper.user);
        }

        return duplicates;
    }

    private static class UserWrapper {

        final User user;

        UserWrapper(User user) {
            this.user = user;
        }

        @Override
        public int hashCode() {
            return hashCode(user.getUsername()) * 633910099
                    + hashCode(user.getEmail()) * 160481183
                    + Arrays.hashCode(user.getPasswordHash());
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof UserWrapper)) {
                return false;
            }
            User u = ((UserWrapper) obj).user;
            return equal(user.getUsername(), u.getUsername()) && equal(user.getEmail(), u.getEmail())
                    && Arrays.equals(user.getPasswordHash(), u.getPasswordHash());
        }

        static boolean equal(Object o1, Object o2) {
            return o1 == o2 || (o1 != null && o1.equals(o2));
        }

        static int hashCode(Object o) {
            return o == null ? 961748941 : o.hashCode();
        }
    }

    private static final int NUMBER_OF_USERS = 100000;
    private static Random RANDOM = new Random();

    public static void main(String[] args) {
        List<User> listA = new ArrayList<>(NUMBER_OF_USERS);
        List<User> listB = new ArrayList<>(NUMBER_OF_USERS);

        for (int i = 0; i < NUMBER_OF_USERS; i++) {
            User userA = newUser();
            listA.add(userA);

            listB.add(newUser());

            if (i % 1000 == 0) {
                // Добавим дубликат.
                User userB = new User();
                userB.setUsername(userA.getUsername());
                userB.setEmail(userA.getEmail());
                userB.setPasswordHash(Arrays.copyOf(userA.getPasswordHash(), userA.getPasswordHash().length));
                listB.add(userB);
            }
        }

        long stamp = System.currentTimeMillis();

        List<User> dups = findDuplicates(listA, listB);

        System.out.println(dups.size() + " " + (System.currentTimeMillis() - stamp) / 1000d);
    }

    private static User newUser() {
        User user = new User();

        user.setUsername(Math.random() + "");
        user.setEmail(Math.random() + "");

        byte[] bytes = new byte[32];
        RANDOM.nextBytes(bytes);
        user.setPasswordHash(bytes);

        return user;
    }
}
...
Рейтинг: 0 / 0
26.07.2014, 15:06
    #38706558
mbiz
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
Из кода можно подчерпнуть много информации помимо собственно правильно/неправильно решил. В код профессионала можно даже не вчитываться, сразу всё понятно просто по форматированию, именованию переменных и другим признакам. И наоборот, если "школьник" перед собеседованием случайно решал аналогичную задачу, и даже выдал правильное решение, код его обязательно выдаст.
...
Рейтинг: 0 / 0
26.07.2014, 19:37
    #38706628
wst
wst
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
А можно еще увидеть код того самого профессионала? То есть, в числе прочего, человека, способного задуматься что это за пользователи, различающиеся только паролями и что если это не подвох в задаче, а реальное требование, то неплохо бы хоть как-то этот момент прояснить в комментариях.
...
Рейтинг: 0 / 0
26.07.2014, 23:44
    #38706670
no56892
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задачка на собеседовании. Коллекции.
авторне справляются с этой детской задачкой на 20 минут (это если ещё и тесты писать).
ВСЁ ИМХО: я что-то сомневаюсь, что Вы успеете за двадцать минут с ходу сделать. А мы то знаем как подобные здачки появляются на свет. Группа прогеров натыкается на проблему, несколько часов (не постесняюсь, даже дней!) пытаются сделать хоть что-то, потом еще столько же отлаживают, а потом на собеседовании просят за 20 мин. на листе бумаги накодить. Неадекват реально. Понимаю если-б какой нить микрософт или оракл хотя бы такое устраивал, а так ваще!
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / Задачка на собеседовании. Коллекции. / 25 сообщений из 42, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]