LeetCode 39 - Combination Sum


Related:
Subset Sum Problem - DP
LeetCode 39 - Combination Sum
LeetCode 40 - Combination Sum II
Leetcode 216 Combination Sum III
LeetCode 377 - Combination Sum IV
Given a set of candidate numbers C and a target number T, find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times.
  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1,a2,,ak) must be in non-descending order. (i.e., a1a2ak ).
  • The solution set must not contain duplicate combinations.
  • For example, given candidate set 2,3,6,7 and target 7,  a solution set is: { [7], [2, 2, 3] }
基本思路是先排好序,然后每次递归中把剩下的元素一一加到结果集合中,并且把目标减去加入的元素,然后把剩下元素(包括当前加入的元素)放到下一层递归中解决子问题。算法复杂度因为是NP问题,所以自然是指数量级的

Presort; 
Optimization: exit early, branch
X. BFS

X. DP
https://discuss.leetcode.com/topic/8200/iterative-java-dp-solution

The main idea reminds an approach for solving coins/knapsack problem - to store the result for all i < target and create the solution from them. For that for each t from 1 to our target we try every candidate which is less or equal to t in ascending order. For each candidate "c" we run through all combinations for target t-c starting with the value greater or equal than c to avoid duplicates and store only ordered combinations.
I just wonder, would there be any relative performance disadvantage comparing to dfs when in cases where both the target and the candidates are large, e.g. target=1000000, candidates=[499999,500001]

    public List<List<Integer>> combinationSum(int[] cands, int t) {
        Arrays.sort(cands); // sort candidates to try them in asc order
        List<List<List<Integer>>> dp = new ArrayList<>();
        for (int i = 1; i <= t; i++) { // run through all targets from 1 to t
            List<List<Integer>> newList = new ArrayList(); // combs for curr i
            // run through all candidates <= i
            for (int j = 0; j < cands.length && cands[j] <= i; j++) {
                // special case when curr target is equal to curr candidate
                if (i == cands[j]) newList.add(Arrays.asList(cands[j]));
                // if current candidate is less than the target use prev results
                else for (List<Integer> l : dp.get(i-cands[j]-1)) {
                    if (cands[j] <= l.get(0)) {
                        List cl = new ArrayList<>();
                        cl.add(cands[j]); cl.addAll(l);
                        newList.add(cl);
                    }
                }
            }
            dp.add(newList);
        }
        return dp.get(t-1);
    }
X. DFS
https://discuss.leetcode.com/topic/46161/a-general-approach-to-backtracking-questions-in-java-subsets-permutations-combination-sum-palindrome-partitioning
https://discuss.leetcode.com/topic/7698/java-solution-using-recursive
public List<List<Integer>> combinationSum(int[] nums, int target) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, target, 0);
    return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int remain, int start){
    if(remain < 0) return;
    else if(remain == 0) list.add(new ArrayList<>(tempList));
    else{ 
        for(int i = start; i < nums.length; i++){
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, remain - nums[i], i); // not i + 1 because we can reuse same elements
            tempList.remove(tempList.size() - 1);
        }
    }
}
Combination Sum II (can't reuse same element) : https://leetcode.com/problems/combination-sum-ii/
public List<List<Integer>> combinationSum2(int[] nums, int target) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, target, 0);
    return list;
    
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int remain, int start){
    if(remain < 0) return;
    else if(remain == 0) list.add(new ArrayList<>(tempList));
    else{
        for(int i = start; i < nums.length; i++){
            if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, remain - nums[i], i + 1);
            tempList.remove(tempList.size() - 1); 
        }
    }
} 




http://codesniper.blogspot.com/2015/03/39-combination-sum-leetcode.html


1. base, terminating case:
if(target==0) ...
2. recursion steps: 
   a) try current candidate: items.add(candidate[i]);
   b) recursion to next level: helper(target-candidate[i]...);
    c) backtrack to current level, remove current candidate: items.remove(item.size()-1---> "candidate[i]")
Tips: 
1. Skip duplicated elements to avoid non necessary recursion and duplicated result.
2. Since element can be used multi times, the next level will be start with the same index as the current level. 

  public List<List<Integer>> combinationSum(int[] candidates, int target) {  
     List<List<Integer>> res=new ArrayList<List<Integer>>();  
     if(candidates==null || candidates.length==0) return res;  
     Arrays.sort(candidates);  
     List<Integer> item=new ArrayList<Integer>();  
     helper(candidates,0,target,item,res);  
     return res;  
   }  
   public void helper(int[] candidates, int index, int target, List<Integer> item, List<List<Integer>> res){  
     if(target==0){  
       List<Integer> temp= new ArrayList<Integer>(item);  
       res.add(temp);  
       return;  
     }  
     for(int i=index;i<candidates.length;i++){  
       if(i>0 && candidates[i]==candidates[i-1]) continue;  
        if(target-candidates[i]<0) return;  
       item.add(candidates[i]);  
       helper(candidates,i,target-candidates[i],item,res);  
       item.remove(item.size()-1);  
     }  
   }  
http://bangbingsyb.blogspot.com/2014/11/leetcode-combination-sum-i-ii.html
由于candidates都为正数,当和超过或等于target时,查找中止。与3sum的思路一样,对candidate排序,并且每层递归扫描的时候需要做到去重复解:
1. 不回头扫,在扫描candidates[i]时,对candidate[i: n-1]递归查找target-candidates[i]。
2. 每层扫描的时候跳过重复的candidates。

public ArrayList<ArrayList<Integer>> combinationSum(int[] candidates, int target) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        if (candidates == null || candidates.length == 0)
            return result;
        Arrays.sort(candidates);        // Sort the candidate in non-descending order
        ArrayList<Integer> current = new ArrayList<Integer>();
        recursiveAppend(candidates, target, 0, current, result);
        return result;
    }
    private void recursiveAppend(int[] candidates, int target, int startIndex, ArrayList<Integer> current,
                                 ArrayList<ArrayList<Integer>> result) {
        if (target < 0)
            return;
        if (target == 0) {     // The current array is an solution
            result.add(new ArrayList<Integer>(current));
            return;
        }
        for (int i = startIndex; i < candidates.length; i++) {
            if (candidates[i] > target)    // No need to try the remaining candidates
                break;
            // Add candidate[i] to the current array
            current.add(candidates[i]);
            // Recursively append the current array to compose a solution
            recursiveAppend(candidates, target-candidates[i], i, current, result);
            // Remove candidate[i] from the current array, and try next candidate in the next loop
            current.remove(current.size()-1);
        }
    }
http://blog.csdn.net/linhuanmars/article/details/20828631
基本思路是先排好序,然后每次递归中把剩下的元素一一加到结果集合中,并且把目标减去加入的元素,然后把剩下元素(包括当前加入的元素)放到下一层递归中解决子问题。算法复杂度因为是NP问题,所以自然是指数量级的.
注意在实现中for循环中第一步有一个判断,那个是为了去除重复元素产生重复结果的影响,因为在这里每个数可以重复使用,所以重复的元素也就没有作用了,所以应该跳过那层递归。
http://www.cnblogs.com/springfor/p/3884294.html
The same repeated number may be chosen from C unlimited number of times.
所以,每次跳进递归不用都往后挪一个,还可以利用当前的元素尝试。
同时,这道题还要判断重复解。用我之前介绍的两个方法:
 1.       if(i>0 && candidates[i] == candidates[i-1])//deal with dupicate
                 continue
 2.       if(!res.contains(item))
                res.add(new ArrayList<Integer>(item));   
 1     public ArrayList<ArrayList<Integer>> combinationSum(int[] candidates, int target) {
 2         ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
 3         ArrayList<Integer> item = new ArrayList<Integer>();
 4         if(candidates == null || candidates.length==0)
 5             return res;
 6    
 7         Arrays.sort(candidates);
 8         helper(candidates,target, 0, item ,res);
 9         return res;
10     }
11
12     private void helper(int[] candidates, int target, int start, ArrayList<Integer> item,
13     ArrayList<ArrayList<Integer>> res){
14         if(target<0)
15             return;
16         if(target==0){
17             res.add(new ArrayList<Integer>(item));
18             return;
19         }
20
21         for(int i=start;i<candidates.length;i++){
22             if(i>0 && candidates[i] == candidates[i-1])//deal with dupicate
23                 continue;
24             item.add(candidates[i]);
25             int newtarget = target - candidates[i];
26             helper(candidates,newtarget,i,item,res);//之所以不传i+1的原因是:27                                                     //The same repeated number may be 28                                                     //chosen from C unlimited number of times.
29             item.remove(item.size()-1);
30         }
31     } 
http://www.jiuzhang.com/solutions/combination-sum/
// version 1: Remove duplicates & generate a new array
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> results = new ArrayList<>();
        if (candidates == null || candidates.length == 0) {
            return results;
        }
        
        int[] nums = removeDuplicates(candidates);
        
        dfs(nums, 0, new ArrayList<Integer>(), target, results);
        
        return results;
    }
    
    private int[] removeDuplicates(int[] candidates) {
        Arrays.sort(candidates);
        
        int index = 0;
        for (int i = 0; i < candidates.length; i++) {
            if (candidates[i] != candidates[index]) {
                candidates[++index] = candidates[i];
            }
        }
        
        int[] nums = new int[index + 1];
        for (int i = 0; i < index + 1; i++) {
            nums[i] = candidates[i];
        }
        
        return nums;
    }
    
    private void dfs(int[] nums,
                     int startIndex,
                     List<Integer> combination,
                     int remainTarget,
                     List<List<Integer>> results) {
        if (remainTarget == 0) {
            results.add(new ArrayList<Integer>(combination));
            return;
        }
        
        for (int i = startIndex; i < nums.length; i++) {
            if (remainTarget < nums[i]) {
                break;
            }
            combination.add(nums[i]);
            dfs(nums, i, combination, remainTarget - nums[i], results);
            combination.remove(combination.size() - 1);
        }
    }
}

// version 2: reuse candidates array
public class Solution {
    public  List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> result = new ArrayList<>();
        if (candidates == null) {
            return result;
        }

        List<Integer> combination = new ArrayList<>();
        Arrays.sort(candidates);
        helper(candidates, 0, target, combination, result);

        return result;
    }

     void helper(int[] candidates,
                 int index,
                 int target,
                 List<Integer> combination,
                 List<List<Integer>> result) {
        if (target == 0) {
            result.add(new ArrayList<Integer>(combination));
            return;
        }

        for (int i = index; i < candidates.length; i++) {
            if (candidates[i] > target) {
                break;
            }

            if (i != index && candidates[i] == candidates[i - 1]) {
                continue;
            }

            combination.add(candidates[i]);
            helper(candidates, i, target - candidates[i], combination, result);
            combination.remove(combination.size() - 1);
        }
    }
}

    public  ArrayList<ArrayList<Integer>> combinationSum(int[] candidates, int target) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        if (candidates == null) {
            return result;
        }

        ArrayList<Integer> path = new ArrayList<Integer>();
        Arrays.sort(candidates);
        helper(candidates, target, path, 0, result);

        return result;
    }

     void helper(int[] candidates, int target, ArrayList<Integer> path, int index,
        ArrayList<ArrayList<Integer>> result) {
        if (target == 0) {
            result.add(new ArrayList<Integer>(path));
            return;
        }

        int prev = -1; // use prev
        for (int i = index; i < candidates.length; i++) {
            if (candidates[i] > target) {
                break;
            }

            if (prev != -1 && prev == candidates[i]) {
                continue;
            }

            path.add(candidates[i]);
            helper(candidates, target - candidates[i], path, i, result);
            path.remove(path.size() - 1);

            prev = candidates[i];
        }
    }
X. Iterative Version
https://leetcode.com/discuss/14362/dynamic-programming-solution
https://github.com/Deadbeef-ECE/Interview/blob/master/Leetcode/BackTracking/039_Combination_Sum.java
public List<List<Integer>> combinationSum(int[] nums, int target) {
    if(nums == null || nums.length == 0)
        return new LinkedList<List<Integer>>();
    Arrays.sort(nums);
    HashMap<Integer, List<List<Integer>>> dp = new HashMap<Integer, List<List<Integer>>>();
    dp.put(0, new LinkedList<List<Integer>>());
    dp.get(0).add(new LinkedList<Integer>());
 
    for(int i = 0; i < nums.length; i++){ // skip when: nums[i[==nums[i+1]
        int cur = nums[i];
        for(int j = cur; j <= target; j++){//
            if(dp.containsKey(j - cur)){//
                for(List<Integer> sol : dp.get(j - cur)){
                    List<Integer> curSol = new LinkedList<Integer>(sol);
                    curSol.add(cur);
                    if(!dp.containsKey(j)){
                        dp.put(j, new LinkedList<List<Integer>>());
                    }
                    dp.get(j).add(curSol);
                }
            }
        }
    }
    if(dp.get(target) == null)
        return new LinkedList<List<Integer>>();
    return dp.get(target);
}

https://leetcode.com/discuss/23818/iterative-java-dp-solution
thanks for this nice answer. I just wonder, would there be any relative performance disadvantage comparing to dfs when in cases where both the target and the candidates are large, e.g. target=1000000, candidates=[499999,500001]?

The main idea reminds an approach for solving coins/knapsack problem - to store the result for all i < target and create the solution from them. For that for each t from 1 to our target we try every candidate which is less or equal to t in ascending order. For each candidate "c" we run through all combinations for target t-c starting with the value greater or equal than c to avoid duplicates and store only ordered combinations.
public List<List<Integer>> combinationSum(int[] cands, int t) { Arrays.sort(cands); // sort candidates to try them in asc order List<List<List<Integer>>> dp = new ArrayList<>(); for (int i = 1; i <= t; i++) { // run through all targets from 1 to t List<List<Integer>> newList = new ArrayList(); // combs for curr i // run through all candidates <= i for (int j = 0; j < cands.length && cands[j] <= i; j++) { // special case when curr target is equal to curr candidate if (i == cands[j]) newList.add(Arrays.asList(cands[j])); // if current candidate is less than the target use prev results else for (List<Integer> l : dp.get(i-cands[j]-1)) { if (cands[j] <= l.get(0)) { List cl = new ArrayList<>(); cl.add(cands[j]); cl.addAll(l); newList.add(cl); } } } dp.add(newList); } return dp.get(t-1); }
X. DFS Stack
   class SumNode{  
     int index;  
     int sum;  
     List<Integer> path;  
     SumNode(int index, int value, List<Integer> path){  
       this.index = index;  
       this.sum = value;  
       this.path = new ArrayList<Integer>(path);  
     }  
     public void addNumber(int value){  
       this.sum += value;  
       this.path.add(value);  
     }  
   }  
   public List<List<Integer>> combinationSum(int[] candidates, int target) {  
     List<List<Integer>> rslt = new ArrayList<List<Integer>>();  
     Stack<SumNode> stack = new Stack<SumNode>();  
     Arrays.sort(candidates);  
     SumNode root = new SumNode(0, 0, new ArrayList<Integer>());  
     stack.push(root);  
     while(!stack.isEmpty()){  
       SumNode node = stack.pop();  
       for(int i = node.index;i < candidates.length;i++){  
         if(node.sum + candidates[i] > target) break;  
         SumNode child = new SumNode(i, node.sum, node.path);  
         child.addNumber(candidates[i]);  
         if(child.sum==target) rslt.add(child.path);  
         else stack.push(child);  
       }  
     }  
     return rslt;  
   }  

X. BFS Queue
http://siyang2leetcode.blogspot.com/2015/03/combination-sum.html
   class SumNode{  
     int index;  
     int sum;  
     List<Integer> path;  
     SumNode(int index, int value, List<Integer> path){  
       this.index = index;  
       this.sum = value;  
       this.path = new ArrayList<Integer>(path);  
     }  
     public void addNumber(int value){  
       this.sum += value;  
       this.path.add(value);  
     }  
   }  
   public List<List<Integer>> combinationSum(int[] candidates, int target) {  
     List<List<Integer>> rslt = new ArrayList<List<Integer>>();  
     Queue<SumNode> queue = new LinkedList<SumNode>();  
     Arrays.sort(candidates);  
     SumNode root = new SumNode(0, 0, new ArrayList<Integer>());  
     queue.add(root);  
     while(!queue.isEmpty()){  
       SumNode node = queue.poll();  
       for(int i = node.index;i < candidates.length;i++){  
         if(node.sum + candidates[i] > target) break;  
         SumNode child = new SumNode(i, node.sum, node.path);  
         child.addNumber(candidates[i]);  
         if(child.sum==target) rslt.add(child.path);  
         else queue.add(child);  
       }  
     }  
     return rslt;  
   }  

X. Bad solutions
https://leetcode.com/discuss/10141/a-solution-avoid-using-set
public List<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> ret = new LinkedList<List<Integer>>(); Arrays.sort(candidates); // sort the candidates // collect possible candidates from small to large to eliminate duplicates, recurse(new ArrayList<Integer>(), target, candidates, 0, ret); return ret; } // the index here means we are allowed to choose candidates from that index private void recurse(List<Integer> list, int target, int[] candidates, int index, List<List<Integer>> ret) { if (target == 0) { ret.add(list); return; } for (int i = index; i < candidates.length; i++) { int newTarget = target - candidates[i]; if (newTarget >= 0) { List<Integer> copy = new ArrayList<Integer>(list); copy.add(candidates[i]);// add to list then remove it//backtrack recurse(copy, newTarget, candidates, i, ret); } else { break; } } }
https://leetcode.com/discuss/61491/asked-discuss-time-complexity-your-solution-what-would-say
(1) Let us see the difference between Combination Sum and Combination Sum II:
The input of Combination Sum has no dups, but each element can be used for MORE than one time.
The input of Combination Sum II has dups, but each element can be used for ONLY one time.
(2) Let us understand the time complexity of Combination Sum II at the beginning:
O(k * 2 ^ n) is the time complexity of Combination Sum II:
k is average length of each solution, and we need O(k) time to copy new linkedlist when we get one combination.
Solution space:
Since we use one element ONLY for one time, so, for the combinations with k elements, the number of different choices is C(n, k). And most of the time, this number is far smaller than k. But what is the worst case? int[] arr = {1,1,1,1,1,1,1,1,1}, target is 2, in this case, the number can actually reach C(n,k).
Considering that the combinations may have different length, which range from 0 ~ n. So, there are at most C(n,0) + C(n,1) + C(n,2) + ... C(n,n) solutions. We know that C(n,0) + C(n,1) + C(n,2) + ... C(n,n) = 2^n. Then we got the time complexity of Combination Sum II which is O(k * 2 ^ n).
(3) Then how we convert Combination Sum to Combination Sum II?
For example, given int[] arr = {2, 3, 4, 5, 6} and target is 10 and each element can be used for MORE than once.
Actually, it is same with the problem: given int[] arr = {2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6}, and target 10, each element can be used for ONLY one time, which is the same description of Combination Sum II.
And you must find that for the new array, each element E, which is smaller than target, will expand to ceil(target/E). Assume the new array has length n', we can get the time complexity which is O(k * 2 ^ n') using the same analysis of Combination Sum II.
https://github.com/Deadbeef-ECE/Interview/blob/master/Leetcode/BackTracking/039_Combination_Sum.java
// 此题time complexity无比蛋疼
// (1) 首先来看Combination sum I和II的区别:
// Combination sum 的input无dups, 但是input的元素可以重复利用
// Combination sum II 的input有重复, 但是input的元素只能用一次
//
// (2) 其次, 弄明白 Combination sum II的time complexity是怎么一回事儿
// https://github.com/Deadbeef-ECE/Interview/blob/master/Leetcode/BackTracking/040_Combination_Sum_II.java

// O(k * 2^n') time:
// 此题可以转换成 combination sum II, 如何做呢, 举个栗子:
// int[] arr = {2, 3, 4, 5, 6}, target = 10; 我们知道此题中,每个元素可以重复用,
// 其实, 如果把 arr 变成 {2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6}, 然
// 后每个元素只能用一次, 就变成了combination sum II的要求了.
// 我们再看新数组, 元素多了很多, 多了多少?
// 那就是数组中所有小于等于target的元素E增加了ceil(target/E)个, 然后就可以用
// combination sum II的方法分析复杂度了. 这里n'是新arr的大小

// O(n) space:
// one n is the recursion stack
// another n is used when copying list
// Both of them depend on the longest solution which is equal to
// target/(min in candidates) in this problem(可以再看下上面的例子, n就是新
// arr中2的个数, 为ceil(10/2))
Read full article from LeetCode - Combination Sum | Darren's Blog

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