LeetCode

381. O(1) 时间插入、删除和获取随机元素 - 允许重复

常数时间的插入容易想到链表和数组,常数时间的删除容易想到哈希表,元素被返回的概率与这个元素的数量有关意味着必须要能统计这个元素出现的次数,容易想到哈希表。注意是平均情况下的复杂度
删除的情况写起来容易出错,面试的时候需要额外注意。

  1. class RandomizedCollection {
  2. int size = 0;
  3. int[] values;
  4. Map<Integer, Set<Integer>> positions;
  5. Random rdm;
  6. public RandomizedCollection() {
  7. values = new int[1024];
  8. positions = new HashMap();
  9. rdm = new Random();
  10. }
  11. public boolean insert(int val) {
  12. if (size == values.length) {
  13. values = Arrays.copyOf(values, size << 1);
  14. }
  15. Set<Integer> position = positions.getOrDefault(val, new HashSet<Integer>());
  16. position.add(size);
  17. positions.put(val, position);
  18. values[size++] = val;
  19. return position.size() == 1 ? true : false;
  20. }
  21. public boolean remove(int val) {
  22. if (positions.getOrDefault(val, new HashSet<Integer>()).size() == 0) return false;
  23. for (int pos : positions.get(val)) {
  24. delete(pos);
  25. break;
  26. }
  27. return true;
  28. }
  29. private void delete(int position) {
  30. int deleteVal = values[position], lastPositionVal = values[size-1];
  31. if (deleteVal != lastPositionVal) {
  32. values[position] = lastPositionVal;
  33. positions.get(lastPositionVal).remove(size-1);
  34. positions.get(lastPositionVal).add(position);
  35. positions.get(deleteVal).remove(position);
  36. } else {
  37. positions.get(deleteVal).remove(size-1);
  38. }
  39. size--;
  40. }
  41. public int getRandom() {
  42. if (size == 0) return -1;
  43. return values[rdm.nextInt(size)];
  44. }
  45. }