LeetCode 406 - Queue Reconstruction by Height


https://leetcode.com/problems/queue-reconstruction-by-height/
Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, k), where h is the height of the person and k is the number of people in front of this person who have a height greater than or equal to h. Write an algorithm to reconstruct the queue.
Note:
The number of people is less than 1,100.
Example

Input:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]

Output:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]

X. Sort Time Complexity: O(N^2) Space Complexity: O(N)
http://www.cnblogs.com/grandyang/p/5928417.html
这道题给了我们一个队列,队列中的每个元素是一个pair,分别为身高和前面身高不低于当前身高的人的个数,让我们重新排列队列,使得每个pair的第二个参数都满足题意。首先我们来看一种超级简洁的方法,不得不膜拜想出这种解法的大神。首先我们给队列先排个序,按照身高高的排前面,如果身高相同,则第二个数小的排前面。然后我们新建一个空的数组,遍历之前排好序的数组,然后根据每个元素的第二个数字,将其插入到res数组中对应的位置
https://discuss.leetcode.com/topic/60394/easy-concept-with-python-c-java-solution
  1. Pick out tallest group of people and sort them in a subarray (S). Since there's no other groups of people taller than them, therefore each guy's index will be just as same as his k value.
  2. For 2nd tallest group (and the rest), insert each one of them into (S) by k value. So on and so forth.
E.g.
input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
subarray after step 1: [[7,0], [7,1]]
subarray after step 2: [[7,0], [6,1], [7,1]]

    public int[][] reconstructQueue(int[][] people) {
        //pick up the tallest guy first
        //when insert the next tall guy, just need to insert him into kth position
        //repeat until all people are inserted into list
        Arrays.sort(people,new Comparator<int[]>(){
           @Override
           public int compare(int[] o1, int[] o2){
               return o1[0]!=o2[0]?-o1[0]+o2[0]:o1[1]-o2[1];
           }
        });
        List<int[]> res = new LinkedList<>();
        for(int[] cur : people){
            if(cur[1]>=res.size())
                res.add(cur);
            else
                res.add(cur[1],cur);       
        }
        return res.toArray(new int[people.length][]);
    }
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people, (a, b) -> a[0] == b[0] ? a[1] - b[1] : b[0] - a[0]);
        List<int[]> list = new LinkedList<>();
        for (int[] p : people) {
            list.add(p[1], p);
        }
        return list.toArray(new int[list.size()][]);
    }
https://leetcode.com/problems/queue-reconstruction-by-height/discuss/89359/Explanation-of-the-neat-Sort+Insert-solution
Below is my explanation of the following neat solution where we sort people from tall to short (and by increasing k-value) and then just insert them into the queue using their k-value as the queue index:
def reconstructQueue(self, people):
    people.sort(key=lambda (h, k): (-h, k))
    queue = []
    for p in people:
        queue.insert(p[1], p)
    return queue
I didn't come up with that myself, but here's my own explanation of it, as I haven't seen anybody explain it (and was asked to explain it):
People are only counting (in their k-value) taller or equal-height others standing in front of them. So a smallest person is completely irrelevant for all taller ones. And of all smallest people, the one standing most in the back is even completely irrelevant for everybodyelse. Nobody is counting that person. So we can first arrange everybody else, ignoring that one person. And then just insert that person appropriately. Now note that while this person is irrelevant for everybody else, everybody else is relevant for this person - this person counts exactly everybody in front of them. So their count-value tells you exactly the index they must be standing.
So you can first solve the sub-problem with all but that one person and then just insert that person appropriately. And you can solve that sub-problem the same way, first solving the sub-sub-problem with all but the last-smallest person of the subproblem. And so on. The base case is when you have the sub-...-sub-problem of zero people. You're then inserting the people in the reverse order, i.e., that overall last-smallest person in the very end and thus the first-tallest person in the very beginning. That's what the above solution does, Sorting the people from the first-tallest to the last-smallest, and inserting them one by one as appropriate.

Nice explanation. I actually came to this solution myself, and pretty quickly, only to be completely baffled by the next rain problem. My code was a bit different, though, because I totally forgot about the key parameter:
        res = []
        for p in sorted((-x[0], x[1]) for x in people):
            res.insert(p[1], [-p[0], p[1]])
        return res
My thinking process, though, was completely backwards. At first I remembered the Russian Doll Envelopes problem, which had me baffled for a while, and this awesome solution to it. So I immediately thought about sorting in various orders by various keys. It became instantly obvious that persons with the same height should be sorted by the second value: if they have the same height, then they have the same selection criteria for counting, and therefore the one with more selected persons in front of them should be behind.
Then I thought about height. Suppose I take only the tallest persons, all having the same maximum height. Their second values must be 0, 1, 2, 3... with no gaps at all, because they only count each other. Therefore, if there were no other persons at all, their second value must be their final index. What about the persons with second maximum height then? Suppose there are only tallest persons and just one more person who has slightly smaller height. What would be his position? Well, since he obviously only count tallest persons, his position would still be his second value. The next person of the same height counts only the previous person and all the tallest ones, but since they are all already in the queue, his second value would also be his index.
Then I realized that I could go on forever like that because each time I put a person in the queue and go to the next person, all persons counted by the next one are already there, so I instantly know the right index and I know that the person I put in the queue doesn't really care about where I put all subsequent persons because they are outside of his selection criteria.
https://discuss.leetcode.com/topic/60423/java-o-n-2-greedy-solution
We always choose the current shortest height (so we need to sort input first), and then try to put it into the right position. We simply scan from the left and count how many persons are really >= its own height. Then we put the person into the empty slot.
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people,new Comparator<int[]>(){
           public int compare(int[] p1, int[] p2){
               return p1[0]!=p2[0]?Integer.compare(p2[0],p1[0]): Integer.compare(p1[1],p2[1]);
           }
        });
        List<int[]> list = new LinkedList(); // use arraylist or array
        for (int[] ppl: people) list.add(ppl[1], ppl);
        return list.toArray(new int[people.length][] );
    }
https://discuss.leetcode.com/topic/60417/java-solution-using-arrays-sort-and-insert-sorting-idea

X.  - O(N^2)
上面那种方法是简洁,但是用到了额外空间,我们来看一种不使用额外空间的解法,这种方法没有没有使用vector自带的insert或者erase函数,而是通过一个变量cnt和k的关系来将元素向前移动到正确位置,移动到方法是通过每次跟前面的元素交换位置,使用题目中给的例子来演示过程:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
排序后:
[[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]]
交换顺序:
[[7,0], [6,1][7,1], [5,0], [5,2], [4,4]]
[[5,0], [7,0], [6,1], [7,1], [5,2], [4,4]]
[[5,0], [7,0], [5,2], [6,1], [7,1], [4,4]]
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]

    vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
        sort(people.begin(), people.end(), [](const pair<int, int>& a, const pair<int, int>& b) {
            return a.first > b.first || (a.first == b.first && a.second < b.second);
        });
        for (int i = 1; i < people.size(); ++i) {
            int cnt = 0;
            for (int j = 0; j < i; ++j) {
                if (cnt == people[i].second) {
                    pair<int, int> t = people[i];
                    for (int k = i - 1; k >= j; --k) {
                        people[k + 1] = people[k];
                    }
                    people[j] = t;
                    break;
                }
                if (people[j].first >= people[i].first) ++cnt;
            }
        }
        return people;
    }

下面这种解法跟解法一很相似,只不过没有使用额外空间,而是直接把位置不对的元素从原数组中删除,直接加入到正确的位置上
    vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
        sort(people.begin(), people.end(), [](const pair<int,int> &a, const pair<int, int> &b) {
            return a.first > b.first || (a.first == b.first && a.second < b.second);
        });
        for (int i = 0; i < people.size(); i++) {
            auto p = people[i];
            if (p.second != i) {
                people.erase(people.begin() + i);
                people.insert(people.begin() + p.second, p);
            }
        }
        return people;
    }
一开始的思路是按照k的大小升序排列,如果k相等就按h升序排列.然后对于每一个元素从头开始到自身位置查找并计数比当前元素大的个数,直到计数比当前元素k大停止,如果此时正好停在当前位置,说明当前元素不需要移动,否则就删除当前元素插入到停止位置之前.这样做的好处是不需要额外申请空间,但是代码稍微麻烦一点.看了一下别人的,发现只需要改变一下排序的规则可以让代码简化很多.就是依然按照h降序排序,但是如果h相等则按照k升序排序.然后开一个新数组,因为数组按照降序排序,所以每次只需要将元素插入到新数组的k的位置即可.两种方法时间复杂度都是O(n*2),但是第二种更容易理解和实现

X. Using PriorityQueue

首先选出k值为0且身高最低的人,记为hi, ki,将其加入结果集。
然后更新队列,若队列中人员的身高≤hi,则令其k值 - 1(需要记录原始的k值)。
循环直到队列为空。
public int[][] reconstructQueue(int[][] people) { int size = people.length; LinkedList<int[]> list = new LinkedList<int[]>(); for (int i = 0; i < size; i++) { list.add(new int[]{people[i][0], people[i][1], 0}); } int ans[][] = new int[size][]; for (int i = 0; i < size; i++) { Collections.sort(list, new Comparator<int[]>() { public int compare (int[] a, int[] b) { if (a[1] == b[1]) return a[0] - b[0]; return a[1] - b[1]; } }); int[] head = list.removeFirst(); ans[i] = new int[]{head[0], head[1] + head[2]}; for (int[] p : list) { if (p[0] <= head[0]) { p[1] -= 1; p[2] += 1; } } } return ans; }
X. https://discuss.leetcode.com/topic/60550/o-n-sqrt-n-solution/13
https://discuss.leetcode.com/topic/60437/java-solution-using-priorityqueue-and-linkedlist
Instead of using ArrayList for insertion, using LinkedList is more efficient. Here is the discussion of when to use LinkedList over ArrayList on StackOverFlow.
    class PairComp implements Comparator<int[]> {
        public int compare(int[] p1, int[] p2){
            int comp_h = Integer.compare(p2[0], p1[0]);
            return comp_h == 0 ? Integer.compare(p1[1], p2[1]): comp_h;
        }
    }
    public int[][] reconstructQueue(int[][] people) {
        LinkedList<int[]> list = new LinkedList();
        PriorityQueue<int[]> queue = new PriorityQueue<int[]>(1, new PairComp() );
        for (int[] ppl: people){
            queue.offer( ppl );
        }
        while ( ! queue.isEmpty() ) {
            int[] pair = queue.poll();
            list.add(pair[1], pair);
        }
        int[][] ret = new int[people.length][];
        for (int i=0; i<list.size(); i++){
            ret[i] = list.get(i);
        }
        return ret;
    }
Shorter version without using PriorityQueue:
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people,new Comparator<int[]>(){
           public int compare(int[] p1, int[] p2){
               return p1[0]!=p2[0]?Integer.compare(p2[0],p1[0]): Integer.compare(p1[1],p2[1]);
           }
        });
        List<int[]> list = new LinkedList();
        for (int[] ppl: people) list.add(ppl[1], ppl);
        return list.toArray(new int[people.length][] );
    }
X. https://leetcode.com/problems/queue-reconstruction-by-height/discuss/89367/O(n-sqrt(n))-solution
Instead of just one long list of all people, I break the queue into O(sqrt(n)) blocks of size up to sqrt(n). Then to insert at the desired index, I find the appropriate block, insert the person into that block, and potentially have to break the block into two. Each of those things takes O(sqrt(n)) time.
def reconstructQueue(self, people):
    blocks = [[]]
    for p in sorted(people, key=lambda (h, t): (-h, t)):
        index = p[1]

        for i, block in enumerate(blocks):
            m = len(block)
            if index <= m:
                break
            index -= m
        block.insert(index, p)
        if m * m > len(people):
            blocks.insert(i + 1, block[m/2:])
            del block[m/2:]

    return [p for block in blocks for p in block]

X. Merge sort
https://leetcode.com/problems/queue-reconstruction-by-height/discuss/143403/O(nlogn)-modified-merge-sort-solution-with-detailed-explanation
The intuition is the fact that if we start with the people sorted ascending by height, then the k value for each person is equal to the number of people that are moved from the right side of a person to the left. You then may realize that you can actually track the number of values moving from right to left during sorting, thus we can modify an existing sorting algorithm (Merge Sort) to take advantage of this fact.

Definitions

Inversions: The number of people that must be moved from the right of a given person to left
Merge Sort: Divide and conquer sorting algorithm where sub-parts are sorted separately and then merged. Log-linear time.
Merge: Key step of merge sort where two separately sorted lists are combined in linear time.

Algorithm

First we sort ascending by height, descending by k if heights are equal. We do this so when we re-sort to the final order, we know how many people of greater than/equal height are moving from right to left. Note that after initial sorting, we know that all people to the right of a person must have height greater than or equal to that person. Initially, the required inversions for each person is the associated k value.
The hard part is now to re-order to the final answer. If we use Merge Sort, we can accurately track the number of inversions as we "move" people from right to left.
While performing the Merge step, we will compare people from the left sub-list and right sub-list. To determine which to place first in the final list at each comparison, we examine the number of remaining inversions that still need to occur for each person. We always choose the person with the smaller remaining inversions.
Let's define a few values for brevity:
L: Current person being compared from the left sub-list
R: Current person being compared from the right sub-list
LIL's remaining inversions
RIR's remaining inversions
As metioned before, we must make a choice between L and R at each iteration of merge, but why do we always choose the person with less remaining inversion? We can have 3 scenarios during the comparison; the logic for each choice will be explained below by contradiction i.e. "what if we made the oppposite choice?":
  1. LI < RI: choose L. If instead we chose the RRI inversions would also affect L (because they must move left past both people), but this would exceed LI, resulting in the kvalue of L to be off by 1 or more.
  2. LI > RI: choose R. If instead we chose to keep the L on the left, the only way to get LI people to move left of L would be to also move those people past R; however these moves would exceed RI, so the kvalue of R would be off by 1 or more.
  3. LI == RI: We must choose the shorter person:
    3a. L is shorter than R, choose L: if instead we chose to place R to the left, it would require an additional inversion for L since a person has moved from right to left, which would result in LI being decreased to a value lower than RI (now LI < RI). However, in order to to move RI people past R, they must also pass L. This would result in the k value of L being off by 1 or more.
    3b. R is shorter or equal height, choose R: if instead we chose to place L to the left, RI would remain equal to LI. In order to move LI people past L, they would also move past R. However, the k value of R is now off by 1, because in addition to the LI people, L (which is now before R) is also of greater than or equal height to R.
Go code which beats 100%:
func reconstructQueue(people [][]int) [][]int {
    // Sort ascending by height, descending by k
    sort.Slice(people, func(i,j int) bool {
        if people[i][0] == people[j][0] {
            // Descending by k  
            return people[i][1] > people[j][1]
        } 
        // Ascending by height
     return people[i][0] < people[j][0] 
    })
    // Make an array allowing tracking current number of inversions without
    // modifying original input values (because they need to be preserved for 
    // the return)
    invs := make([]int, len(people))
    for i, person := range people {
        invs[i] = person[1]
    }
    
    mergeSort(people, invs, 0, len(people)-1)
    
    return people
}

func mergeSort(people [][]int, invs []int, left, right int) {
    if left >= right {
        return
    }
    middle := (left + right) / 2

    mergeSort(people, invs, left, middle)
    mergeSort(people, invs, middle+1, right)
    
    merge(people, invs, left, middle, right)
}

func merge(people [][]int, invs []int, left, middle, right int) {
    inversions := 0
    li, ri := left, middle+1
    i := 0
    tmp := make([][]int, right-left+1)
    tmpInv := make([]int, right-left+1)
    for li <= middle && ri <= right {
        if invs[li]-inversions < invs[ri] { 
            tmp[i], tmpInv[i] = people[li], invs[li]-inversions
            li++
        } else if invs[li]-inversions > invs[ri] {
            inversions++
            tmp[i], tmpInv[i] = people[ri], invs[ri]
            ri++
        } else { 
            if people[li][0] < people[ri][0] {
                tmp[i], tmpInv[i] = people[li], invs[li]-inversions
                li++
            } else {
                inversions++
                tmp[i], tmpInv[i] = people[ri], invs[ri]
                ri++
            }
        }
        i++
    }
    for li <= middle {
        tmp[i], tmpInv[i] = people[li], invs[li]-inversions
        li++
        i++
    }
    for ri <= right {
        tmp[i], tmpInv[i] = people[ri], invs[ri]
        ri++
        i++
    }
    // Copy in tmp array
    for ti, person := range tmp {
        people[left+ti], invs[left+ti] = person, tmpInv[ti]
    }
}
X. BIT
https://leetcode.com/problems/queue-reconstruction-by-height/discuss/89342/O(nlogn)-Binary-Index-Tree-C%2B%2B-solution
1. Sort by height, if height is equal, sort by second item

2. Naive Algorithm:
   for each item in seq:
         find the new insert position and assign it to the item

3. Case analysis:
    [4,4], [5,0], [5,2], [6,1], [7,0], [7,1], total 6 sorted items
    that means we must fill 6 blankets.     _ _ _ _ _ _ 
    (1)[4,4] means there are 4 items before it, since no other items less than it, so it must be at the 5th pos. 
    (2)[5,0] means there are 0 items before it, so it must be at the first pos.
    ......
    (6)same as before
    
   visualize process
   -----------------

     _      _      _      _      _      _
     _      _      _      _    [4,4]    _
   [5,0]    _      _      _    [4,4]    _
   [5,0]    _    [5,2]    _    [4,4]    _
   [5,0]    _    [5,2]  [6,1]  [4,4]    _
   [5,0]  [7,0]  [5,2]  [6,1]  [4,4]    _
   [5,0]  [7,0]  [5,2]  [6,1]  [4,4]  [7,1]

4. Improved Algorithm
    for each item in seq:
         pos = find Kth avaliable position in newArray // K = item.second
         newArray[pos] = item
         used[pos] = true

   Implement find_Kth() method can be done in O(n), thus total complexity is O(n^2)

5. Implement find_Kth() method in O(lgN*lgN) or O(lgN) use BIT
    (1)trick #1: to convert the former "fill blanket" to "range sum"
    (2)trick #2: if height[i] == height[i+1], we must delay the "convert" operation as below described

   visualize process
   -----------------
     1   1   1   1   1   1      // first initialize all position with 1
     1   1   1   1   0   1     // find [4,4] pos by calling find_Kth(4+1), pos = 5, and convert 1 to 0
     1   1   1   1   0   1     // find [5,0] pos by calling find_Kth(0+1), pos = 1, do not convert 1 to 0 
     0   1   0   1   0   1     // find [5,2] pos by calling find_Kth(2+1), pos = 3, and convert 1 to 0
     0   1   0   0   0   1     // find [6,1] pos by calling find_Kth(1+1), pos = 4, and convert 1 to 0
     0   1   0   0   0   1     // find [7,0] pos by calling find_Kth(0+1), pos = 2, do not convert 1 to 0 
     0   0   0   0   0   0     // find [7,1] pos by calling find_Kth(1+1), pos = 6, convert 1 to 0
Dirty Code Below......
Hope someone can post a nice and clean code.....
class Solution {
public:
    typedef pair<int,int> Node;
    vector<int> c;
    int n;
    vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
        int len = people.size();
        vector<Node> ans(len);
        vector<int> tmp(len+2,0);
        c = tmp;
        n = len;
        
        //initialize
        for(int i = 1; i <= n; i++)update(i,1);
        sort(people.begin(), people.end());
        
        int pre = -1;
        vector<int> preNum;
        
        for(int i = 0; i < len; i++)
        {
            //amotized O(1) operation
            if(people[i].first != pre)
            {
                for(int j = 0; j < preNum.size(); j++)update(preNum[j],-1);
                preNum.clear();
                    
            }
            int num = findKth(people[i].second+1);
            ans[num-1] = people[i];
            
            preNum.push_back(num);
            pre = people[i].first;
        }
        
        return ans;
        
    }
    
   //Binary Index Tree update
    void update(int idx, int val)
    {
        while(idx <= n)
        {
            c[idx] += val;
            idx += idx & -idx;
        }
    }
    
    //Binary Index Tree getSum [1, idx]
    int getsum(int idx)
    {
        int sum = 0;
        while(idx > 0)
        {
            sum += c[idx];
            idx -= idx & -idx;
        }
        return sum;
    }
    
    //find-Kth position, Here I use Binary-search, So complexity is O(lgN*lgN)
    int findKth(int k)
    {
        int l = 1, r = n, mid;
        while(l <= r)
        {
            mid = (l + r) >> 1;
            if(getsum(mid) >= k)r = mid - 1;
            else l = mid + 1;
        }
        return l;
    }
    
    bool static cmp(Node a, Node b)
    {
        if(a.first == b.first)return a.second < b.second;
        return a.first < b.first;
    }
};


Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts