Data Structure Design - How to Succeed in Algorithms Interview


Data Structure Design - How to Succeed in Algorithms Interview

How to Succeed in Algorithms Interview Series


Implementation Detail

  • DoubleLinkedList + Map/TreeMap
  • Use DoubleLinkedList class to wrap the logic of maintain head tail nodes.
  • use version to track valid element in map

DoubleLinkedList + Map/TreeMap

Freq Buckets

  • freq increases from 1 to n continuously
  • LeetCode 895 - Maximum Frequency Stack: popMax
    class FreqStack {
      List<Stack<Integer>> bucket;
      HashMap<Integer, Integer> map;
      public FreqStack() {
          bucket = new ArrayList<>();
          map = new HashMap<>();
      }
      public void push(int x) {
          map.put(x, map.getOrDefault(x, 0) + 1);
          int freq = map.get(x);
          if (freq - 1 >= bucket.size()) {
              bucket.add(new Stack<Integer>());
          }
          bucket.get(freq - 1).add(x);
      }
      public int pop() {
          int freq = bucket.size();
          int x = bucket.get(freq - 1).pop();
          if (bucket.get(freq - 1).isEmpty()) bucket.remove(bucket.size() - 1);
          map.put(x, map.get(x) - 1);
          if (map.get(x) == 0) map.remove(x);
          return x;
      }
    }
    class FreqStack {
      class Pair{
          int num;
          int count;
          int time;
          Pair(int num, int count, int time){
              this.num = num;
              this.count = count;
              this.time = time;
          }
      }
      private PriorityQueue<Pair> queue;
      private HashMap<Integer,Integer> map;
      private int clock = 0;
      public FreqStack() {
          queue = new PriorityQueue<Pair>((a,b) -> (a.count == b.count?b.time-a.time:b.count-a.count));
          map = new HashMap();
      }
      public void push(int x) {
          Pair pair = new Pair(x,map.getOrDefault(x,0)+1,clock++);
          map.put(x,map.getOrDefault(x,0)+1);
          queue.offer(pair);
      }
      public int pop() {
          Pair cur = queue.poll();
          // update
          map.put(cur.num,map.getOrDefault(cur.num,0)-1);
          return cur.num;
      }   
    }
  • Design a Data Structure with Insert & Delete & GetMostFrequent of O(1) - LRU
    • HashMap<Integer, Node> map: Node contains all values with same frequency
  • LeetCode 432 - All O`one Data Structure
    // maintain a doubly linked list of Buckets
    private Bucket head;
    private Bucket tail;
    // for accessing a specific Bucket among the Bucket list in O(1) time
    private Map<Integer, Bucket> countBucketMap;
    // keep track of count of keys
    private Map<String, Integer> keyCountMap;
    // each Bucket contains all the keys with the same count
    // sorted linked
    private class Bucket {
      int count;
      Set<String> keySet;
      Bucket next;
      Bucket pre;
      public Bucket(int cnt) {
          count = cnt;
          keySet = new HashSet<>();
      }
    }

Custom LinkedList + HashMap

  • LeetCode 146 - Least Recently Used (LRU) Cache
    • Linkedlist + HashMap
  • [LeetCode 460 - LFU Cache][keyValueMap, freqMap, Map<Integer, LinkedHashSet> sameFreqMap, minFreq](https://leetcode.com/problems/lfu-cache/discuss/94521/java-o1-very-easy-solution-using-3-hashmaps-and-linkedhashset)
    private Node head = null;
    private int cap = 0;
    private HashMap<Integer, Integer> valueHash = null;
    private HashMap<Integer, Node> nodeHash = null;
    public LFUCache(int capacity) {
      this.cap = capacity;
      valueHash = new HashMap<Integer, Integer>();
      nodeHash = new HashMap<Integer, Node>();
    }
    public int get(int key) {
      if (valueHash.containsKey(key)) {
          increaseCount(key);
          return valueHash.get(key);
      }
      return -1;
    }
    public void set(int key, int value) {
      if ( cap == 0 ) return;
      if (valueHash.containsKey(key)) {
          valueHash.put(key, value);
      } else {
          if (valueHash.size() < cap) {
              valueHash.put(key, value);
          } else {
              removeOld();
              valueHash.put(key, value);
          }
          addToHead(key);
      }
      increaseCount(key);
    }
    private void addToHead(int key) {
      if (head == null) {
          head = new Node(0);
          head.keys.add(key);
      } else if (head.count > 0) {
          Node node = new Node(0);
          node.keys.add(key);
          node.next = head;
          head.prev = node;
          head = node;
      } else {
          head.keys.add(key);
      }
      nodeHash.put(key, head);      
    }
    private void increaseCount(int key) {
      Node node = nodeHash.get(key);
      node.keys.remove(key);
      if (node.next == null) {
          node.next = new Node(node.count+1);
          node.next.prev = node;
          node.next.keys.add(key);
      } else if (node.next.count == node.count+1) {
          node.next.keys.add(key);
      } else {
          Node tmp = new Node(node.count+1);
          tmp.keys.add(key);
          tmp.prev = node;
          tmp.next = node.next;
          node.next.prev = tmp;
          node.next = tmp;
      }
      nodeHash.put(key, node.next);
      if (node.keys.size() == 0) remove(node);
    }
    private void removeOld() {
      if (head == null) return;
      int old = 0;
      for (int n: head.keys) {
          old = n;
          break;
      }
      head.keys.remove(old);
      if (head.keys.size() == 0) remove(head);
      nodeHash.remove(old);
      valueHash.remove(old);
    }
    private void remove(Node node) {
      if (node.prev == null) {
          head = node.next;
      } else {
          node.prev.next = node.next;
      }
      if (node.next != null) {
          node.next.prev = node.prev;
      }
    }
    class Node {
      public int count = 0;
      public LinkedHashSet<Integer> keys = null;
      public Node prev = null, next = null;
    }

N Queens

Map<Integer, Integer> row = new HashMap();       // row number to count of lamps
Map<Integer, Integer> col = new HashMap();       // col number to count of lamps
Map<Integer, Integer> diag = new HashMap();       // diagonal x-y to count of lamps
Map<Integer, Integer> diag2 = new HashMap();       // diagonal x+y to count of lamps
Map<Integer, Boolean> lamps = new HashMap();       // whether lamp is  ON|OFF

Examples

Binary Tree

  • [Google – Manager Peer Problem]
  1. setManager(A, B) sets A as a direct manager of B
  2. setPeer(A, B) sets A as a colleague of B. After that, A and B will have the same direct Manager.
  3. query(A, B) returns if A is in the management chain of B.
  • Map<Integer, TNode> nodeMap
  • union find: int[] parent

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)