zoukankan      html  css  js  c++  java
  • 数据结构设计 Stack Queue

    之前在简书上初步总结过几个有关栈和队列的数据结构设计的题目。http://www.jianshu.com/p/d43f93661631

    1.线性数据结构

      Array Stack Queue Hash

    2.非线性数据结构

      Tree HashMap Heap/PriorityQueue

    3.HashSet HashMap HashTable的区别:

        hashMap的键就组成一个HashSet

      HashTble实现是基于Dictionary类,而HashMap是基于Map接口

        HashTable是线程安全的,HashMap不是线程安全的,效率更高

          HashTable不允许空键值,HashMap允许空键值。

    4.Hash Function

      4.1对于给定键值,产生一个固定的无规律的介于 0 ~ capacity之间的一个值

      4.2再好的HashFunction也可能存在冲突,解决冲突的方法:开放定址法和拉链法。

      4.3当hash不够大时,就需要rehash

    5.Heap 支持O(logn)的添加,O(logn)的删除堆顶元素,O(1)的max/min(最大堆 Vs 最小堆) PriorityQueue heap的java实现

    6.TreeMap 支持O(logn)的任意位置的查找删除,比起Heap,只是在min/max的获取上时间复杂度为O(logn)。

    7.LRU:最近最少使用页面置换算法,淘汰最长时间未被使用的页面,关键是页面最后一次内使用到发生页面调度的时间长短。

     LFU:最近最不常用页面置换算法,淘汰一定时期内被访问次数最少的页面,关键是看一定时期内页面被使用的频率。

    8. HashMap Hashtable TreeMap LinkedHashMap的区别于联系

    这四个类都是Map接口的实现类。Map主要用于存取键值对,根据键得到值,因此不允许键重复(覆盖机制),但允许值重复。
    
    HashMap: 1. 访问数据很快,一般用于获取键值和查找是否包含某个键值
                    2. HashMap 最多允许一条记录的键为null, 允许多条值记录为null
                    3. 不是线程同步的
    
    HashTable: 1. 相对于hashMap速度较慢
                      2. 键和值都不能为null
                      3. 是线程同步的
    
    LinkedHashMap :1.HashMap的一个子类,保存了记录的插入顺序。
                         2.在用Iterator遍历 LinkedHashMap 时,先得到的记录肯定是先插入的。
                            也可以在构造时用带参数按照应用次数排序。
                         3. 在遍历的时候会比HashMap慢,不过有种情况例外,当 HashMap容量
                             很大,实际数据较少时,遍历起来可能会比 LinkedHashMap慢因为
                             LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而
                             HashMap的遍历速度和他的容量有关  
                         4. 按应用次数排序需要在构造函数中传入true。
                         5. 也可指定LinkedHashMap的大小,使得大于某个size的时候删除最早来
                             的数据。
    LinkedHashMap<Integer, Integer> lm = new LinkedHashMap<Integer, Integer>(10, (float) 0.75, true) {
                @Override
                protected boolean removeEldestEntry(Map.Entry eldest) {
                    return size() > 3;
                }
            };
    
    
    TreeMap: TreeMap实现sortMap接口,能够让保存的记录根据键排序,可以通过自定义
                   比较器以实现自定义排序方法。            
    

      

    实现猫狗队列,猫类型和狗类型都继承自Pet类型

    Pet类型如下

    要求如下:

    思路:

    如果使用一个队列来存储,那么无法区分猫和狗;如果使用两个队列,那么pollAll()中猫和狗的先后顺序无法区分;继续思考时候可以使用一个时间戳,相当于一个map,键为pet,值为其如队列的时间,但是这带来一个问题就是同一个宠物多次进队列的问题。所以,采用新建一个数据结构PetEnterQueue类型,对之前的宠物进行封装。这个类型包含Pet和count两个变量,然后猫狗队列中实际存放的是这个PetEnterQueue的实例,如队列的时候可以检测时猫还是狗然后封装进count之后进入各自的队列(猫和狗),然后pollDog pollPet的时候自个儿弹就行了,pollAll的时候先弹出两个队列头的count较小的。

    Animal Shelter

    在一个宠物避难所里,仅有两种动物可供领养,且领养时严格执行“先进先出”的规则。如果有人想要从避难所领养动物,他只有两种选择:要么选择领养所有动物中最资深的一只(根据到达避难所的时间,越早到的越资深),要么选择领养猫或狗(同样,也只能领养最资深的一只)。也就是说,领养者不能随意选择某一指定动物。请建立一个数据结构,使得它可以运行以上规则,并可实现 enqueuedequeueAnydequeueDog, 和 dequeueCat 操作。

     1 public static final int DOG = 1;
     2     public static final int CAT = 2;
     3     private int stamp;
     4     private Queue<PetEnqueue> dogQueue;
     5     private Queue<PetEnqueue> catQueue;
     6     public AnimalShelter() {
     7         // do initialize if necessary
     8         stamp = 0;
     9         dogQueue = new LinkedList<PetEnqueue>();
    10         catQueue = new LinkedList<PetEnqueue>();
    11     }
    12 
    13     /**
    14      * @param name a string
    15      * @param type an integer, 1 if Animal is dog or 0
    16      * @return void
    17      */
    18     void enqueue(String name, int type) {
    19         // Write your code here
    20         if (type == DOG) {
    21             dogQueue.offer(new PetEnqueue(name, stamp++));
    22         } else {
    23             catQueue.offer(new PetEnqueue(name, stamp++));
    24         }
    25     }
    26 
    27     public String dequeueAny() {
    28         // Write your code here
    29         if (dogQueue.isEmpty() && catQueue.isEmpty()) {
    30             return "";
    31         }
    32         if (dogQueue.isEmpty()) {
    33             return catQueue.poll().pet;
    34         }
    35         if (catQueue.isEmpty()) {
    36             return dogQueue.poll().pet;
    37         }
    38         int dog_stamp = dogQueue.peek().stamp;
    39         int cat_stamp = catQueue.peek().stamp;
    40         if (dog_stamp < cat_stamp) {
    41             return dogQueue.poll().pet;
    42         } else {
    43             return catQueue.poll().pet;
    44         }
    45     }
    46 
    47     public String dequeueDog() {
    48         // Write your code here
    49         if (dogQueue.isEmpty()) {
    50             return "";
    51         }
    52         return dogQueue.poll().pet;
    53     }
    54 
    55     public String dequeueCat() {
    56         // Write your code here
    57          if (catQueue.isEmpty()) {
    58             return "";
    59         }
    60         return catQueue.poll().pet;
    61     }
    62 }
    63 class PetEnqueue {
    64     String pet;
    65     int stamp;
    66     public PetEnqueue(String pet, int stamp) {
    67         this.pet = pet;
    68         this.stamp = stamp;
    69     }
    View Code

    Min Stack

    Implement a stack with min() function, which will return the smallest number in the stack.

    It should support push, pop and min operation all in O(1) cost.

    方法一:使用两个栈,内容栈和最小栈同入同出

     1 Stack<Integer> contentStack;
     2     Stack<Integer> minStack;
     3     
     4     public MinStack() {
     5         // do initialize if necessary
     6         contentStack = new Stack<Integer>();
     7         minStack = new Stack<Integer>();
     8         minStack.push(Integer.MAX_VALUE);
     9     }
    10 
    11     public void push(int number) {
    12         // write your code here
    13         contentStack.push(number);
    14         minStack.push(minStack.peek() < number ? minStack.peek() : number);
    15     }
    16 
    17     public int pop() {
    18         // write your code here
    19         minStack.pop();
    20         return contentStack.pop();
    21     }
    22 
    23     public int min() {
    24         // write your code here
    25         return minStack.peek();
    26     }
    View Code

    方法二:使用两个栈。入栈的时候,只有当前元素小于等于最小栈栈顶才入栈,出栈的时候只有内容栈等于最小栈栈顶,才弹出最小栈的栈顶元素。

    注意最小栈压栈的时候是和最小站中的元素比较。

     1 Stack<Integer> contentStack;
     2     Stack<Integer> minStack;
     3     
     4     public MinStack() {
     5         // do initialize if necessary
     6         contentStack = new Stack<Integer>();
     7         minStack = new Stack<Integer>();
     8     }
     9 
    10     public void push(int number) {
    11         // write your code here
    12         contentStack.push(number);
    13         if (minStack.isEmpty() || number <= minStack.peek()) {
    14             minStack.push(number);
    15         }
    16     }
    17 
    18     public int pop() {
    19         // write your code here
    20         int temp = contentStack.pop();
    21         if (temp == minStack.peek()) {
    22             minStack.pop();
    23         }
    24         return temp;
    25     }
    26 
    27     public int min() {
    28         // write your code here
    29         return minStack.peek();
    30     }
    View Code

    Stack Sorting

    Sort a stack in ascending order (with biggest terms on top).

    You may use at most one additional stack to hold items, but you may not copy the elements into any other data structure (e.g. array).

     1 public void stackSorting(Stack<Integer> stack) {
     2         // Write your code here
     3         Stack<Integer> help = new Stack<Integer>();
     4         while (!stack.isEmpty()) {
     5             int val = stack.pop();
     6             if (help.isEmpty() ||  val <= help.peek()) {
     7                 help.push(val);
     8             } else {
     9                 int num = 0;
    10                 while(!help.isEmpty() && help.peek() < val) {
    11                     stack.push(help.pop());
    12                     num++;
    13                 }
    14                 help.push(val);
    15                 for (int i = 0; i < num; i++) {
    16                     help.push(stack.pop());
    17                 }
    18             }
    19         }
    20         while (!help.isEmpty()) {
    21             stack.push(help.pop());
    22         }
    23     }
    View Code

    Largest Rectangle in Histogram

    Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

     1 public int largestRectangleArea(int[] height) {
     2         // write your code here
     3         if (height == null || height.length == 0) {
     4             return 0;
     5         }
     6         int max = 0;
     7         Stack<Integer> stack = new Stack<Integer>();
     8         stack.push(-1);
     9         for (int i = 0; i <= height.length; i++) {
    10             int val = i == height.length ? -1 : height[i];
    11             while(stack.peek() != -1 && val <= height[stack.peek()]){
    12                 int cur = stack.pop();
    13                 max = Math.max(max, height[cur] * (i - stack.peek() - 1));
    14             }
    15             stack.push(i);
    16         }
    17         return max;
    18     }
    View Code

    Maximal Rectangle

    Given a 2D boolean matrix filled with False and True, find the largest rectangle containing all True and return its area.

     1 public int maximalRectangle(boolean[][] matrix) {
     2         // Write your code here
     3         if (matrix == null || matrix.length == 0) {
     4             return 0;
     5         }
     6         int max = 0;
     7         int m = matrix.length;
     8         int n = matrix[0].length;
     9         int[] height = new int[n];
    10         for (int i = 0; i < m; i++) {
    11             for (int j = 0; j < n; j++) {
    12                 if (matrix[i][j]) {
    13                     height[j] += 1;
    14                 } else {
    15                     height[j] = 0;
    16                 }
    17             }
    18             max = Math.max(max, maxRectangle(height));
    19         }
    20         return max;
    21     }
    22     public int maxRectangle(int[] height) {
    23         int max = 0;
    24         Stack<Integer> stack = new Stack<Integer>();
    25         stack.push(-1);
    26         for (int i = 0; i <= height.length; i++) {
    27             int val = i == height.length ? -1 : height[i];
    28             while (stack.peek() != -1 && val <= height[stack.peek()]) {
    29                 int cur = stack.pop();
    30                 max = Math.max(max, height[cur] * (i - stack.peek() - 1));
    31             }
    32             stack.push(i);
    33         }
    34         return max;
    35     }
    View Code

    Max Tree ***** --not bug free

    Given an integer array with no duplicates. A max tree building on this array is defined as follow:

    • The root is the maximum number in the array
    • The left subtree and right subtree are the max trees of the subarray divided by the root number.

    Construct the max tree by the given array.

    使用一个栈来记录子树,遍历原数组,如果新来的数小于栈顶树根节点的值,那么新节点作为子树放入栈中,如果新来的数大,那么进行弹出操作,弹出栈顶元素,如果此时栈为空,表明栈顶元素就是新来的数的左二子,否则,考察弹出之后的栈顶left,弹出的middle和当前讨论的right。现在有left right的值时大于middle的值的,那么middle应该挂在哪呢?这由left和right的值的大小关系决定,如果left的值大,则right.left = middle,否则就是right的值大,left.right = middle。同样为了处理5 4 3 2 1的情况,最后需要传进来一个大数把栈中元素都弹出。

     1 public TreeNode maxTree(int[] A) {
     2         // write your code here
     3         if (A == null || A.length == 0) {
     4             return new TreeNode(0);
     5         }
     6         Stack<TreeNode> stack = new Stack<TreeNode>();
     7         for (int i = 0; i <= A.length; i++) {
     8             TreeNode right = i == A.length ? new TreeNode(Integer.MAX_VALUE) 
     9                                          : new TreeNode(A[i]);
    10             while (!stack.isEmpty() && right.val > stack.peek().val) {
    11                 TreeNode middle = stack.pop();
    12                 if (stack.isEmpty()) {
    13                     right.left = middle;
    14                 } else {
    15                     TreeNode left = stack.peek();
    16                     if (left.val < right.val) {
    17                         left.right = middle;
    18                     } else {
    19                         right.left = middle;
    20                     }
    21                 }
    22             }
    23             stack.push(right);
    24         }
    25         return stack.peek().left;
    26     }
    View Code

    Implement Queue by Two Stacks

     1 private Stack<Integer> stack1;
     2     private Stack<Integer> stack2;
     3 
     4     public Queue() {
     5        // do initialization if necessary
     6        stack1 = new Stack<Integer>();
     7        stack2 = new Stack<Integer>();
     8     }
     9     
    10     public void push(int element) {
    11         // write your code here
    12         stack1.push(element);
    13     }
    14 
    15     public int pop() {
    16         // write your code here
    17         if (stack2.isEmpty()) {
    18             while (!stack1.isEmpty()) {
    19                 stack2.push(stack1.pop());
    20             }
    21         }
    22         return stack2.pop();
    23     }
    24 
    25     public int top() {
    26         // write your code here
    27         if (stack2.isEmpty()) {
    28             while (!stack1.isEmpty()) {
    29                 stack2.push(stack1.pop());
    30             }
    31         }
    32         return stack2.peek();
    33     }
    View Code

    Implement Stack by Two Queues

     1 Queue<Integer> data = new LinkedList<Integer>();
     2     Queue<Integer> help = new LinkedList<Integer>();
     3     // Push a new item into the stack
     4     public void push(int x) {
     5         // Write your code here
     6         data.offer(x);
     7     }
     8 
     9     // Pop the top of the stack
    10     public void pop() {
    11         // Write your code here
    12         while (data.size() != 1) {
    13             help.offer(data.poll());
    14         }
    15         data.poll();
    16         while (!help.isEmpty()) {
    17             data.offer(help.poll());
    18         }
    19     }
    20 
    21     // Return the top of the stack
    22     public int top() {
    23         // Write your code here
    24         while (data.size() != 1) {
    25             help.offer(data.poll());
    26         }
    27         
    28         int result = data.peek();
    29         help.offer(data.poll());
    30         
    31         while (!help.isEmpty()) {
    32             data.offer(help.poll());
    33         }
    34         return result;
    35     }
    36 
    37     // Check the stack is empty or not.
    38     public boolean isEmpty() {
    39         // Write your code here
    40         return data.isEmpty();
    41     }   
    View Code

      优化,交换queue1 queue2的指针:

     1 Queue<Integer> queue1;
     2     Queue<Integer> queue2;
     3     public MyStack() {
     4         queue1 = new LinkedList<Integer>();
     5         queue2 = new LinkedList<Integer>();
     6     }
     7     
     8     public void moveItems() {
     9         while (queue1.size() > 1) {
    10             queue2.offer(queue1.poll());
    11         }
    12     }
    13     
    14     public void swapQueues() {
    15         Queue<Integer> temp = queue1;
    16         queue1 = queue2;
    17         queue2 = temp;
    18     }
    19     
    20     // Push element x onto stack.
    21     public void push(int x) {
    22         queue1.offer(x);
    23     }
    24 
    25     // Removes the element on top of the stack.
    26     public void pop() {
    27         moveItems();
    28         queue1.poll();
    29         swapQueues();
    30     }
    31 
    32     // Get the top element.
    33     public int top() {
    34         moveItems();
    35         int val = queue1.poll();
    36         queue2.offer(val);
    37         swapQueues();
    38         return val;
    39     }
    40 
    41     // Return whether the stack is empty.
    42     public boolean empty() {
    43         return queue1.isEmpty();
    44     }
    View Code

     Implement Stack

    Implement a stack. You can use any data structure inside a stack except stack itself to implement it.

     1 Node dummyHead;
     2     Node dummyEnd;
     3     public Stack() {
     4         dummyHead = new Node(0);
     5         dummyEnd = new Node(0);
     6         dummyHead.next = dummyEnd;
     7         dummyEnd.prev = dummyHead;
     8     }
     9     // Push a new item into the stack
    10     public void push(int x) {
    11         // Write your code here
    12         Node cur = new Node(x);
    13         cur.next = dummyHead.next;
    14         cur.next.prev = cur;
    15         dummyHead.next = cur;
    16         cur.prev = dummyHead;
    17     }
    18 
    19     // Pop the top of the stack
    20     public void pop() {
    21         // Write your code here
    22         dummyHead.next = dummyHead.next.next;
    23         dummyHead.next.prev = dummyHead;
    24     }
    25 
    26     // Return the top of the stack
    27     public int top() {
    28         // Write your code here
    29         return dummyHead.next.val;
    30     }
    31 
    32     // Check the stack is empty or not.
    33     public boolean isEmpty() {
    34         // Write your code here
    35         return dummyHead.next == dummyEnd;
    36     }    
    37 }
    38 class Node {
    39     int val;
    40     Node prev;
    41     Node next;
    42     public Node(int val) {
    43         this.val = val;
    44     }
    View Code

    Implement Queue by Linked List

     Node dummyHead;
        Node dummyEnd;
        public Queue() {
            // do initialize if necessary
            dummyHead = new Node(0);
            dummyEnd = new Node(0);
            dummyHead.prev = dummyEnd;
            dummyEnd.next = dummyHead;
        }
    
        public void enqueue(int item) {
            // Write your code here
            Node cur = new Node(item);
            cur.next = dummyEnd.next;
            dummyEnd.next.prev = cur;
            dummyEnd.next = cur;
            cur.prev = dummyEnd;
        }
    
        public int dequeue() {
            // Write your code here
            if (dummyEnd.next == dummyHead) {
                return Integer.MAX_VALUE;
            }
            Node top = dummyHead.prev;
            top.prev.next = dummyHead;
            dummyHead.prev = top.prev;
            return top.val;
        }
        
        class Node {
            int val;
            Node next;
            Node prev;
            public Node(int val) {
                this.val = val;
            }
        }
    View Code

    Implement Queue by Linked List II

     1 private LinkedList<Integer> list;
     2     
     3     public Dequeue() {
     4         // do initialize if necessary
     5         list = new LinkedList<Integer>();
     6     }
     7 
     8     public void push_front(int item) {
     9         // Write your code here
    10         list.add(item);
    11     }
    12 
    13     public void push_back(int item) {
    14         // Write your code here
    15         list.addFirst(item);
    16     }
    17 
    18     public int pop_front() {
    19         // Write your code here
    20         return list.removeLast();
    21     }
    22 
    23     public int pop_back() {
    24         // Write your code here
    25         return list.removeFirst();
    26     }
    View Code

    Hash Function --not bug free

    1 public int hashCode(char[] key,int HASH_SIZE) {
    2         // write your code here
    3         long ans = 0;
    4         for (int i = 0; i < key.length; i++) {
    5             ans = (ans * 33 + (int)key[i]) % HASH_SIZE;
    6         }
    7         return (int)ans;
    8     }
    View Code

    Rehashing

    The size of the hash table is not determinate at the very beginning. If the total size of keys is too large (e.g. size >= capacity / 10), we should double the size of the hash table and rehash every keys.

    public ListNode[] rehashing(ListNode[] hashTable) {
            // write your code here
            if (hashTable == null || hashTable.length == 0) {
                return hashTable;
            }
            int oldCapacity = hashTable.length;
            int newCapacity = oldCapacity * 2;
            ListNode[] reHash = new ListNode[newCapacity];
            for (int i = 0; i < oldCapacity; i++) {
                ListNode cur = hashTable[i];
                help(cur, reHash);
            }
            return reHash;
        }
        public void help(ListNode cur, ListNode[] reHash) {
            if (cur == null) {
                return;
            }
            int newCapacity = reHash.length;
            help(cur.next, reHash);
            int pos = (cur.val % newCapacity +  newCapacity) % newCapacity;
            ListNode next = reHash[pos];
            reHash[pos] = new ListNode(cur.val);
            reHash[pos].next = next;
        }
    View Code

    LRU Cache **

    注意访问过就要更新在后边

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

    get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
    set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

     1 public class Solution {
     2    
     3     HashMap<Integer, Node> hashMap;
     4     int capacity;
     5     int size;
     6     Node dummyHead;
     7     Node dummyEnd;
     8     
     9     // @param capacity, an integer
    10     public Solution(int capacity) {
    11         // write your code here
    12         hashMap = new HashMap<Integer, Node>();
    13         this.capacity = capacity;
    14         size = 0;
    15         dummyHead = new Node(0,0);
    16         dummyEnd = new Node(0,0);
    17         dummyEnd.next = dummyHead;
    18         dummyHead.prev = dummyEnd;
    19     }
    20 
    21     // @return an integer
    22     public int get(int key) {
    23         // write your code here
    24        
    25         if (hashMap.containsKey(key)) {
    26             set(key, hashMap.get(key).val);
    27             return hashMap.get(key).val;
    28         } else {
    29             return -1;
    30         }
    31     }
    32     // @param key, an integer
    33     // @param value, an integer
    34     // @return nothing
    35     public void set(int key, int value) {
    36         // write your code here
    37         if (hashMap.containsKey(key)) {
    38             Node oldNode = hashMap.get(key);
    39             oldNode.prev.next = oldNode.next;
    40             oldNode.next.prev = oldNode.prev;
    41         } else {
    42             if (size == capacity) {
    43                 Node realHead = dummyHead.prev;
    44                 realHead.prev.next = dummyHead;
    45                 dummyHead.prev = realHead.prev;
    46                 hashMap.remove(realHead.key);
    47             } else {
    48                 size++;
    49             }
    50         }
    51         Node newNode = new Node(key, value);
    52         dummyEnd.next.prev = newNode;
    53         newNode.next = dummyEnd.next;
    54         newNode.prev = dummyEnd;
    55         dummyEnd.next = newNode;
    56         hashMap.put(key, newNode);
    57     }
    58 }
    59 class Node {
    60     int key;
    61     int val;
    62     Node prev;
    63     Node next;
    64     public Node(int key, int val) {
    65         this.key = key;
    66         this.val = val;
    67         prev = null;
    68         next = null;
    69     }
    70 }
    View Code

    LFU Cache

    由于需要检测是有出现过某个键,所以需要一个hashMap,其对应的值为我们定义的Node。

    这里主要有两种想法,其一使用一个PriorityQueue,按照出现次数建立一个minHeap,问题在于这里设立Pq的删除任意位置结点的操作,比较费时间。

    另一种想法是直接使用TreeMap,这样本身就可以检测是否包含某个键,但是这里的问题在于TreeMap需要的是依照Value的大小顺序来排序,这是非常不方便的。

    另外,这里假如frequency都相等的话,需要先拿走最先进入的,这里需要引入一个时间戳来记录这一个属性。

    LFU (Least Frequently Used) is a famous cache eviction algorithm.

    For a cache with capacity k, if the cache is full and need to evict a key in it, the key with the lease frequently used will be kicked out.

    Implement set and get method for LFU cache.

    方法一:PQ

     1 long stamp;
     2     int capacity;
     3     int num;
     4     PriorityQueue<Pair> minHeap;
     5     HashMap<Integer, Pair> hashMap;
     6 
     7     // @param capacity, an integer
     8     public LFUCache(int capacity) {
     9         // Write your code here
    10         this.capacity = capacity;
    11         num = 0;
    12         minHeap = new PriorityQueue<Pair>();
    13         hashMap = new HashMap<Integer, Pair>();
    14         stamp = 0;
    15     }
    16 
    17     // @param key, an integer
    18     // @param value, an integer
    19     // @return nothing
    20     public void set(int key, int value) {
    21         // Write your code here
    22         if (hashMap.containsKey(key)) {
    23             Pair old = hashMap.get(key);
    24             minHeap.remove(old);
    25             
    26             Pair newNode = new Pair(key, value, old.times + 1, stamp++);
    27             
    28             hashMap.put(key, newNode);
    29             minHeap.offer(newNode);
    30         } else if (num == capacity) {
    31             Pair old = minHeap.poll();
    32             hashMap.remove(old.key);
    33             
    34             Pair newNode = new Pair(key, value, 1, stamp++);
    35             
    36             hashMap.put(key, newNode);
    37             minHeap.offer(newNode);
    38         } else {
    39             num++;
    40             Pair pair = new Pair(key, value, 1, stamp++);
    41             hashMap.put(key, pair);
    42             minHeap.offer(pair);
    43         }
    44     }
    45 
    46     public int get(int key) {
    47         // Write your code here
    48         if (hashMap.containsKey(key)) {
    49             Pair old = hashMap.get(key);
    50             minHeap.remove(old);
    51             
    52             Pair newNode = new Pair(key, old.value, old.times + 1, stamp++);
    53             
    54             hashMap.put(key, newNode);
    55             minHeap.offer(newNode);
    56             return hashMap.get(key).value;
    57         } else {
    58             return -1;
    59         }
    60     }
    61     
    62     class Pair implements Comparable<Pair> {
    63         long stamp;
    64         int key;
    65         int value;
    66         int times;
    67         public Pair(int key, int value, int times, long stamp) {
    68             this.key = key;
    69             this.value = value;
    70             this.times = times;
    71             this.stamp = stamp;
    72         }
    73         
    74         public int compareTo(Pair that) {
    75             if (this.times == that.times) {
    76                 return (int)(this.stamp - that.stamp);
    77             } else {
    78                 return this.times - that.times;    
    79             }
    80         }
    81     }
    View Code

     方法二:TreeMap

    今天重新使用treeMap来实现,treeMap的键就是我们自己定义的那个Pair

     1 private int stamp;
     2     private int capacity;
     3     private TreeMap<Pair, Integer> treeMap;
     4     private HashMap<Integer, Pair> hashMap;
     5     // @param capacity, an integer
     6     public LFUCache(int capacity) {
     7         // Write your code here
     8         stamp = 0;
     9         this.capacity = capacity; 
    10         treeMap = new TreeMap<Pair, Integer>();
    11         hashMap = new HashMap<Integer, Pair>();
    12     }
    13 
    14     // @param key, an integer
    15     // @param value, an integer
    16     // @return nothing
    17     public void set(int key, int value) {
    18         // Write your code here
    19         if (hashMap.containsKey(key)) {
    20             Pair old = hashMap.get(key);
    21             treeMap.remove(old);
    22             Pair newPair = new Pair(value, old.times + 1, stamp++);
    23             treeMap.put(newPair, key);
    24             hashMap.put(key, newPair);
    25         } else {
    26             if (treeMap.size() == capacity) {
    27                 Map.Entry<Pair, Integer> min = treeMap.pollFirstEntry();
    28                 hashMap.remove(min.getValue());
    29             }
    30             Pair newPair = new Pair(value, 1, stamp++);
    31             treeMap.put(newPair, key);
    32             hashMap.put(key, newPair);
    33         }
    34     }
    35 
    36     public int get(int key) {
    37         // Write your code here
    38         if (!hashMap.containsKey(key)) {
    39             return -1;
    40         }
    41         Pair old = hashMap.get(key);
    42         treeMap.remove(old);
    43         Pair newPair = new Pair(old.value, old.times + 1, stamp++);
    44         treeMap.put(newPair, key);
    45         hashMap.put(key, newPair);
    46         return old.value;
    47     }
    48     
    49     class Pair implements Comparable<Pair> {
    50         int value;
    51         int times;
    52         int stamp;
    53         public Pair(int value, int times, int stamp) {
    54             this.value = value;
    55             this.times = times;
    56             this.stamp = stamp;
    57         }
    58         
    59         public int compareTo(Pair that) {
    60             if (this.times == that.times) {
    61                 return this.stamp - that.stamp;
    62             } else {
    63                 return this.times - that.times;
    64             }
    65         }
    66     }
    View Code

    Top K Frequent Words**

    语法细节容易出错。

    Given a list of words and an integer k, return the top k frequent words in the list.、

    方法一:获取频数之后,进行排序之后取出前k大。O(n + mlogm)

    View Code

    方法二:保持一个大小为k的最小堆,比方法一效率更高。O(n + klog(k))

    View Code

    Top K Frequent Words II--not bug free

    对比LFU,LFU是新来的有最大的优先级,而这里新来的并不具有最大的优先级,而是所有次数才具有最大的优先级。

    方法一:PQ

    View Code

     方法二:TreeMap 和LFU不同的是,这里其实TreeMap的值已经不起作用了,因为我们并不需要根据删除的treeMap节点去更新hashMap节点。

     1  int k;
     2     HashMap<String, Pair> hashMap;
     3     TreeMap<Pair, String> treeMap;
     4     public TopK(int k) {
     5         // initialize your data structure here
     6         this.k = k;
     7         hashMap = new HashMap<String, Pair>();
     8         treeMap = new TreeMap<Pair, String>();
     9     }
    10 
    11     public void add(String word) {
    12         // Write your code here
    13         if (!hashMap.containsKey(word)) {
    14             Pair pair = new Pair(word, 1);
    15             hashMap.put(word, pair);
    16             treeMap.put(pair, word);
    17             if (treeMap.size() > k) {
    18                 treeMap.pollFirstEntry();
    19             }
    20         } else {
    21             Pair oldPair = hashMap.get(word);
    22             treeMap.remove(oldPair);
    23             Pair newPair = new Pair(word, oldPair.times + 1);
    24             hashMap.put(word, newPair);
    25             treeMap.put(newPair, word);
    26             if (treeMap.size() > k) {
    27                 treeMap.pollFirstEntry();
    28             }
    29         }
    30     }
    31 
    32     public List<String> topk() {
    33         // Write your code here
    34         List<Pair> temp = new ArrayList<Pair>(treeMap.keySet());
    35         Collections.sort(temp);
    36         LinkedList<String> results = new LinkedList<String>();
    37         for (Pair pair : temp) {
    38             results.addFirst(pair.val);
    39         }
    40         return results;
    41     }
    42     
    43     class Pair implements Comparable<Pair> {
    44         String val;
    45         int times;
    46         public Pair(String val, int times) {
    47             this.val = val;
    48             this.times = times;
    49         }
    50         public int compareTo(Pair that) {
    51             if (this.times == that.times) {
    52                 return that.val.compareTo(this.val);
    53             } else {
    54                 return this.times - that.times;
    55             }
    56         }
    57     }
    View Code

    Anagrams

    注意字符数组转字符串是用的String.ValueOf(), 并不是toString.

    Given an array of strings, return all groups of strings that are anagrams.

    方法一:字符串排序之后作为键

     1 public List<String> anagrams(String[] strs) {
     2         // write your code here
     3         if (strs == null || strs.length < 2) {
     4             return new ArrayList<String> ();
     5         }
     6         HashMap<String, List<String>> hashMap = new HashMap<String, List<String>>();
     7         for (int i = 0; i < strs.length; i++) {
     8             char[] chars = strs[i].toCharArray();
     9             Arrays.sort(chars);
    10             String temp = String.valueOf(chars);
    11             if (!hashMap.containsKey(temp)) {
    12                 hashMap.put(temp, new ArrayList<String>());
    13             }
    14             hashMap.get(temp).add(strs[i]);
    15         }
    16         List<String> result = new ArrayList<String>();
    17         for (String str : hashMap.keySet()) {
    18             List<String> tmpList = hashMap.get(str);
    19             if (tmpList.size() > 1) {
    20                 for (String str1 : tmpList) {
    21                     result.add(str1);
    22                 }
    23             } 
    24         }
    25         return result;
    26     }
    View Code

     方法二:使用hash作为键

     1 public int getHash(int[] count) {
     2         int a = 378551;
     3         int b = 63689;
     4         int hash = 0;
     5         for (int tmp : count) {
     6             hash = hash * a + tmp;
     7             a = a * b;
     8         }
     9         return hash;
    10     }
    11     public List<String> anagrams(String[] strs) {
    12         // write your code here
    13         if (strs == null || strs.length == 0) {
    14             return new ArrayList<String>();
    15         }
    16         List<String> results = new ArrayList<String>();
    17         HashMap<Integer, List<String>> hashMap = new HashMap<Integer, List<String>>();
    18         for (int i = 0; i < strs.length; i++) {
    19             int[] count = new int[26];
    20             for (int j = 0; j < strs[i].length(); j++) {
    21                 count[strs[i].charAt(j) - 'a']++;
    22             }
    23             int hash = getHash(count);
    24             if (!hashMap.containsKey(hash)) {
    25                 hashMap.put(hash, new ArrayList<String>());
    26             }
    27             hashMap.get(hash).add(strs[i]);
    28         }
    29         for (Integer tmp : hashMap.keySet()) {
    30             if (hashMap.get(tmp).size() > 1) {
    31                 results.addAll(hashMap.get(tmp));
    32             }
    33         }
    34         return results;
    35     }
    View Code

    Longest Consecutive Sequence **

    主要是思路。

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence.

     1 public int longestConsecutive(int[] num) {
     2         // write you code here
     3         if (num == null || num.length == 0) {
     4             return 0;
     5         }
     6         int result = 0;
     7         HashSet<Integer> hashSet = new HashSet<Integer>();
     8         for (int i = 0; i < num.length; i++) {
     9             hashSet.add(num[i]);
    10         }
    11         for (int i = 0; i < num.length; i++) {
    12             int down = num[i] - 1;
    13             while (hashSet.contains(down)) {
    14                 hashSet.remove(down);
    15                 down--;
    16             }
    17             int up = num[i] + 1;
    18             while (hashSet.contains(up)) {
    19                 hashSet.remove(up);
    20                 up++;
    21             }
    22             result = Math.max(result, up - down - 1);
    23             if (result >= hashSet.size()) {
    24                 break;
    25             }
    26         }
    27         return result;
    28     }
    View Code

    Heapify***--not bug free

    之前思路错误[1,7,4,8,9,5,6],不要试图去交换已经处理好了的两个孩子,这会引发问题。

    Given an integer array, heapify it into a min-heap array.

    For a heap array A, A[0] is the root of heap, and for each A[i], A[i * 2 + 1] is the left child of A[i] and A[i * 2 + 2] is the right child of A[i].
     1 public void heapify(int[] A) {
     2         // write your code here
     3         if (A == null || A.length == 0) {
     4             return ;
     5         }
     6         for (int i = A.length / 2; i >= 0; i--) {
     7             siftDown(A, i);
     8         }
     9     }
    10     
    11     private void siftDown(int[] A, int k) {
    12         while (k < A.length) {
    13             int smallest = k;
    14             if (2 * k + 1 < A.length && A[2 * k + 1] < A[smallest]) {
    15                 smallest = 2 * k + 1;
    16             }
    17             if (2 * k + 2 < A.length && A[2 * k + 2] < A[smallest]) {
    18                 smallest = 2 * k + 2;
    19             }
    20             if (smallest == k) {
    21                 break ;
    22             } else {
    23                 swap(A, k, smallest);
    24                 k = smallest;
    25             }
    26         }
    27     }
    28     private void swap(int[] A, int i, int j) {
    29         int temp = A[i];
    30         A[i] = A[j];
    31         A[j] = temp;
    32     }
    View Code

    Ugly Number II --not bug free

    注意可能会出现 fact2, fact3, fact5不仅一个等于min的情况,这是相应的index都要增加,所以不能用else来分支判断。

    Ugly number is a number that only have factors 23 and 5.

    Design an algorithm to find the nth ugly number. The first 10 ugly numbers are 1, 2, 3, 4, 5, 6, 8, 9, 10, 12...

     1  public int nthUglyNumber(int n) {
     2         // Write your code here
     3         if (n <= 0) {
     4             return 0;
     5         }
     6         int[] uglys = new int[n];
     7         uglys[0] = 1;
     8         int index2 = 0;
     9         int index3 = 0;
    10         int index5 = 0;
    11         int fact2 = 2;
    12         int fact3 = 3;
    13         int fact5 = 5;
    14         for (int i = 1; i < n; i++) {
    15             int min = Math.min(fact2, Math.min(fact3, fact5));
    16             uglys[i] = min;
    17             if (min == fact2) {
    18                 fact2 = uglys[++index2] * 2;
    19             }
    20             if (min == fact3) {
    21                 fact3 = uglys[++index3] * 3;
    22             } 
    23             if (min == fact5) {
    24                 fact5 = uglys[++index5] * 5;
    25             }
    26         }
    27         return uglys[n - 1];
    28     }
    View Code

     

    Top k Largest Numbers --not bug free

    好几次都不能bug free。易错点:最后输出是从大到小;getPivo容易直接返回下标了。。;i <= j都要交换,不然导致死循环例如:54321,pivot选了1;quickSelect最后忘记递归的调用

    。。。。我这都是在干啥。。。。

    Given an integer array, find the top k largest numbers in it.

     1  public int[] topk(int[] nums, int k) {
     2         // Write your code here
     3         if (nums == null || nums.length == 0 || nums.length < k) {
     4             return new int[0];
     5         }
     6         quickSelect(nums, 0, nums.length - 1, k);
     7         // ArrayList<Integer> list = new ArrayList<Integer>();
     8         // for (int i = 0; i < k; i++) {
     9         //     list.add(nums[i]);
    10         // }
    11         // Collections.sort(list, Collections.reverseOrder());
    12         int[] result = new int[k];
    13         for (int i = 0; i < k; i++) {
    14             // result[i] = list.get(i);
    15             result[i] = nums[i];
    16         }
    17         return result;
    18     }
    19     
    20     private void quickSelect(int[] nums, int left, int right, int k) {
    21         if (left >= right) {
    22             return ;
    23         }
    24         int pivot = getPivot(nums, left, right);
    25         int i = left;
    26         int j = right;
    27         while (i <= j) {
    28             while (i <= j && nums[i] > pivot) {
    29                 i++;
    30             }
    31             while (i <= j && nums[j] < pivot) {
    32                 j--;
    33             }
    34             if (i <= j) {
    35                 swap(nums, i, j);
    36                 i++;
    37                 j--;
    38             }
    39         }
    40         if (k <= i) {
    41             quickSelect(nums, left, i - 1, k);
    42         } else {
    43             quickSelect(nums, left, i - 1, k);
    44             quickSelect(nums, i, right, k);
    45         }
    46     }
    47     
    48     private void swap(int[] nums, int i, int j) {
    49         int temp = nums[i];
    50         nums[i] = nums[j];
    51         nums[j] = temp;
    52     }
    53     
    54     private int getPivot(int[] nums, int left, int right) {
    55         Random random = new Random();
    56         int index = random.nextInt(right - left + 1);
    57         return nums[left + index];
    58     }
    View Code

    Top k Largest Numbers II --not bug free

    注意堆中只是保存了最大的k个数,而这些数并不是大小有序的。

    Implement a data structure, provide two interfaces:

    1. add(number). Add a new number in the data structure.
    2. topk(). Return the top k largest numbers in this data structure. k is given when we create the data structure.
     1 private int k;
     2     PriorityQueue<Integer> minHeap;
     3     
     4     public Solution(int k) {
     5         // initialize your data structure here.
     6         this.k = k;
     7         minHeap = new PriorityQueue<Integer>();
     8     }
     9 
    10     public void add(int num) {
    11         // Write your code here
    12         minHeap.offer(num);
    13         if (minHeap.size() > k) {  
    14             minHeap.poll();
    15         }
    16     }
    17     
    18     public List<Integer> topk() {
    19         // Write your code here
    20         List<Integer> result = new ArrayList<Integer>();
    21         result.addAll(minHeap);
    22         Collections.sort(result,  Collections.reverseOrder());
    23         return result;
    24     }
    View Code

    Merge k Sorted Arrays

    Given k sorted integer arrays, merge them into one sorted array.

    三种方法:

    分治

    Heap

    merge two by two

    merge list给出了三种方法,这里只实现一种。

     1  public List<Integer> mergekSortedArrays(int[][] arrays) {
     2         // Write your code here
     3         ArrayList<Integer> results = new ArrayList<Integer>();
     4         if (arrays == null || arrays.length == 0) {
     5             return results;
     6         }
     7         int m = arrays.length;
     8         int n = arrays[0].length;
     9         PriorityQueue<Element> minHeap = new PriorityQueue<Element>();
    10         for (int i = 0; i < m; i++) {
    11             if (arrays[i].length == 0) {
    12                 continue;
    13             }
    14             minHeap.offer(new Element(arrays[i][0], i, 0));
    15         }
    16         while (!minHeap.isEmpty()) {
    17             Element top = minHeap.poll();
    18             results.add(top.val);
    19             if (top.col + 1 < arrays[top.row].length) {
    20                 minHeap.add(new Element(arrays[top.row][top.col + 1], top.row, top.col + 1));
    21             }
    22         }
    23         return results;
    24     }
    25 }
    26 class Element implements Comparable<Element> {
    27     int val;
    28     int row;
    29     int col;
    30     public Element(int val, int row, int col) {
    31         this.val = val;
    32         this.row = row;
    33         this.col = col;
    34     }
    35     public int compareTo(Element eleB) {
    36         return val - eleB.val;
    37     }
    View Code

    Find Median from Data Stream ***

    主要是思路。大堆存较小的数,小堆存较大的数。保证大堆 size 大于等于小堆 size。

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

     1 PriorityQueue<Integer> maxHeap;
     2     PriorityQueue<Integer> minHeap;
     3     
     4     public MedianFinder() {
     5         maxHeap = new PriorityQueue<Integer>(Collections.reverseOrder());
     6         minHeap = new PriorityQueue<Integer>();
     7     }
     8 
     9     // Adds a number into the data structure.
    10     public void addNum(int num) {
    11         maxHeap.offer(num);
    12         minHeap.offer(maxHeap.poll());
    13         if (maxHeap.size() < minHeap.size()) {
    14             maxHeap.offer(minHeap.poll());
    15         }
    16     }
    17 
    18     // Returns the median of current data stream
    19     public double findMedian() {
    20         if (maxHeap.size() == 0) {
    21             return 0;
    22         }
    23         if (maxHeap.size() == minHeap.size()) {
    24             return (minHeap.peek() + maxHeap.peek()) * 0.5;
    25         } else {
    26             return maxHeap.peek();
    27         }
    28     }
    View Code

    Data Stream Median

    同上题,要求稍微不同,接口不同。

    Numbers keep coming, return the median of numbers at every time a new number added.

     1 public int[] medianII(int[] nums) {
     2         // write your code here
     3         if(nums == null || nums.length == 0) {
     4             return new int[0];
     5         }
     6         PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
     7         PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(nums.length, Collections.reverseOrder());//java 1.7
     8         int[] result = new int[nums.length];
     9         for (int i = 0; i < nums.length; i++) {
    10             maxHeap.offer(nums[i]);
    11             minHeap.offer(maxHeap.poll());
    12             if (maxHeap.size() < minHeap.size()) {
    13                 maxHeap.offer(minHeap.poll());
    14             }
    15             result[i] = maxHeap.peek();
    16         }
    17         return result;
    18     }
    View Code

    Kth Smallest Number in Sorted Matrix**

    Find the kth smallest number in at row and column sorted matrix.

     1 public int kthSmallest(int[][] matrix, int k) {
     2         // write your code here
     3         if (matrix == null || matrix[0].length == 0) {
     4             return -1;
     5         }
     6         int m = matrix.length;
     7         int n = matrix[0].length;
     8         PriorityQueue<Tuple> minHeap = new PriorityQueue<Tuple>();
     9         for (int j = 0; j < n; j++) {
    10             minHeap.offer(new Tuple(0, j, matrix[0][j]));
    11         }
    12         for (int i = 0; i < k - 1; i++) {
    13             if (minHeap.size() == 0) {
    14                 return -1;
    15             }
    16             Tuple temp = minHeap.poll();
    17             if (temp.x == m - 1) {
    18                 continue;
    19             } else {
    20                 minHeap.offer(new Tuple(temp.x + 1, temp.y, matrix[temp.x + 1][temp.y]));
    21             }
    22         }
    23         return minHeap.poll().val;
    24     }
    25     class Tuple implements Comparable<Tuple>{
    26         int x;
    27         int y;
    28         int val;
    29         public Tuple(int x, int y, int val) {
    30             this.x = x;
    31             this.y = y;
    32             this.val = val;
    33         }
    34         public int compareTo(Tuple that) {
    35             return this.val - that.val;
    36         }
    37     }
    View Code

    The Skyline Problem *****

    大楼轮廓问题。之前不会解这个问题,在老师提示使用TreeMap之后,看了一个使用PriorityQueue的解法之后,改为使用TreeMap,效率得到了很大的提高。

    解法思想:

    首先对于每一个building,都提取处其左上角点和右上角点,提取的单位为一个大小为二的数组,height[0]为横坐标, height[1]位纵坐标或者纵坐标的负,这取决于是左上角点还是右上角点,放到height中。

    然后根据横坐标的大小,对height进行排序。(横坐标相同的纵坐标小的排在前面 *1)

    遍历height数组,如果遇到左上角点,就把这个点加入TreeMap,如果遇到右上角点,就把这个点对应的左上角点从TreeMap中弹出。TreeMap 键为height单元的高度,值为这个高度出现的次数(相比于PQ,这里记录次数的原因是treeMap不允许重复键值)。

    使用变量key来记录之前的有效高度。每次弹出或者压入TreeMap之后,检测当前TreeMap的顶部(相当于最大堆,也就是最大高度)的高度,如果这个高度和prev不相等,往结果中加入一个新的点,更新prev。

    *1这里是很关键的,相同的横坐标,纵坐标小的排在前边,不然的话,前边大的弹出的时候会往结果写入一个新点,后边小的压入的时候也会往结果写入一个新点。而其实这里顶多引入一个新点的。

    *2之前对于以下这种情况还有点担心:[[1,2,2],[2,3,2]]

    其实有了之前的规则,这种情况也是能够正确处理的。首先第二个左边由于是负数,所以他们的横坐标相同,按照纵坐标小的原则来排序的话,(2,-2) 是排在 (2,2) 的前面的,没有任何问题。

     1 public List<int[]> getSkyline(int[][] buildings) {
     2         List<int[]> result = new ArrayList<int[]>();
     3         if (buildings == null || buildings.length == 0) {
     4             return result;
     5         }
     6         List<int[]> height = new ArrayList<int[]>();
     7         for (int i = 0; i < buildings.length; i++) {
     8             height.add(new int[] {buildings[i][0], -buildings[i][2]});
     9             height.add(new int[] {buildings[i][1], buildings[i][2]});
    10         }
    11         Collections.sort(height, new Comparator<int[]> () {
    12             public int compare(int[] a, int[] b) {
    13                 if (a[0] == b[0]) {
    14                     return a[1] - b[1];
    15                 } else {
    16                     return a[0] - b[0];
    17                 }
    18             }
    19         });
    20         TreeMap<Integer, Integer> treeMap = new TreeMap<Integer,Integer> (Collections.reverseOrder());
    21         int prev = 0;
    22         treeMap.put(0,1);
    23         for (int[] h : height) {
    24             if (h[1] < 0) {
    25                 Integer times = treeMap.get(-h[1]);
    26                 if (times == null) {
    27                      treeMap.put(-h[1], 1);
    28                 } else {
    29                     treeMap.put(-h[1], times + 1);
    30                 }
    31             } else {
    32                 Integer times = treeMap.get(h[1]);
    33                 if (times == 1) {
    34                     treeMap.remove(h[1]);
    35                 } else {
    36                     treeMap.put(h[1], times - 1);
    37                 }
    38             }
    39             int cur = treeMap.firstKey();
    40             if (cur != prev) {
    41                 result.add(new int[] {h[0], cur});
    42                 prev = cur;
    43             }
    44         }
    45         return result;
    46     }
    View Code

    Building Outline

    lintcode上相似的题目,只是最后徐亚返回的结果稍微不同。

    Given 3 buildings:

    [
      [1, 3, 3],
      [2, 4, 4],
      [5, 6, 1]
    ]

    The outlines are:

    [
      [1, 2, 3],
      [2, 4, 4],
      [5, 6, 1]
    ]

     1 public ArrayList<ArrayList<Integer>> buildingOutline(int[][] buildings) {
     2         // write your code here
     3         ArrayList<ArrayList<Integer>> result = new ArrayList<>();
     4         if (buildings == null || buildings.length == 0) {
     5             return result;
     6         }
     7         List<int[]> height = new ArrayList<int[]>();
     8         for (int i = 0; i < buildings.length; i++) {
     9             height.add(new int[] {buildings[i][0], -buildings[i][2]});
    10             height.add(new int[] {buildings[i][1], buildings[i][2]});
    11         }
    12         Collections.sort(height, new Comparator<int[]>() {
    13             public int compare(int[] a, int[] b) {
    14                 if (a[0] != b[0]) {
    15                     return a[0] - b[0];
    16                 } else {
    17                     return a[1] - b[1];
    18                 }
    19             }
    20         });
    21         List<int[]> points = new ArrayList<int[]>();
    22         int prev = 0;
    23         TreeMap<Integer, Integer> treeMap = new TreeMap<Integer, Integer>(
    24                 Collections.reverseOrder()
    25             );
    26         treeMap.put(0,1);
    27         for (int[] h : height) {
    28             if (h[1] < 0) {
    29                 Integer times = treeMap.get(-h[1]);
    30                 if (times == null) {
    31                     treeMap.put(-h[1], 1);
    32                 } else {
    33                     treeMap.put(-h[1], times + 1);
    34                 }
    35             } else {
    36                 Integer times = treeMap.get(h[1]);
    37                 if (times == 1) {
    38                     treeMap.remove(h[1]);
    39                 } else {
    40                     treeMap.put(h[1], times - 1);
    41                 }
    42             }
    43             int cur = treeMap.firstKey();
    44             if (cur != prev) {
    45                points.add(new int[]{h[0], cur});
    46                prev = cur;
    47             }
    48         }
    49         for (int i = 0; i < points.size() - 1; i++) {
    50             if (points.get(i)[1] != 0) {
    51                 ArrayList<Integer> list = new ArrayList<Integer>();
    52                 list.add(points.get(i)[0]);
    53                 list.add(points.get(i + 1)[0]);
    54                 list.add(points.get(i)[1]);
    55                 result.add(list);
    56             }
    57         }
    58         return result;
    59     }
    View Code

    H-Index ***

    https://leetcode.com/problems/h-index/

    这个题还是有些绕的,主要是题意搞得有点晕了。最后题意应该是:h 为 h篇文章的引用至少为h,其余N-h篇文章的引用至多为h。(另外一种错误的理解是引用大于h的至少h篇)

    方法一:hashtable

    新建一个数组来存储每个引用分别有多少篇文章,由于h最多为文章总数len,所以对于那些引用大于文章总数len的,就把这些文章也加载引用为len次的元素位置。然后从这个数组末尾开始遍历。

    使用一个tmp来存储文章数目,遍历到cur,首先更新tmp,表示引用大于等于cur的文章共有tmp篇。如果tmp>=cur,则可以返回cur.

     1 class Solution(object):
     2     def hIndex(self, citations):
     3         """
     4         :type citations: List[int]
     5         :rtype: int
     6         """
     7         if not citations:
     8             return 0
     9         length = len(citations)
    10         articleNum = [0]*(length + 1)
    11         for i in range(length):
    12             if citations[i] >= length:
    13                 articleNum[length] += 1
    14             else:
    15                 articleNum[citations[i]] += 1
    16         tmp = 0
    17         for i in range(length, -1, -1):
    18             tmp += articleNum[i]
    19             if tmp >= i:
    20                 return i
    21         return 0
    View Code

    方法二:sort

    首先对原数组按升序排序,然后二分寻找。我们的目标是尽量往前走,length-cur为h因子。对于位置cur,可知引用大于等于cur的共有length-cur篇,如果citations[mid] ==length - cur,那么h=length-cur,因为你无法再往前走了(citations缩小而文章数增大);如果citations[mid] < length - cur,表明mid这个位置已经不满足条件了;citations[mid]>length-cur,表明还可以继续往前走,多增加几篇文章,增大h。

     1 def hIndex(self, citations):
     2         """
     3         :type citations: List[int]
     4         :rtype: int
     5         """
     6         if not citations:
     7             return 0
     8         citations.sort()
     9         length = len(citations)
    10         start = 0
    11         end = length - 1
    12         while start + 1 < end:
    13             mid = (start + end) / 2
    14             if citations[mid] == length - mid:
    15                 return length - mid
    16             elif citations[mid] < length - mid:
    17                 start = mid
    18             else :
    19                 end = mid
    20         if citations[start] >= length - start:
    21             return length - start
    22         elif citations[end] >= length - end:
    23             return length - end
    24         else:
    25             return 0
    View Code

    GFS Client

    Implement a simple client for GFS (Google File System, a distributed file system), it provides the following methods:

    1. read(filename). Read the file with given filename from GFS.
    2. write(filename, content). Write a file with given filename & content to GFS.

    There are two private methods that already implemented in the base class:

    1. readChunk(filename, chunkIndex). Read a chunk from GFS.
    2. writeChunk(filename, chunkIndex, chunkData). Write a chunk to GFS.

    To simplify this question, we can assume that the chunk size is chunkSizebytes. (In a real world system, it is 64M). The GFS Client's job is splitting a file into multiple chunks (if need) and save to the remote GFS server.chunkSize will be given in the constructor. You need to call these two private methods to implement read & write methods.

     1  int chunkSize;
     2     HashMap<String, Integer> chunkNum;
     3     public GFSClient(int chunkSize) {
     4         // initialize your data structure here
     5         this.chunkSize = chunkSize;
     6         chunkNum = new HashMap<String, Integer>();
     7     }
     8     
     9     // @param filename a file name
    10     // @return conetent of the file given from GFS
    11     public String read(String filename) {
    12         // Write your code here
    13         if (!chunkNum.containsKey(filename)) {
    14             return null;
    15         }
    16         int num = chunkNum.get(filename);
    17         StringBuilder sb = new StringBuilder();
    18         for (int i = 0; i < num; i++) {
    19             sb.append(readChunk(filename, i));
    20         }
    21         return sb.toString();
    22     }
    23 
    24     // @param filename a file name
    25     // @param content a string
    26     // @return void
    27     public void write(String filename, String content) {
    28         // Write your code here
    29         int length = content.length();
    30         int num = (length - 1) / chunkSize + 1;
    31         chunkNum.put(filename, num);
    32         for (int i = 0; i < num; i++) {
    33             int start = i * chunkSize;
    34             int end = i == num - 1 ? length : (i + 1) * chunkSize;
    35             String chunk = content.substring(start, end);
    36             writeChunk(filename, i, chunk);
    37         }
    38     }
    View Code

    132 Pattern --not bug free***

    Given a sequence of n integers a1, a2, ..., an, a 132 pattern is a subsequence ai, aj, ak such that i < j < k and ai < ak < aj. Design an algorithm that takes a list of n numbers as input and checks whether there is a 132 pattern in the list.

    方法一:检测每一个打头的是否满足。每一个的时候保留最大的大于它的。O(n^2)

     1  public boolean find132pattern(int[] nums) {
     2         if (nums == null || nums.length == 0) {
     3             return false;
     4         }
     5         int n = nums.length;
     6         int min = nums[0];
     7         for (int i = 0; i < n - 2; i++) {
     8             min = nums[i];
     9             int max = Integer.MIN_VALUE;
    10             for (int j = i + 1; j < n; j++) {
    11                 if (nums[j] > max) {
    12                     max = nums[j];
    13                 }
    14                 if (nums[j] < max && nums[j] > min) {
    15                     return true;
    16                 }
    17             }
    18         }
    19         return false;
    20     }
    View Code

    方法二:使用栈,记录最小最大区间。

    画出一个图来就会比较好分析。

    算法更新规则:

    遍历数组,栈为空或者栈顶元素最小值大于新来的数的时候,压入栈。

          新来元素素等于栈顶最小值不做任何操作

          新来元素大于栈顶最小值,表明栈顶这个区间有机会了。看看新来的数是否小于栈顶最大值,如果是的,表明满足条件。如果新来的数大于等于栈顶最大值,此时画出图来就很明白,后面大的区间有可能有                  满足条件的区间。弹出栈中元素如果栈不为空并且新来的数大于大于栈顶最大值。不用担心这些被弹出的区间带来什么问题,因为后边要压入一个大区间就包含了这些小区间。弹出完成之后检测如果新来的                  数大于栈顶数的最小值则满足条件。最后把新来的数当最大值,最开始弹出的最小值为最小值压入栈。

     1 public boolean find132pattern(int[] nums) {
     2         if (nums == null || nums.length < 3) {
     3             return false;
     4         }
     5         Stack<Pair> stack = new Stack<Pair>();
     6         for (int i = 0; i < nums.length; i++) {
     7             if (stack.isEmpty() || nums[i] < stack.peek().min) {
     8                 stack.push(new Pair(nums[i], nums[i]));
     9             } else if (stack.peek().min == nums[i]) {
    10                 continue;
    11             } else {
    12                 Pair top = stack.pop();
    13                 if (nums[i] < top.max) {
    14                     return true;
    15                 } else {
    16                     while (!stack.isEmpty() && stack.peek().max < nums[i]) {
    17                         stack.pop();
    18                     }
    19                     if (!stack.isEmpty() && stack.peek().min < nums[i]) {
    20                         return true;
    21                     }
    22                     top.max = nums[i];
    23                     stack.push(top);
    24                 }
    25             }
    26         }
    27         return false;
    28     }
    29     class Pair {
    30         int min;
    31         int max;
    32         public Pair(int min, int max) {
    33             this.min = min;
    34             this.max = max;
    35         }
    36     }
    View Code
  • 相关阅读:
    C#多线程编程之:集合类中Synchronized方法与SyncRoot属性原理分析
    Newtonsoft.Json 序列化和反序列化 以及时间格式 2 高级使用
    C++:基类和派生类
    C++:友元(非成员友元函数、成员友元函数、友元类)
    C++:静态成员
    C++:向函数传递对象(对象、对象指针、对象引用)
    C++:常类型Const
    C++:对象的赋值和复制
    C++:类的组合
    C++:析构函数
  • 原文地址:https://www.cnblogs.com/futurehau/p/5878322.html
Copyright © 2011-2022 走看看