接水问题
Container With Most Water
Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
两个指针问题。需要计算的是两条线之间的最大面积。使用两个指针,先结算小的那边,因为这边此时的高度成为了下界,不移动这边的话,其他任何情况都会有此下界而且长度变短。
1 public int maxArea(int[] height) { 2 if (height == null || height.length < 2) { 3 return 0; 4 } 5 int left = 0; 6 int right = height.length - 1; 7 int res = 0; 8 while (left < right) { 9 if (height[left] < height[right]) { 10 res = Math.max(res, height[left] * (right - left)); 11 left++; 12 } else { 13 res = Math.max(res, height[right] * (right - left)); 14 right--; 15 } 16 } 17 return res; 18 }
Trapping Rain Water
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
一共可以接多少水。首先找到一个最大作为保障。然后分别计算左边和右边。分槽位计算每个槽位可以放多少水
1 public int trap(int[] height) { 2 if(height==null||height.length<3) 3 return 0; 4 int max=0,maxIndex=0; 5 for(int i=0;i<height.length;i++){ 6 if(height[i]>max) 7 { 8 max=height[i]; 9 maxIndex=i; 10 } 11 } 12 int area=0; 13 int left=0; 14 for(int i=0;i<maxIndex;i++){ 15 if(height[i]<height[left]){ 16 area+=height[left]-height[i]; 17 } 18 else 19 left=i; 20 } 21 int right=height.length-1; 22 for(int i=height.length-1;i>maxIndex;i--){ 23 if(height[i]<height[right]) 24 area+=height[right]-height[i]; 25 else 26 right=i; 27 } 28 return area; 29 }
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[] heights) { 2 if (heights == null || heights.length == 0) { 3 return 0; 4 } 5 Stack<Integer> stack = new Stack<Integer>(); 6 int res = 0; 7 for (int i = 0; i <= heights.length; i++) { 8 int cur = i == heights.length ? -1 : heights[i]; 9 while (!stack.isEmpty() && heights[stack.peek()] > cur) { 10 int height = heights[stack.pop()]; 11 res = Math.max(res, (i - (stack.isEmpty() ? -1 : stack.peek()) - 1) * height); 12 } 13 stack.push(i); 14 } 15 return res; 16 }
方法二:
DP。分别求出每个位置往左边可以扩张的最大位置和往右边可以扩张的最大位置。
1 public int largestRectangleArea(int[] heights) { 2 if (heights == null || heights.length == 0) { 3 return 0; 4 } 5 int n = heights.length; 6 int[] left = new int[n]; // left[i]表示当前高度扩张的最左边 7 int[] right = new int[n]; // right[i]表示当前高度扩展的最右边 8 right[n - 1] = n - 1; 9 for (int i = n - 2; i >= 0; i--) { 10 int j = i + 1; 11 while (j < n && heights[j] >= heights[i]) { 12 j = right[j] + 1; 13 } 14 right[i] = j - 1; 15 } 16 int res = 0; 17 for (int i = 0; i < n; i++) { 18 int j = i - 1; 19 while (j >= 0 && heights[j] >= heights[i]) { 20 j = left[j] - 1; 21 } 22 left[i] = j + 1; 23 res = Math.max(res, heights[i] * (right[i] - left[i] + 1)); // 一边扩张,一边结算 24 } 25 return res; 26 }
删除重复元素问题
Remove Element
删除所有等于val的元素。
public int removeElement(int[] nums, int val) { if(nums.length<1) return nums.length; int pos=0; for(int i=0;i<nums.length;i++){ if(nums[i]!=val){ nums[pos++]=nums[i]; } } return pos; }
Remove Linked List Elements
删除链表中值等于val的节点。
注意最后tail的next需要指向null
1 public ListNode removeElements(ListNode head, int val) { 2 if (head == null) { 3 return head; 4 } 5 ListNode dummy = new ListNode(0); 6 ListNode tail = dummy; 7 while (head != null) { 8 if (head.val == val) { 9 head = head.next; 10 } else { 11 tail.next = head; 12 tail = head; 13 head = head.next; 14 } 15 } 16 tail.next = null; // Attention 17 return dummy.next; 18 }
Remove Duplicates from Sorted Array
删除重复元素,只保留一个。
public int removeDuplicates(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int left = 0; int i = 0; while (i < nums.length) { if (nums[i] == nums[left]) { i++; } else { nums[++left] = nums[i++]; } } return left + 1; }
Remove Duplicates from Sorted Array II --not bug free
删除重复元素,最多保留两个。
pos记录一个新数位置,后边的如果等于nums[pos]就把times++,如果times == 2, 加一个进来,再多的话则不在处理。新来的数不等于nums[pos]的话,pos后边移动一位并放数。
public int removeDuplicates(int[] nums) { if (nums == null) { return 0; } if (nums.length < 3) { return nums.length; } int n = nums.length; int pos = 0; int times = 1; for (int i = 1; i < n; i++) { if (nums[i] == nums[pos]) { times++; if (times == 2) { nums[++pos] = nums[i]; } } else { nums[++pos] = nums[i]; times = 1; } } return pos + 1; }
Remove Duplicates from Sorted List
删除排序链表重复元素,保留一个。
1 public ListNode deleteDuplicates(ListNode head) { 2 if (head == null || head.next == null) { 3 return head; 4 } 5 ListNode cur = head; 6 while (cur.next != null) { 7 if (cur.val == cur.next.val) { 8 cur.next = cur.next.next; 9 } else { 10 cur = cur.next; 11 } 12 } 13 return head; 14 }
Remove Duplicates from Sorted List II--not bug free
删除排序链表重复元素,所有都删除。
1 public ListNode deleteDuplicates(ListNode head) { 2 if (head == null || head.next == null) { 3 return head; 4 } 5 ListNode dummy = new ListNode(0); 6 dummy.next = head; 7 ListNode tail = dummy; 8 while (head != null) { 9 while (head.next != null && head.val == head.next.val) { 10 head = head.next; 11 } 12 if (tail.next == head) { 13 tail = tail.next; 14 head = head.next; 15 } else { 16 head = head.next; 17 tail.next = head; 18 } 19 } 20 return dummy.next; 21 }
两种缓存方法
LRU Cache****--not bug free
get的时候忘记检测是否包含在map中了。
近期最少使用页面置换算法
方法一:HashMap + DoublyLinkedList
使用hashMap来记录一个页面是否出现过。如果只有get和set功能,那么这一个map就够用了,但是现在的问题是还需要在到达cache size的时候弹出最老的那一个,那么这怎么办呢?一种想法是直接记录一个LinkedList就行了嘛,每次删除list头部的那个,对应的删除map中的键值对。但是还有一个问题是假如缓存中已经存在了的页面又来了呢?这时候就需要从原始链表中把这个页面删除,但是问题来了,删除结点的前后两个结点是需要连接起来的,所以考虑到这一点,需要使用一个双向链表。
1 private int capacity; 2 private int size; 3 HashMap<Integer, Node> hashMap; 4 Node dummyEnd; 5 Node dummyHead; 6 7 public LRUCache(int capacity) { 8 this.capacity = capacity; 9 this.size = 0; 10 hashMap = new HashMap<Integer, Node>(); 11 // 新来节点加到dummyHead之后,最老节点是dummyEnd前一个节点 12 dummyHead = new Node(0, 0); 13 dummyEnd = new Node(0, 0); 14 dummyHead.next = dummyEnd; 15 dummyEnd.prev = dummyHead; 16 } 17 18 public int get(int key) { 19 if (hashMap.containsKey(key)) { 20 set(key, hashMap.get(key).val); 21 return hashMap.get(key).val; 22 } else { 23 return -1; 24 } 25 } 26 27 public void set(int key, int value) { 28 if (hashMap.containsKey(key)) { 29 Node cur = hashMap.get(key); 30 cur.prev.next = cur.next; 31 cur.next.prev = cur.prev; 32 } else if (size == capacity) { 33 Node end = dummyEnd.prev; 34 end.prev.next = dummyEnd; 35 dummyEnd.prev = end.prev; 36 hashMap.remove(end.key); 37 } else { 38 size++; 39 } 40 Node newNode = new Node(key, value); 41 hashMap.put(key, newNode); 42 newNode.next = dummyHead.next; 43 dummyHead.next.prev = newNode; 44 dummyHead.next = newNode; 45 newNode.prev = dummyHead; 46 } 47 class Node { 48 int key; 49 int val; 50 Node next; 51 Node prev; 52 public Node(int key, int val) { 53 this.key = key; 54 this.val = val; 55 } 56 }
方法二:Java库中的LinkedHashMap可以其实就是基于hashMap和双向链表实现的,可以完美实现上述功能。
private int capacity; private LinkedHashMap<Integer, Integer> linkedHashMap; public LRUCache(int capacity) { this.capacity = capacity; // true表示对于map中已经存在了的key,要不要更新为最开始 linkedHashMap = new LinkedHashMap<Integer, Integer>(capacity, (float)0.75, true) { protected boolean removeEldestEntry(Map.Entry eldest) { // 重写这个方法,超过缓存大小的时候,就会删除最老的页面 return size() > capacity; } }; } public int get(int key) { Integer value = linkedHashMap.get(key); return value == null ? -1 : value; } public void set(int key, int value) { if (capacity == 0) { return; } linkedHashMap.put(key, value); }
LFU Cache****
最近最不常使用页面置换算法。
方法一:PriorityQueue get O(capacity) set O(capacity)
long stamp; int capacity; int num; PriorityQueue<Pair> minHeap; HashMap<Integer, Pair> hashMap; // @param capacity, an integer public LFUCache(int capacity) { // Write your code here this.capacity = capacity; num = 0; minHeap = new PriorityQueue<Pair>(); hashMap = new HashMap<Integer, Pair>(); stamp = 0; } // @param key, an integer // @param value, an integer // @return nothing public void set(int key, int value) { if (capacity == 0) { return; } // Write your code here if (hashMap.containsKey(key)) { Pair old = hashMap.get(key); minHeap.remove(old); Pair newNode = new Pair(key, value, old.times + 1, stamp++); hashMap.put(key, newNode); minHeap.offer(newNode); } else if (num == capacity) { Pair old = minHeap.poll(); hashMap.remove(old.key); Pair newNode = new Pair(key, value, 1, stamp++); hashMap.put(key, newNode); minHeap.offer(newNode); } else { num++; Pair pair = new Pair(key, value, 1, stamp++); hashMap.put(key, pair); minHeap.offer(pair); } } public int get(int key) { if (capacity == 0) { return -1; } // Write your code here if (hashMap.containsKey(key)) { Pair old = hashMap.get(key); minHeap.remove(old); Pair newNode = new Pair(key, old.value, old.times + 1, stamp++); hashMap.put(key, newNode); minHeap.offer(newNode); return hashMap.get(key).value; } else { return -1; } } class Pair implements Comparable<Pair> { long stamp; int key; int value; int times; public Pair(int key, int value, int times, long stamp) { this.key = key; this.value = value; this.times = times; this.stamp = stamp; } public int compareTo(Pair that) { if (this.times == that.times) { return (int)(this.stamp - that.stamp); } else { return this.times - that.times; } } }
方法二:HashMap + TreeMap get O(log (capacity)) set O(log(capacity))
1 private int capacity; 2 private int stamp; 3 private HashMap<Integer, Tuple> hashMap; 4 private TreeMap<Tuple, Integer> treeMap; 5 public LFUCache(int capacity) { 6 this.capacity = capacity; 7 stamp = 0; 8 hashMap = new HashMap<Integer, Tuple>(); 9 treeMap = new TreeMap<Tuple, Integer>(new Comparator<Tuple>() { 10 public int compare(Tuple t1, Tuple t2) { 11 if (t1.times == t2.times) { 12 return t1.stamp - t2.stamp; 13 } 14 return t1.times - t2.times; 15 } 16 }); 17 } 18 19 public int get(int key) { 20 if (capacity == 0) { 21 return -1; 22 } 23 if (!hashMap.containsKey(key)) { 24 return -1; 25 } 26 Tuple old = hashMap.get(key); 27 treeMap.remove(old); 28 Tuple newTuple = new Tuple(old.value, stamp++, old.times + 1); 29 treeMap.put(newTuple, key); 30 hashMap.put(key, newTuple); 31 return old.value; 32 } 33 34 public void set(int key, int value) { 35 if (capacity == 0) { 36 return; 37 } 38 if (hashMap.containsKey(key)) { 39 Tuple old = hashMap.get(key); 40 Tuple newTuple = new Tuple(value, stamp++, old.times + 1); 41 treeMap.remove(old); 42 hashMap.put(key, newTuple); 43 treeMap.put(newTuple, key); 44 } else { 45 if (treeMap.size() == capacity) { 46 int endKey = treeMap.pollFirstEntry().getValue(); 47 hashMap.remove(endKey); 48 } 49 Tuple newTuple = new Tuple(value, stamp++, 1); 50 hashMap.put(key, newTuple); 51 treeMap.put(newTuple, key); 52 } 53 } 54 class Tuple { 55 int value; 56 int times; 57 int stamp; 58 public Tuple (int value, int stamp, int times) { 59 this.value = value; 60 this.stamp = stamp; 61 this.times = times; 62 } 63 }
方法三:HashMap + HashMap + DoublyLinkedList **** --not bug free
使用一个map来记录出现过的节点,一个map来记录出现过key次的最后一个节点。
1 private int capacity; 2 private int count; 3 private HashMap<Integer, Tuple> map1; // whether appeared 4 private HashMap<Integer, Tuple> finalNodes; // value : the final node of key times 5 private Tuple dummyHead; 6 private Tuple dummyEnd; 7 8 public LFUCache(int capacity) { 9 this.capacity = capacity; 10 count = 0; 11 map1 = new HashMap<Integer, Tuple>(); 12 finalNodes = new HashMap<>(); 13 dummyHead = new Tuple(0, 0, 0); 14 dummyEnd = new Tuple(0, 0, 0); 15 dummyHead.next = dummyEnd; 16 dummyEnd.prev = dummyHead; 17 } 18 19 public int get(int key) { 20 if (capacity == 0 || !map1.containsKey(key)) { 21 return -1; 22 } 23 Tuple old = map1.get(key); 24 set(key, old.value); 25 return old.value; 26 } 27 28 public void set(int key, int value) { 29 if (capacity == 0) { 30 return; 31 } 32 if (map1.containsKey(key)) { // this key has appeared 33 Tuple cur = map1.get(key); 34 if (finalNodes.get(cur.times) == cur && finalNodes.get(cur.times + 1) == null) { // the position should not change 35 finalNodes.put(cur.times, cur.prev.times == cur.times ? cur.prev : null); 36 cur.times++; 37 cur.value = value; 38 finalNodes.put(cur.times, cur); 39 return; 40 } 41 removeNode(cur); // remove node cur 42 if (finalNodes.get(cur.times) == cur) { 43 finalNodes.put(cur.times, cur.prev.times == cur.times ? cur.prev : null); 44 } 45 cur.times++; 46 cur.value = value; 47 Tuple finalNode = finalNodes.get(cur.times) == null ? finalNodes.get(cur.times - 1) : finalNodes.get(cur.times); 48 insertNode(finalNode, cur); 49 finalNodes.put(cur.times, cur); // cur is the final node whitch appeared cur.times 50 } else if (count == capacity) { // reach limt of the cache 51 Tuple head = dummyHead.next; 52 removeNode(head); //remove the first which appeared least times and is the least Used 53 map1.remove(head.key); 54 if (finalNodes.get(head.times) == head) { 55 finalNodes.remove(head.times); 56 } 57 Tuple cur = new Tuple(key, value, 1); 58 if (finalNodes.get(1) == null) { 59 insertNode(dummyHead, cur); 60 } else { 61 Tuple finalNode = finalNodes.get(1); 62 insertNode(finalNode, cur); 63 } 64 finalNodes.put(1, cur); 65 map1.put(key, cur); 66 } else { 67 count++; 68 Tuple cur = new Tuple(key, value, 1); 69 if (finalNodes.get(1) == null){ 70 insertNode(dummyHead, cur); 71 } else { 72 Tuple finalNode = finalNodes.get(1); 73 insertNode(finalNode, cur); 74 } 75 finalNodes.put(1, cur); 76 map1.put(key, cur); 77 } 78 } 79 80 public void insertNode(Tuple t1, Tuple t2) { 81 t2.next = t1.next; 82 t1.next.prev = t2; 83 t1.next = t2; 84 t2.prev = t1; 85 } 86 87 public void removeNode(Tuple node) { 88 node.next.prev = node.prev; 89 node.prev.next = node.next; 90 } 91 class Tuple { 92 int key; 93 int value; 94 int times; 95 Tuple prev; 96 Tuple next; 97 public Tuple(int key, int value, int times) { 98 this.key = key; 99 this.value = value; 100 this.times = times; 101 } 102 }