3.雙端隊列html
There is an integer matrix which has the following features:java
The numbers in adjacent positions are different.
The matrix has n rows and m columns.
For all i < m, A[0][i] < A[1][i] && A[n – 2][i] > A[n – 1][i].
For all j < n, A[j][0] < A[j][1] && A[j][m – 2] > A[j][m – 1].
We define a position P is a peek if:c++
A[j][i] > A[j+1][i] && A[j][i] > A[j-1][i] && A[j][i] > A[j][i+1] && A[j][i] > A[j][i-1]
Find a peak element in this matrix. Return the index of the peak.git
Noticegithub
The matrix may contains multiple peeks, find any of them.面試
Have you met this question in a real interview? Yes
Example
Given a matrix:算法
[
[1 ,2 ,3 ,6 ,5],
[16,41,23,22,6],
[15,17,24,21,7],
[14,18,19,20,10],
[13,14,11,10,9]
]
return index of 41 (which is [1,1]) or index of 24 (which is [2,2])windows
這道題我想到的是隨便找個位置當起點,而後往高處爬.
我開始以爲這種算法的時間複雜度爲m+n, 後來以爲本身有點腦殘...
這種作法最壞狀況下的時間複雜度爲0(n^2).
狀況以下:數組
XXXXXXXXXXXXXXXXXXXXXXXXXXXXX X 1 2 3 4 5 6 7 8 9 10 11XXXX X 19 18 17 16 15 14 13 12XXXX X 20 21 22 23 24 25 26 27XXXX ......
呈蛇形排列的狀況.數據結構
而後呢咱們想一想能不能相似於find peak I 裏面的二分去掉一半?
咱們首先改一下栗子...改爲以下,方便理解:
[ 1, 2, 3, 6, 5], [16, 41, 23, 22, 6], [15, 17, 16, 21, 7], [14, 18, 19, 20, 10], [13, 14, 11, 10, 9]
咱們先假設取中間的一行:
[15, 17, 16, 21, 7]
中間一行有兩個極大值:17和21, 咱們目標是:看看找到極值,而後極值往高了爬,能不能甩掉身後小的那半邊矩陣, 並保證在剩下的通常裏仍然有要找的答案.
假設咱們先選擇17,而後上下找比它大的,意圖刪掉帶有17的那半邊:
若是走到41,是ok的...
可是若是走到18呢,18->19->20->21,又走回原來的第3行了...阿西吧,行不通.
而後咱們試試看看最大值,21呢?由於21是第三行的最大值, 因此咱們若是找個一個比21大的, 就是第二行第四列的22. 咱們發現, 若是從21走到22, 在從22找比它大的往高爬, 永遠都不會爬回21所在的第三行, 因此我成功甩掉了第四五行…下面咱們來肯定在剩下的一半里面, 必定有咱們要找的答案:
題目中的條件:
For all i < m, A[0][i] < A[1][i] && A[n – 2][i] > A[n – 1][i].
For all j < n, A[j][0] < A[j][1] && A[j][m – 2] > A[j][m – 1].
能夠保證四周的一圈是山腳,比中間的要小, 這樣才能肯定中間必定有個極值峯, 如pic4.1圖左, 當刪掉21所在的第三行下面的第四五行, 圖變成了pic4.1的右圖形式,保證了峯值依然存在:
class Solution { /** * @param A: An integer matrix * @return: The index of the peak */ public List find(int x1, int x2, int y1, int y2, int[][] A, boolean flag) { if (flag) { int mid = x1 + (x2 - x1) / 2; int index = y1; for (int i = y1; i A[mid][index]) index = i; if (A[mid - 1][index] > A[mid][index]) return find(x1, mid - 1, y1, y2, A, !flag); else if (A[mid + 1][index] > A[mid][index]) return find(mid + 1, x2, y1, y2, A, !flag); else return new ArrayList(Arrays.asList(mid, index)); } else { int mid = y1 + (y2 - y1) / 2; int index = x1; for (int i = x1; i A[index][mid]) index = i; if (A[index][mid - 1] > A[index][mid]) return find(x1, x2, y1, mid - 1, A, !flag); else if (A[index][mid + 1] > A[index][mid]) return find(x1, x2, mid + 1, y2, A, !flag); else return new ArrayList(Arrays.asList(index, mid)); } } public List findPeakII(int[][] A) { // write your code here int n = A.length; int m = A[0].length; return find(1, n - 2, 1, m - 2, A, true); } }
這道題的時間複雜度是:
T(n) = O(n) + O(n/2) + T(n/2)
最後的時間仍是O(3n), 即爲O(n).
每每沒有給你一個數組讓你二分, 而是找到知足某個條件的最大或者最小值
由於找答案有兩種思路:
而神馬是有二分性呢:
就是一個區間, 中間某個點畫條線, 線一邊的所有知足條件, 另外一邊的所有不知足:
-> 知足 ->| |____________|____________|
經過猜值判斷是否知足題意不對去搜索可能解
模板以下:
Implement int sqrt(int x).
Compute and return the square root of x.
Have you met this question in a real interview? Yes
Example
sqrt(3) = 1
sqrt(4) = 2
sqrt(5) = 2
sqrt(10) = 3
class Solution { /** * @param x: An integer * @return: The sqrt of x */ public int sqrt(int x) { // find the last number which square of it <= x long start = 1, end = x; while (start + 1 < end) { long mid = start + (end - start) / 2; if (mid * mid <= x) { start = mid; } else { end = mid; } } if (end * end <= x) { return (int) end; } return (int) start; } }
Implement double sqrt(double x) and x >= 0.
Compute and return the square root of x.
Notice
You do not care about the accuracy of the result, we will help you to output results.
Have you met this question in a real interview? Yes
Example
Given n = 2 return 1.41421356
這道題有個浮點精度問題, 在計算機裏面, 兩個樹若是不相等,可是由於精度問題, 計算機會判斷他們相等. 計算機如何判斷兩個浮點數y和z相等呢?
if (y ==z) 對於計算機來講是 if (abs(y-z)<eps), 這個eps是計算機設定的很小的值. 那麼對於計算機來講:
y = 1.0
z = 1.000000000000000000000000000001
是相等的, 雖然他們原本是不相等的.
這道題的eps腫麼肯定呢?
答案就是: 和麪試官商量…
public class Solution { /** * @param x a double * @return the square root of x */ public double sqrt(double x) { // Write your code here double left = 0.0; double right = x; double eps = 1e-12; if(right eps) { // 二分浮點數 和二分整數不一樣 // 通常都有一個精度的要求 譬如這題就是要求小數點後八位 // 也就是隻要咱們二分的結果達到了這個精度的要求就能夠 // 因此 須要讓 right 和 left 小於一個咱們事先設定好的精度值 eps // 通常eps的設定1e-8,由於這題的要求是到1e-8,因此我把精度調到了1e-12 // 最後 選擇 left 或 right 做爲一個結果便可 double mid = (right + left) / 2; if(mid * mid < x) { left = mid; } else { right = mid; } } return left; } }
Given n pieces of wood with length L[i] (integer array). Cut them into small pieces to guarantee you could have equal or more than k pieces with the same length. What is the longest length you can get from the n pieces of wood? Given L & k, return the maximum length of the small pieces.
Notice
You couldn’t cut wood into float length.
If you couldn’t get >= k pieces, return 0.
Have you met this question in a real interview? Yes
Example
For L=[232, 124, 456], k=7, return 114.
這道題能夠用heap來作, 同時呢, 也能夠二分試答案:
public class Solution { /** *@param L: Given n pieces of wood with length L[i] *@param k: An integer *return: The maximum length of the small pieces. */ public int woodCut(int[] L, int k) { int max = 0; for (int i = 0; i = k) { return end; } if (count(L, start) >= k) { return start; } return 0; } private int count(int[] L, int length) { int sum = 0; for (int i = 0; i < L.length; i++) { sum += L[i] / length; } return sum; } }
這道題若是範圍是[1, INT_MAX]的話, 最多咱們能找多少次呢?
就是log(max -min)次. 那麼這個數大約是多大呢?
31, 由於int是四個byte,就是最多32位, 32位的最大的整數是2^31-1
,因此須要找log(2^31-1-1)次, 就是大約31次. 那麼時間複雜度是多少呢?
log(max-min) * O(n)
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Notice
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than O(n^2).
There is only one duplicate number in the array, but it could be repeated more than once.
Have you met this question in a real interview? Yes
Example
Given nums = [5,5,4,3,2,1] return 5
Given nums = [5,4,4,3,2,1] return 4
由於一共有n+1個數,因此若是一個一個找的話,對於
[5,5,4,3,2,1] 來講呢?咱們一個一個試:
1的時候 小於等於1的 1個 2的時候 小於等於2的 2個 3的時候 小於等於3的 3個 4的時候 小於等於4的 4個 5的時候 小於等於5的 6個
咱們發現, 對於數字n來講,若是小於等於它的數字個數小於等於n, 那麼它和它以前木有重複的. 反之有重複.
對於這種for的查找, 答案有二分性, 咱們要想到神馬?
public class Solution { /** * @param nums an array containing n + 1 integers which is between 1 and n * @return the duplicate one */ public int findDuplicate(int[] nums) { // Write your code here int start = 1; int end = nums.length - 1; while(start + 1 < end) { int mid = start + (end - start) / 2; if (check_smaller_num(mid, nums) <= mid) { start = mid; } else { end = mid; } } if (check_smaller_num(start, nums) <= start) { return end; } return start; } public int check_smaller_num(int mid, int[] nums) { int cnt = 0; for(int i = 0; i < nums.length; i++){ if(nums[i] <= mid){ cnt++; } } return cnt; } } // 映射法 public class Solution { /** * @param nums an array containing n + 1 integers which is between 1 and n * @return the duplicate one */ public int findDuplicate(int[] nums) { // Write your code here if (nums.length <= 1) return -1; int slow = nums[0]; int fast = nums[nums[0]]; while (slow != fast) { slow = nums[slow]; fast = nums[nums[fast]]; } fast = 0; while (fast != slow) { fast = nums[fast]; slow = nums[slow]; } return slow; } }
知足條件和不知足條件的混合:
-> 不知足->知足 |____________|____________|
Given an interval list which are flying and landing time of the flight. How many airplanes are on the sky at most?
Notice
If landing and flying happens at the same time, we consider landing should happen at first.
Have you met this question in a real interview? Yes
Example
For interval list
[
[1,10],
[2,3],
[5,8],
[4,7]
]
這道題呢, 和起點終點的大小有關.
可是有個問題, 若是按起點排序呢, 終點無法處理.
若是按終點排序呢, 起點又無法處理.
區間類的問題, 咱們要想掃描線.
這道題咱們能夠怎麼作?
for一遍1 2 3 4 5 6 7 8 9 10的時間段, 找當時天空中一共有幾架飛機, 而後取最大
本質是這樣的, 如圖4.2所示:
咱們有個時間軸, 每一個時間咱們畫一條鉛筆的總線, 看各個時間的這條總線和橫線的區間交點最可能是幾個.
如今咱們把起點和終點拆開記錄,T表明起飛, F表明降落:
1 T 10 F 2 T 3 F 5 T 8 F 4 T 7 F
排序而後依次遍歷這些時間節點, 記錄count:
1 count++ 2 count++ 3 count-- ......
class Point{ int time; int flag; Point(int t, int s){ this.time = t; this.flag = s; } public static Comparator PointComparator = new Comparator(){ public int compare(Point p1, Point p2){ if(p1.time == p2.time) return p1.flag - p2.flag; else return p1.time - p2.time; } }; } class Solution { /** * @param intervals: An interval array * @return: Count of airplanes are in the sky. */ public int countOfAirplanes(List airplanes) { List list = new ArrayList(airplanes.size()*2); for(Interval i : airplanes){ list.add(new Point(i.start, 1)); list.add(new Point(i.end, 0)); } Collections.sort(list,Point.PointComparator ); int count = 0, ans = 0; for(Point p : list){ if(p.flag == 1) count++; else count--; ans = Math.max(ans, count); } return ans; } }
Given N buildings in a x-axis,each building is a rectangle and can be represented by a triple (start, end, height),where start is the start position on x-axis, end is the end position on x-axis and height is the height of the building. Buildings may overlap if you see them from far away,find the outline of them。
An outline can be represented by a triple, (start, end, height), where start is the start position on x-axis of the outline, end is the end position on x-axis and height is the height of the outline.
Notice
Please merge the adjacent outlines if they have the same height and make sure different outlines cant overlap on x-axis.
Example
Given 3 buildings:
[ [1, 3, 3], [2, 4, 4], [5, 6, 1] ]
The outlines are:
[ [1, 2, 3], [2, 4, 4], [5, 6, 1] ]
圖示參考:
https://briangordon.github.io/2014/08/the-skyline-problem.html
這是一道掃描線和其它結合的題:
區間問題, 若是按起點和終點排序解決不了, 那咱們要想到掃描線. 而掃描線由於須要排序, 因此時間複雜度通常是O(nlogn).
這道題舉個栗子:
[ [1, 3, 2], [2, 4, 3], [5, 6, 2] ]
就要拆成:
1 T 2 3 F 2 2 T 3 4 F 3 5 T 2 6 F 2
sweep line + heap 由於要刪除, 因此c++要用heap
import java.util.*; public class Solution { class HashHeap { ArrayList heap; String mode; int size_t; HashMap hash; class Node { public Integer id; public Integer num; Node(Node now) { id = now.id; num = now.num; } Node(Integer first, Integer second) { this.id = first; this.num = second; } } public HashHeap(String mod) { // TODO Auto-generated constructor stub heap = new ArrayList(); mode = mod; hash = new HashMap(); size_t = 0; } public int peek() { return heap.get(0); } public int size() { return size_t; } public Boolean isEmpty() { return (heap.size() == 0); } int parent(int id) { if (id == 0) { return -1; } return (id - 1) / 2; } int lson(int id) { return id * 2 + 1; } int rson(int id) { return id * 2 + 2; } boolean comparesmall(int a, int b) { if (a 0) { siftdown(0); } } else { hash.put(now, new Node(0, hashnow.num - 1)); } return now; } public void add(int now) { size_t++; if (hash.containsKey(now)) { Node hashnow = hash.get(now); hash.put(now, new Node(hashnow.id, hashnow.num + 1)); } else { heap.add(now); hash.put(now, new Node(heap.size() - 1, 1)); } siftup(heap.size() - 1); } public void delete(int now) { size_t--; Node hashnow = hash.get(now); int id = hashnow.id; int num = hashnow.num; if (hashnow.num == 1) { swap(id, heap.size() - 1); hash.remove(now); heap.remove(heap.size() - 1); if (heap.size() > id) { siftup(id); siftdown(id); } } else { hash.put(now, new Node(id, num - 1)); } } void siftup(int id) { while (parent(id) > -1) { int parentId = parent(id); if (comparesmall(heap.get(parentId), heap.get(id)) == true) { break; } else { swap(id, parentId); } id = parentId; } } void siftdown(int id) { while (lson(id) = heap.size() || (comparesmall(heap.get(leftId), heap.get(rightId)) == true)) { son = leftId; } else { son = rightId; } if (comparesmall(heap.get(id), heap.get(son)) == true) { break; } else { swap(id, son); } id = son; } } } class Edge { int pos; int height; boolean isStart; public Edge(int pos, int height, boolean isStart) { this.pos = pos; this.height = height; this.isStart = isStart; } } class EdgeComparator implements Comparator { @Override public int compare(Edge arg1, Edge arg2) { Edge l1 = (Edge) arg1; Edge l2 = (Edge) arg2; if (l1.pos != l2.pos) return compareInteger(l1.pos, l2.pos); if (l1.isStart && l2.isStart) { return compareInteger(l2.height, l1.height); } if (!l1.isStart && !l2.isStart) { return compareInteger(l1.height, l2.height); } return l1.isStart ? -1 : 1; } int compareInteger(int a, int b) { return a <= b ? -1 : 1; } } List output(List res) { List ans = new ArrayList(); if (res.size() > 0) { int pre = res.get(0).get(0); int height = res.get(0).get(1); for (int i = 1; i 0) { now.add(pre); now.add(id); now.add(height); ans.add(now); } pre = id; height = res.get(i).get(1); } } return ans; } public List buildingOutline(int[][] buildings) { // write your code here List res = new ArrayList(); if (buildings == null || buildings.length == 0 || buildings[0].length == 0) { return res; } ArrayList edges = new ArrayList(); for (int[] building : buildings) { Edge startEdge = new Edge(building[0], building[2], true); edges.add(startEdge); Edge endEdge = new Edge(building[1], building[2], false); edges.add(endEdge); } Collections.sort(edges, new EdgeComparator()); HashHeap heap = new HashHeap("max"); List now = null; for (Edge edge : edges) { if (edge.isStart) { if (heap.isEmpty() || edge.height > heap.peek()) { now = new ArrayList(Arrays.asList(edge.pos, edge.height)); res.add(now); } heap.add(edge.height); } else { heap.delete(edge.height); if (heap.isEmpty() || edge.height > heap.peek()) { if (heap.isEmpty()) { now = new ArrayList(Arrays.asList(edge.pos, 0)); } else { now = new ArrayList(Arrays.asList(edge.pos, heap.peek())); } res.add(now); } } } return output(res); } }
Given an array of n integer with duplicate number, and a moving window(size k), move the window at each iteration from the start of the array, find the maximum number inside the window at each moving.
Have you met this question in a real interview? Yes
Example
For array [1, 2, 7, 7, 8], moving window size k = 3. return [7, 7, 8]
At first the window is at the start of the array like this
[|1, 2, 7| ,7, 8] , return the maximum 7;
then the window move one step forward.
[1, |2, 7 ,7|, 8], return the maximum 7;
then the window move one step forward again.
[1, 2, |7, 7, 8|], return the maximum 8;
queue: 是吃飯拉屎
stack: 是吃飯有毒吐出來
queue: 是上下都吃 上下都排…
這道題若是用heap作呢, 就是O(nlogk)的時間. 若是優化的話呢?
只能想線性數據結構啦
線性數據結構有啥呢? queue stack 和deque
那咱們先試試stack?
好比: [ 1 2 7 5 8] 這組數據:
咱們想找最大值, 那麼就是若是從左到右, 若是遇到比一個數a大的, 就把a踢出去:
先:
1 1加入 1 2 2加入 2 1踢掉 2 7 7加入 7 2踢掉 7 5 5加入
這時候注意了, 5比7 小並不能說明5不會成爲最大值, 由於stack先進後出, 因此有保留有效信息的能力, 因此咱們先把5 存着, 而後:
7 5 8 8加入 7 8 5踢掉 8 7踢掉
單調棧升級爲單調雙端隊列:
public class Solution { /** * @param nums: A list of integers. * @return: The maximum number inside the window at each moving. */ void inQueue(Deque deque, int num) { while (!deque.isEmpty() && deque.peekLast() < num) { deque.pollLast(); } deque.offer(num); } void outQueue(Deque deque, int num) { if (deque.peekFirst() == num) { deque.pollFirst(); } } public ArrayList maxSlidingWindow(int[] nums, int k) { // write your code here ArrayList ans = new ArrayList(); Deque deque = new ArrayDeque(); if (nums.length == 0) { return ans; } for (int i = 0; i < k - 1; i++) { inQueue(deque, nums[i]); } for(int i = k - 1; i < nums.length; i++) { inQueue(deque, nums[i]); ans.add(deque.peekFirst()); outQueue(deque, nums[i - k + 1]); } return ans; } }
爲何Debug必定要靠本身?
緣由有四:
Debug的基本步驟
在第4步中,若是沒法經過肉眼看出錯誤的部分,就一步步「模擬執行」程序,找出錯誤。
實在Debug 不出來怎麼辦?
若是你已經 Debug 了一成天,能夠考慮向他人求助。