Showing posts with label difficulty 3. Show all posts
Showing posts with label difficulty 3. Show all posts

Saturday, October 12, 2013

Day 49, #127, #131, Word Ladder, Palindrome Partitioning

Word Ladder
Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:
  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.
Note:

  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
------------------------------------------------------------------------
typical BFS and shortest path
class Solution {
public:
    int ladderLength(string start, string end, unordered_set<string> &dict) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        if (start == end) return 1;
        queue<pair<string,int> > q;
        q.push(make_pair(start, 1)); // assign each node a distance
        unordered_set<string> used;
        while (!q.empty()) {
            string top = q.front().first;
            int length = q.front().second;
            q.pop();
            for (int index = 0; index < start.length(); index++ ) {
                for (int alp = 'a'; alp < 'z'; alp++) {
                    if (alp == top[index]) continue; // ignore the same letter
                    string temp = top;
                    temp[index] = alp;
                    if (temp == end) {
                        return length+1;
                    }
                    if (used.find(temp) == used.end() && dict.find(temp) != dict.end()) {
                        used.insert(temp);
                        q.push(make_pair(temp, length+1));
                    }
                    
                }
            }
        }
        return 0;
    }
};
Java,双向BFS, udpated on Aug-4th-2018
class Solution {
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        int len = 1;
        Map<String, Boolean> dic = getDic(wordList);
        if (!dic.containsKey(endWord)) return 0;
        
        dic.put(beginWord, false);
        dic.put(endWord, false);
        Set<String> begin = new HashSet<>();
        Set<String> end = new HashSet<>();
        begin.add(beginWord);
        end.add(endWord);
        
        while (!begin.isEmpty() && !end.isEmpty()) {
            if (begin.size() > end.size()) {
                Set<String> t = begin;
                begin = end;
                end = t;
            }
            
            len++;
            Set<String> temp = new HashSet<>();
            for (String s : begin) {
                for (int i = 0; i < s.length(); i++) {
                    char c = s.charAt(i);
                    for (char nextC = 'a'; nextC <= 'z'; nextC++) {
                        String next = s.substring(0, i) + nextC + s.substring(i + 1);

                        if (end.contains(next)) return len;

                        if (dic.containsKey(next) && dic.get(next)) {
                            temp.add(next);
                            dic.put(next, false);
                        }
                    }
                }
            }
            
            begin = temp;
        }
        
        return 0;
    }
    
    private Map<String, Boolean> getDic(List<String> wordList) {
        Map<String, Boolean> dic = new HashMap<>();
        
        for (String s : wordList) {
            dic.put(s, true);
        }
        
        return dic;
    }
}
Palindrome Partitioning
Given a string s, partition s such that every substring of the partition is a palindrome.
Return all possible palindrome partitioning of s.
For example, given s = "aab",
Return
  [
    ["aa","b"],
    ["a","a","b"]
  ]
-----------------------------------------
DFS, recursive
class Solution {
public:
    bool checkPalin (string s) {
        for (int i = 0; i < s.length()/2; i++) {
            int end = s.length() - 1 - i;
            if (s[i] != s[end]) {
                return false;
            }
        }
        return true;
    }
    
    void partition (string cur, vector<string> v, string remain,  vector<vector<string> >& ret) {
        if (remain.empty()) {
            ret.push_back(v);
            return;
        }
        
        for (int i = 0; i < remain.length(); i++) {
            cur += remain[i];
            if (checkPalin(cur)) {
                vector<string> cp = v; 
                cp.push_back(cur);
                partition("",cp,remain.substr(i+1),ret);
            }
        }
    }
    
    vector<vector<string>> partition(string s) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        vector<vector<string> > ret;
        vector<string> v;
        partition("",v,s,ret);
        return ret;
    }
};
Update on Oct-03-2014
Using index
class Solution {
public:
    bool isPal(string str) {
        for (int i = 0; i < str.length() / 2; i++) {
            if (str[i] != str[str.length() - 1 - i]) {
                return false;
            }
        }
        
        return true;
    }
    
    void dfs(vector<vector<string> > &rt, vector<string> cur, string s,int index) {
        if (index == s.length()) {
            rt.push_back(cur);
            return;
        }
        for (int i = 1; i < s.length() - index + 1; i++) {
            string sub = s.substr(index,i);    
            if (isPal(sub)) {
                vector<string> temp = cur;
                temp.push_back(sub);
                dfs(rt,temp,s,index + i);
            }
        }
    
    }
    
    vector<vector<string>> partition(string s) {
        vector<vector<string> > rt;
        vector<string> v;
        dfs(rt,v,s,0);
        return rt;
    }
};
Thoughts: we can add Memoization to improve efficiency. Set up a 2d-array of vector<vector<string> >, [i][j] contains all palindrome partitionings between i and j

Friday, October 11, 2013

Day 48, #116, #120, #123, Populating Next Right Pointers in Each Node, Triangle, Best Time to Buy and Sell Stock II

Populating Next Right Pointers in Each Node
Given a binary tree
    struct TreeLinkNode {
      TreeLinkNode *left;
      TreeLinkNode *right;
      TreeLinkNode *next;
    }
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.
Initially, all next pointers are set to NULL.
Note:
  • You may only use constant extra space.
  • You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).
For example,
Given the following perfect binary tree,

         1
       /  \
      2    3
     / \  / \
    4  5  6  7
After calling your function, the tree should look like:

         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \  / \
    4->5->6->7 -> NUL
-----------------------------------------------------------------
 typical level order tree traversal, can be implemented with either DFS or BFS
using an array to store the current tailing nodes, one slot for each level
/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void traverse (TreeLinkNode* root, int curlevel, vector<TreeLinkNode*>& v) {
        if (root == NULL) {
            return;
        } 
        if (v.size() < curlevel) {
            v.push_back(root);
        }else{
            v[curlevel-1]->next = root;
            v[curlevel-1] = root;
        }
        traverse(root->left,curlevel+1,v);
        traverse(root->right,curlevel+1,v);
    }
    
    void connect(TreeLinkNode *root) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        vector<TreeLinkNode*> v;
        traverse(root,1,v);
    }
};

constant space
/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void connect(TreeLinkNode *root) {
        while (root != NULL) {
            TreeLinkNode *pre = root;
            TreeLinkNode *before = NULL;
            while (pre != NULL && pre->left != NULL) {
                if (before != NULL) {
                    before->next = pre->left;
                }
                pre->left->next = pre->right;
                before = pre->right;
                pre = pre->next;
            }
            root = root->left;
        }
    }
};

Triangle

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).
Note:
Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.
--------------------------------------------
DP in place
replace each element in level #i with the possible minimum sum that are added from level #i+1
class Solution {
public:
    int minimumTotal(vector<vector<int> > &triangle) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        int size = triangle.size();
        for (int row = size - 2; row >= 0; row--) {
            for (int index = 0; index < triangle[row].size(); index++) {
                triangle[row][index] += min(triangle[row+1][index],triangle[row+1][index+1]);
            }
        }
        return triangle[0][0];
    }
};
Best Time to Buy and Sell Stock II
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
-----------------------------------------------------------------------
greedy
class Solution {
public:
    int maxProfit(vector<int> &prices) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        int sum = 0;
        for (int i = 1; i < prices.size(); i++) {
            int dif = prices[i] - prices[i - 1];
            if (dif > 0) {
                sum += dif;
            }
        }
        return sum;
    }
};

Day 47, #105, #106, #107, #114 Construct Binary Tree from Preorder and Inorder Traversal, Construct Binary Tree from Inorder and Postorder Traversal, Binary Tree Level Order Traversal II, Flatten Binary Tree to Linked List

Construct Binary Tree from Preorder and Inorder Traversal
Given preorder and inorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
-----------------------------------------------
Explaination 
Having a start and an end pointer for each array.
Using hash table to track the root position in inorder array.
For preorder array, the first in partition is always the root node, for inorder one, in a given partition, all nodes whose indexes are less than root's are belong to its left child, whose indexes are greater than root's, belongs to its right child
Same algorithm for Postorder and Inorder combination

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void hashMapping(vector<int> &inorder, unordered_map<int,int>& mapping){
        for (int i = 0; i < inorder.size(); i++) {
            int k = inorder[i];
            mapping[k] = i;
        }
    }
    
    TreeNode *rec(vector<int> &preorder, vector<int> &inorder, int startP, int endP, int startI, int endI,unordered_map<int,int>& mapping) {
        //if (endI < startI || endP < startP)return NULL;
        int rootIndex = mapping[preorder[startP]];
        TreeNode *root = new TreeNode(preorder[startP]);
        // delimiter for preorder
        int delimiterIndex = rootIndex - startI + startP; 
        if (rootIndex > startI) {
            root->left = rec(preorder,inorder,startP+1,delimiterIndex,startI,rootIndex - 1,mapping);
        }else {
            root->left=NULL;
        }
        if (rootIndex < endI) {
            root->right = rec(preorder,inorder,delimiterIndex + 1,endP,rootIndex + 1,endI,mapping);
        }else {
            root->right=NULL;
        }
        return root;
    }
    
    TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        if (preorder.size() == 0) return NULL;
        unordered_map<int,int> mapping;
        hashMapping(inorder,mapping);
        return rec(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1,mapping);
    }
};
Construct Binary Tree from Inorder and Postorder Traversal
Given inorder and postorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
-----------------------------
Similar to Preorder and Inorder combination
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void hashMapping(vector<int> &inorder, unordered_map<int,int>& mapping){
        for (int i = 0; i < inorder.size(); i++) {
            int k = inorder[i];
            mapping[k] = i;
        }
    }

    TreeNode *rec(vector<int> &postorder, vector<int> &inorder, int startP, int endP, int startI, int endI,unordered_map<int,int>& mapping) {
        //if (endI < startI || endP < startP)return NULL;
        int rootIndex = mapping[postorder[endP]];
        TreeNode *root = new TreeNode(postorder[endP]);
        // delimiter for postorder
        int delimiterIndex = rootIndex - startI + startP-1; 
        if (rootIndex > startI) {
            root->left = rec(postorder,inorder,startP,delimiterIndex,startI,rootIndex - 1,mapping);
        }else {
            root->left=NULL;
        }
        if (rootIndex < endI) {
            root->right = rec(postorder,inorder,delimiterIndex + 1,endP-1,rootIndex + 1,endI,mapping);
        }else {
            root->right=NULL;
        }
        return root;
    }

    TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        if (postorder.size() == 0) return NULL;
        unordered_map<int,int> mapping;
        hashMapping(inorder,mapping);
        return rec(postorder,inorder,0,postorder.size()-1,0,inorder.size()-1,mapping);
    }
};
Binary Tree Level Order Traversal II
Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root).
For example:
Given binary tree {3,9,20,#,#,15,7},

    3
   / \
  9  20
    /  \
   15   7
return its bottom-up level order traversal as:

[
  [15,7]
  [9,20],
  [3],
] 
----------------------------------
Similar to #102 Binary Tree Level Order Traversal
This is a DFS solution 
 
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    

vector<vector<int> > levelOrderBottom(TreeNode *root) {
    // Start typing your C/C++ solution below
    // DO NOT write int main() function
    vector<vector<int>> result;
    traverse(root, 1, result);
    std::reverse(result.begin(), result.end());
    return result;
}

void traverse(TreeNode *root, int level, vector<vector<int>> &result) {
    if (root == NULL) {
        return;
    }
    
    if (level > result.size()) {
        vector<int> v;
        result.push_back(v);
    }
    
    result[level-1].push_back(root->val);
    traverse(root->left,level+1,result);
    traverse(root->right,level+1,result);
}
};

Flatten Binary Tree to Linked List
Given a binary tree, flatten it to a linked list in-place.
For example,
Given
         1
        / \
       2   5
      / \   \
     3   4   6
The flattened tree should look like:
   1
    \
     2
      \
       3
        \
         4
          \
           5
            \
             6
----------------------------------------------------------
Solution #1, not in place, preorder traverse the tree, store each node in an array,

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void traverse (TreeNode *root, vector<TreeNode*>& v) {
        if (root != NULL) {
            v.push_back(root);
            traverse(root->left,v);
            traverse(root->right,v);
        }
    }

    void flatten(TreeNode *root) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        vector<TreeNode*> v;
        traverse(root,v);
        TreeNode *itr = root;
        for (int i = 1; i < v.size(); i++) {
            itr->right = v[i];
            itr->left = NULL;
            itr = itr->right;
        }
    }
};
Solution #2, in place iterative.
Same logic can be adopted in recursive implementation
O(n), 在inner loop里面,在整段代码的执行过程中每个node只出现过一次
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void flatten(TreeNode *root) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        TreeNode* ret = root;
        while (root != NULL) {
            if (root->left != NULL) {
                TreeNode *right = root->right;
                TreeNode *mostRight = root->left;
                
                while (mostRight->right != NULL) {
                    mostRight = mostRight->right;
                }
                mostRight->right = right;
                root->right = root->left;
                root->left = NULL;
            }
            root = root->right;
        }
        root = ret;
    }
};
Update on Sep-28-2014
Recursive solution, Pre-Order tree traversal
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* f(TreeNode *root, TreeNode *newRoot) {
        if (root == NULL) return newRoot;
        TreeNode *tempRight = root->right;
        newRoot->right = root;
        
        TreeNode *t = f(root->left,root); // return the end of list
        root->left = NULL;
        TreeNode *t2 = f(tempRight,t);
        return t2;
    }

    void flatten(TreeNode *root) {
        TreeNode *newRoot = root;
        TreeNode *dummy = new TreeNode(0);

        f(newRoot,dummy);
    }
};

Updated on Sep-24th-2018
跟上面类似思路,更易懂的写法。getEndOfList(root)返回以root为顶点的sub-tree转换成为list之后的最尾端的点
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {

    public void flatten(TreeNode root) {
        if (root == null) return;
        getEndOfList(root);
    }
    
    private TreeNode getEndOfList(TreeNode root) {

        TreeNode l = root.left;
        TreeNode r = root.right;
        if (root.left != null) {
            TreeNode end = getEndOfList(root.left);
            root.right = l;
            l = end;
            end.right = r;
            root.left = null;
        }
        
        if (r != null) {
            return getEndOfList(r);
        }
        if (l == null) {
            return root;
        }
        return l;   
    }
}

Thursday, September 19, 2013

Day 45, #98 Validate Binary Search Tree

Validate Binary Search Tree
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
  • The left subtree of a node contains only nodes with keys less than the node's key.
  • The right subtree of a node contains only nodes with keys greater than the node's key.
  • Both the left and right subtrees must also be binary search trees.
---------------------------------------------------
Perform an in-order tree traversal, save all values in an array, and later check if it is sorted
There is room for space optimization in solution below
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void rec (TreeNode *root, vector<int> &v) {
        if (root->left != NULL) {
            rec(root->left,v);
        }
        v.push_back(root->val);
        if (root->right != NULL) {
            rec(root->right,v);
        }
    }

    bool isValidBST(TreeNode *root) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (root == NULL) return true; 
        vector<int> v;
        rec(root,v);
        if (v.size() < 2) {
            return true;
        }
        // check if it's already sorted
        for (int i = 1; i < v.size(); i++) {
            if (v[i-1] >= v[i]) {
                return false;
            }
        }
        return true;
    }
};
Update: Jan-16-2014
http://leetcode.com/2010/09/determine-if-binary-tree-is-binary.html
Solution#2, in space.
Note int &pre in arguments
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool inorder (TreeNode *root, int &pre) {
       if (root == NULL) {
           return true;
       }
       if (inorder(root->left,pre)) {
           if (pre >= root->val) {
               return false;
           }
           pre = root->val;
           return inorder(root->right,pre);
       }
       return false;
       
    }

    bool isValidBST(TreeNode *root) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (root == NULL) return true; 
        int pre = INT_MIN;
        return inorder(root,pre);
    }
};

Update: Jan-15-2015
to handle INT_MIN case
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool inorder(TreeNode *root, TreeNode *&pre) {
        if (root == NULL) {
            return true;
        }
        
        if (inorder(root->left,pre)) {
            if (pre != NULL && pre->val >= root->val) {
                return false;
            }
            pre = root;
            return inorder(root->right,pre);
            
        }
        
        return false;
    }

    bool isValidBST(TreeNode *root) {
        TreeNode *pre = NULL;
        return inorder(root,pre);
    }
};

Java, updated Jun-24th-2018
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    private TreeNode pre = null;
    public boolean isValidBST(TreeNode root) {
        if (root == null) return true;
        if (!isValidBST(root.left)) {
            return false;
        }
        
        if (pre == null) pre = root;
        else if (pre.val >= root.val) {
            return false;
        }
        pre = root;
        return isValidBST(root.right);
    }
}

当有node的值等于MIN_VALUE或MAX_VALUE, 这算法就搞不定了。所有还是别用了
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isValidBST(TreeNode root) {
        return helper(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
    }
    
    private boolean helper(TreeNode root, int min, int max) {
        if (root == null) return true;
        if (root.val < max && root.val > min) {
            return helper(root.left, min, root.val) 
                && helper(root.right, root.val, max);
        }
        
        return false;
    }
}

Wednesday, September 11, 2013

Day 44, #96 Unique Binary Search Trees

Unique Binary Search Trees
Given n, how many structurally unique BST's (binary search trees) that store values 1...n?
For example,
Given n = 3, there are a total of 5 unique BST's.
   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3 
-------------------------------------------------
Catalan Number 
COME_BACK


class Solution {
public:
    int numTrees(int n) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int ret = 1;
        for (int i = 2; i <= n; i++) {
            ret = 2*(2*i-1)*ret/(i+1);
        }
        return ret;
    }
};
DP
class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n + 1,0);
        dp[0] = dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            for (int j = 0; j < i; j++) {
                dp[i] += dp[j] * dp[i - j - 1];
            }
        }
        return dp[n];
    }
};

Thursday, September 5, 2013

Day 43, #93 Restore IP Addresses

Restore IP Addresses
Given a string containing only digits, restore it by returning all possible valid IP address combinations.
For example:
Given "25525511135",
return ["255.255.11.135", "255.255.111.35"]. (Order does not matter)
----------------------------------------------------
DFS

class Solution {
public:
    int stringToInt (string s) {
        int num = 0;
        for (int i = 0; i < s.length(); i++) {
            num = num * 10;
            int temp  = s[i] - '0';
            num = num + temp;
        }
        return num;
    }

    void rec (string cur, string s, int count, vector<string> &ret) {
        if (s.length() == 0 && count == 4) {
            ret.push_back(cur);
        }else if (count < 4 && s.length() != 0) {
            if (count != 0) { // no '.' before the first part 
                cur = cur + ".";
            }
            string temp;
            if (s.length() >= 1) {
                temp = cur + s[0];
            rec(temp,s.substr(1),count+1,ret);
            }
            if (s.length() >= 2 && s[0] != '0') {
                temp = cur + s.substr(0,2);
            rec(temp,s.substr(2),count+1,ret);
            }
            if (s.length() >= 3 && s[0] != '0') {
                temp = cur + s.substr(0,3);
                if (stringToInt(s.substr(0,3)) < 256) {
                    rec(temp,s.substr(3),count+1,ret);
                }
            }
        }
        
    }

    vector<string> restoreIpAddresses(string s) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        vector<string> ret;
        rec("",s,0,ret);
        return ret;
        
    }
};
Update on Sep-21-2014 
Same algorithm but with index
class Solution {
public:
    void rec(vector<string> &rt, string s, int index, int count,string ip) {
        if (count == 4 && index == s.length()) {
            rt.push_back(ip);
            return;
        }
        
        if (count > 4 || index > s.length()) return;
        
        if (count != 0) {
            ip += "."; 
        }
        
        rec(rt,s,index + 1, count + 1, ip + s.substr(index,1));
        
        if (index + 1 < s.length() && s[index] != '0') {
            string sub = s.substr(index,2);
            rec(rt,s,index + 2, count + 1, ip + sub);
        }
        
        if (index + 2 < s.length() && s[index] != '0') {
            string sub = s.substr(index,3);
            if (stoi(sub) < 256) {
                rec(rt,s,index + 3, count + 1, ip + sub);
            }
        }
        
    }

    vector<string> restoreIpAddresses(string s) {
        vector<string> rt;
        if (s == "") return rt;
        rec(rt,s,0,0,"");
        
        return rt;
    }
};

Wednesday, August 28, 2013

Day 42, #92, #109, Reverse Linked List II, Convert Sorted List to Binary Search Tree

Reverse Linked List II
Reverse a linked list from position m to n. Do it in-place and in one-pass.
For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,
return 1->4->3->2->5->NULL.
Note:
Given m, n satisfy the following condition:
1 ? m ? n ? length of list.
----------------------------------------
lets say m = 3, n = 5
1             2              3             4             5            6
|              |                |                             |
head      left           tail                     newHead

/* Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *reverseBetween(ListNode *head, int m, int n) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        ListNode *newHead = NULL, *itr = head,*left = NULL,*tail;
        // move to m-th node
        for (int i = 1; i < m; i++) {
            left = itr;
            itr = itr->next;
        }
        tail = itr;
        // move to n-th node
        for (int i = m; i <= n; i++) {
            ListNode *temp = itr->next;
            itr->next = newHead;
            newHead = itr;
            itr = temp;
        }
        tail->next = itr;
        if (m == 1) {
            return newHead;
        }
        left->next = newHead;
        return head;
    }
};
Convert Sorted List to Binary Search Tree
Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.
--------------------------------------------------------------------------
Further reading:
http://leetcode.com/2010/11/convert-sorted-list-to-balanced-binary.html
http://www.geeksforgeeks.org/sorted-linked-list-to-balanced-bst/
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* constructTree (ListNode *&list,int start, int end) {
        if (start > end) {
            return NULL;
        }
        int mid = start + (end - start) / 2;
        TreeNode *left = constructTree(list,start,mid - 1);
        TreeNode *root = new TreeNode(list->val);
        root->left = left;
        list = list->next;
        root->right = constructTree(list,mid + 1, end);
        return root;
    }


    TreeNode *sortedListToBST(ListNode *head) {
        int n = 0;
        ListNode *itr = head;
        while (itr != NULL ) {
            n++;
            itr = itr->next;
        }
        return constructTree(head,0,n-1);
    }
};
Update Nov-21-2014
Bottom up solution. For each node, build the left child -> root -> right child, follow the in order sequence

Monday, August 26, 2013

Day 41, 91 Decode Ways

Decode Ways
A message containing letters from A-Z is being encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.
For example,
Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12).
The number of ways decoding "12" is 2.
------------------------------------------------
similar to steps problem, with some extra conditions
Solution #1 simple recursion
class Solution {
public:
    int numDecodings(string s) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (s.length() == 0 || s[0] == '0') return 0;
        if (s.length() == 1) return 1;
        int fix = 0;
        if (s.length() == 2) {
            fix = 1;
        }
        if (s[0] == '1' || (s[0] == '2' && s[1] < '7')) {
            return numDecodings(s.substr(1)) + numDecodings(s.substr(2)) + fix;
        }
        return numDecodings(s.substr(1));
    }
};
Solution #2 DP
class Solution {
public:
    int numDecodings(string s) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (s.length() == 0 || s[0] == '0') {
            return 0;
        }
        vector<int> ways(s.length() + 1, 1);
        for (int i = s.length() - 1; i >= 0; i--) {
            if (s[i] == '0') {
                ways[i] = 0;
            }else {
                ways[i] = ways[i+1];
            }
            if (i+1 < s.length() && (s[i] == '1' || (s[i] == '2' && s[i+1] < '7'))) {
                ways[i] += ways[i+2];
            }
        }
        return ways[0];
    }
};

In Java, recursion with memoization
class Solution {
    private Map<String, Integer> map = new HashMap<>();
    public int numDecodings(String s) {
        if (s.length() == 0 || s.charAt(0) == '0') return 0;
        if (s.length() == 1) {
            return 1;
        }
        
        int i = 0;
        String s1 = s.substring(1);
        if (map.containsKey(s1)) {
            i = map.get(s1);
        }else {
            i = numDecodings(s.substring(1)); 
            map.put(s.substring(1), i);
        }
        
        if (s.charAt(0) == '1' || (s.charAt(0) == '2' && s.charAt(1) < '7')) {
            
            String s2 = s.substring(2);
            int j = 0;
            
            if (map.containsKey(s2)) {
                j = map.get(s2);
            }else {
                j = numDecodings(s2); 
                map.put(s2, j);
            }
            
            int rt = 0;
            if (s.length() == 2) rt = 1;
            return i + j + rt;
        }
        
        return i;
    }
}

COME_BACK
写一下O(1) 空间复杂度

Thursday, July 11, 2013

Day 40, 86 Partition List

Partition List
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of the nodes in each of the two partitions.
For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
---------------------------------------------------------------------
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *partition(ListNode *head, int x) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (head == NULL) return head;
        ListNode *leftHead = NULL, *rightHead = NULL, *end;
        ListNode ** before = &leftHead, **after = &rightHead;
        while (head != NULL) {
            if (head->val >= x) {
                *after = head;
                after = &(head->next);
            }else {
                *before = head;
                before = &(head->next);
            }
            // use end to break the new attached node from the original list
            end = head;
            head = head->next;
            end->next = NULL;
        }
        *before = rightHead; // connect two lists
        return leftHead;
    }
};
Update on Sep-19-2014 
Without double-pointer
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *partition(ListNode *head, int x) {
        ListNode *head1 = NULL, *head2 = NULL,*tail1 = NULL,*tail2 = NULL;
        
        while (head != NULL) {
            if (head->val < x) {
                if (head1 == NULL) {
                    head1 = head;
                    tail1 = head;
                }else {
                    tail1->next = head;
                    tail1 = tail1->next;
                }
            }else {
                
                if (head2 == NULL) {
                    head2 = head;
                    tail2 = head;
                }else {
                    tail2->next = head;
                    tail2 = tail2->next;
                }
            }
            head = head->next;
        }
        
        // merge
        if (tail1 != NULL) tail1->next = head2;
        if (tail2 != NULL) tail2->next = NULL;
        if (head1 == NULL) return head2;
        return head1;
    }
};

Sunday, July 7, 2013

Day 39, 79, 82 Word Search, Remove Duplicates from Sorted List II

Word Search
Given a 2D board and a word, find if the word exists in the grid.
The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.
For example,
Given board =
[
  ["ABCE"],
  ["SFCS"],
  ["ADEE"]
]
word = "ABCCED", -> returns true,
word = "SEE", -> returns true,
word = "ABCB", -> returns false.
----------------------------------------------
class Solution {
public:
    bool searchWord (vector<vector<char> > &board, string word, int cur, int row, int col,vector<vector<bool> > &mapping) {
        int rowSize = board.size();
        int colSize = board[0].size();
        if (word.size() == cur) return true; 
        if (word.size() > cur) {
            if (row > 0 && mapping[row-1][col] && word[cur] == board[row-1][col]) {
                mapping[row-1][col] = false;
                if (searchWord(board,word,cur+1,row-1,col,mapping)) {
                    return true;
                }
                mapping[row-1][col] = true;
            }
            if (row < rowSize-1 && mapping[row+1][col] && word[cur] == board[row+1][col]) {
                mapping[row+1][col] = false;
                if (searchWord(board,word,cur+1,row+1,col,mapping)) {
                    return true;
                }
                mapping[row+1][col] = true;
            }
            if (col < colSize-1 && mapping[row][col+1] && word[cur] == board[row][col+1]) {
                mapping[row][col+1] = false;
                if (searchWord(board,word,cur+1,row,col+1,mapping)) {
                    return true;
                }
                mapping[row][col+1] = true;
            }
            if (col > 0 && mapping[row][col-1] && word[cur] == board[row][col-1]) {
                mapping[row][col-1] = false;
                if (searchWord(board,word,cur+1,row,col-1,mapping)) {
                    return true;
                }
                mapping[row][col-1] = true;
            }
        }
        return false;
    }

    bool exist(vector<vector<char> > &board, string word) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int rowSize = board.size();
        int colSize = board[0].size();
        vector<vector<bool>> mapping(rowSize, vector<bool>(colSize, true));
        for (int i=0;i<rowSize;i++) {
            for (int j=0;j<colSize;j++) {
                if (board[i][j] == word[0]) {
                    mapping[i][j] = false;
                    if (searchWord(board,word,1,i,j,mapping)) return true;
                    mapping[i][j] = true;
                }
            }
        }
        return false;
    }
};

更新
class Solution {
public:
    bool searchWord(vector<vector<char>>& board, string word,vector<vector<bool>> &visit,int index,int row,int col) {
        if (index == word.length()) return true;
        if (row < 0 || row >= board.size() || col < 0 || col >= board[0].size() 
                || visit[row][col] || word[index] != board[row][col]) {
            return false;
        }
        visit[row][col] = true;
        
        if(searchWord(board,word,visit,index + 1,row + 1,col)
            || searchWord(board,word,visit,index + 1,row - 1,col)
            || searchWord(board,word,visit,index + 1,row,col + 1)
            || searchWord(board,word,visit,index + 1,row,col - 1)) {
            return true;
        }
        visit[row][col] = false;
        return false;
    }


    bool exist(vector<vector<char>>& board, string word) {
        int rowSize = board.size();
        int colSize = board[0].size();
        vector<vector<bool>> mapping(rowSize, vector<bool>(colSize, false));
        for (int i=0; i<rowSize; i++) {
            for (int j=0; j<colSize; j++) {
                if (board[i][j] == word[0]) {
                    if (searchWord(board,word,mapping,0,i,j)) return true;
                }
            }
        }
        return false;
    }
};

BFS理论上可行,但是需要记录太多信息 - 每个点的坐标,当前word的index,和一个额外的(独立的)visit的map。特别是这个map,因为不能backtracking,所有每条path都需要自己独立的map

Remove Duplicates from Sorted List II
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.
----------------------------------------------------------------------
Solution #1, iterative

watch out for the tailing number(s)
1,2,2 // cut off
1,2,2,3 // re-attach
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *deleteDuplicates(ListNode *head) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (head == NULL || head->next == NULL) return head;
        ListNode *ret = NULL, *itr = head->next,*cur = head;
        ListNode **pre = &ret;  // a pointer to a pointer
        while (itr != NULL) {
            if (cur->val != itr->val) {
                if (cur->next == itr) {
                    *pre = cur;
                    pre = &(cur->next);
                    cur = cur->next;
                }else {
                    cur = itr;
                }
            }
            itr = itr->next;
        }
        if (cur->next == NULL) {  // include it if the last one is singular
            *pre = cur;
        }else {  // otherwise, leave out the rest of the list 
            *pre = NULL;
        }
        return ret;
    }
};
Solution #2 from internet, recursive
ListNode *deleteDuplicates(ListNode *head) {
    // Start typing your C/C++ solution below
    // DO NOT write int main() function

    // base case, 0, or 1 item in the list
    if (head == NULL || head->next == NULL) return head;        
    ListNode *ret=NULL;
    ListNode *cur = head;
    int dup=0;

    // remove duplicated values from head
    while (cur->next != NULL && cur->val == cur->next->val)
    {
        ListNode *t=cur;
        cur=cur->next;
        delete(t);
        dup = 1;
    }

    if (!dup)
    {
        ret = cur;
        cur->next = deleteDuplicates(cur->next);            
    }
    else
    {
        ret = deleteDuplicates(cur->next);
    }    
    return ret;        
}


Update on Sep-18-2014
A simpler version of solution #1
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *deleteDuplicates(ListNode *head) {
        if (head == NULL || head->next == NULL) return head;
        ListNode *dummy = new ListNode(INT_MIN);
        dummy->next = head;
        ListNode *pre = dummy;
        
        while (head != NULL && head->next != NULL) {
            if (head->val != head->next->val) {
                pre = head;
                head = head->next;
            }else {
                while (head->next != NULL && head->val == head->next->val) {
                    head = head->next;
                }
                pre->next = head->next;
                head = head->next;
            }
            
        }
        
        return dummy->next;
    }
};

Tuesday, June 18, 2013

Day 38, 77, 78 Combinations, Subsets

Combinations
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
For example,
If n = 4 and k = 2, a solution is:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
--------------------------------------------------------
combination, note that in this case, [1,2] and [2,1] are considered the same
we can use a stack instead of vector for vector<int> num
class Solution {
public:
    void comb (vector<vector<int> >&ret, vector<int> num, vector<int> cur, int k) {
        if (k == 0) {
            ret.push_back(cur);
        }else {
            int size = num.size(); 
            for (int i=0;i<size;i++) {
                vector<int> temp = cur;
                temp.push_back(num[0]);
                num.erase(num.begin());
                comb(ret,num,temp,k-1);
            }
        }
    }

    vector<vector<int> > combine(int n, int k) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        vector<int> num(n);
        for (int i=0;i<n;i++) {
            num[i] = 1+i;
        }
        vector<int> cur;
        vector<vector<int> > ret;
        comb(ret,num,cur,k);
        return ret;
    }
};
Update on Sep-16-2014
class Solution {
public:
    void comb (vector<vector<int> > &rt, vector<int> cur, int n, int k, int index) {
        if (k == 0) {
            rt.push_back(cur);
            return;
        }
        
        for (int i = index; i <= n + 1 - k; i++) {
            vector<int> temp = cur;
            temp.push_back(i);
            comb(rt,temp,n,k - 1,i + 1);
        }
    }

    vector<vector<int> > combine(int n, int k) {
        vector<vector<int> > rt;
        vector<int> v;
        comb(rt,v,n,k,1);
        return rt;
    }
};

同subsets的bit operation的方法
class Solution {
public:
    void helper(vector<vector<int>> &rt,vector<int> cur, int n, int k, int index) {
        if (k == 0) {
            rt.push_back(cur);
            return;
        }
        if (k < 0 || index > n) return;
        
        helper(rt,cur,n,k,index + 1);
        cur.push_back(index);
        helper(rt,cur,n,k - 1,index + 1);
    }

    vector<vector<int>> combine(int n, int k) {
        vector<vector<int> > rt;
        vector<int> cur;
        helper(rt,cur,n,k,1);
        
        return rt;
    }
};


Subsets
Given a set of distinct integers, S, return all possible subsets.
Note:
  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.
For example,
If S = [1,2,3], a solution is:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
--------------------------------------------------
Solution #1 recursive, Combination
class Solution {
public:
    void sub (vector<vector<int> > &ret, vector<int> S, vector<int> cur) {
        if (S.size() != 0) {
            int size = S.size();
            for (int i=0;i<size;i++) {
                vector<int> temp = cur;
                temp.push_back(S[0]);
                S.erase(S.begin());
                ret.push_back(temp);
                sub(ret,S,temp);
            }
        }
    }

    vector<vector<int> > subsets(vector<int> &S) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        sort(S.begin(),S.end());
        vector<vector<int> > ret;
        vector<int> cur;
        ret.push_back(cur);
        sub(ret,S,cur);
        return ret;
    }
};
Update on Sep-17-2014
class Solution {
public:
    void sub(vector<vector<int> > &rt, vector<int> cur, vector<int> S, int index) {
        rt.push_back(cur);
        
        for (int i = index; i < S.size(); i++) {
            vector<int> temp = cur;
            temp.push_back(S[i]);
            sub(rt,temp,S,i + 1);
        }
    }

    vector<vector<int> > subsets(vector<int> &S) {
        sort(S.begin(),S.end());
        vector<vector<int> > rt;
        vector<int> v;
        sub(rt,v,S,0);
        
        return rt;
    }
};
Update on Nov-01-2014
Solution #2, Bitmap
For each S it has 2^S.size() subsets and each for loop iteration generates one subset
1 2 3
------
0 0 0
0 0 1
0 1 0
0 1 1
...
class Solution {
public:
    vector<vector<int> > subsets(vector<int> &S) {
        int numOfSubsets = 1 << S.size();
        sort(S.begin(),S.end());
        vector<vector<int> > rt;
        
        for (int i = 0; i < numOfSubsets; i++) {
            int pos = 0;
            int bitMask = i;
            vector<int> sub;
            
            while (bitMask > 0) {
                if ((bitMask & 1) == 1) {
                    sub.push_back(S[pos]);
                }
                bitMask >>= 1;
                pos++;
            }
            rt.push_back(sub);
        }
        
        return rt;
    }
};

Update on Nov-18-2014
Solution #3 iterative
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int> > rt;
        vector<int> cur;
        rt.push_back(cur);
        sort(nums.begin(),nums.end());
        
        for (int i = 0; i < nums.size(); i++) {
            vector<vector<int> > temp = rt;
            for (int j = 0; j < temp.size(); j++) {
                temp[j].push_back(nums[i]);
                rt.push_back(temp[j]);
            }
        }
        
        return rt;
    }
};




Update on July-5th-2015
每个数字都可以为 “有” 或 “无”
class Solution {
public:
    void helper(vector<vector<int> > &rt, vector<int> nums, vector<int> cur,int index) {
        if (index == nums.size()) {
            rt.push_back(cur);
            return;
        }
        
        helper(rt,nums,cur,index + 1);
        cur.push_back(nums[index]);
        helper(rt,nums,cur,index + 1);
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<vector<int> > rt;
        vector<int> cur;
        helper(rt,nums,cur,0);
        
        return rt;
    }
};

ToDo, 以上所有解法要再看一次

Monday, June 17, 2013

Day 37, 74 Search a 2D Matrix

Search a 2D Matrix
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.
For example,
Consider the following matrix:
[
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
Given target = 3, return true.
-------------------------------------------------------------
Do 2 binary searches
Note that start <= end
Searching a 2D Sorted Matrix Part
class Solution {
public:
    bool searchMatrix(vector<vector<int> > &matrix, int target) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
       // return false;
        int m = matrix.size();
        int n = matrix[0].size();
        int start = 0, end = m-1;
        if(target< matrix[0][0]) return false;  
        // binary search the first element of each row
        while (start <= end) {
            int mid = (start + end) / 2;
            if (matrix[mid][0] == target) {
                return true;
            }
            if (matrix[mid][0] > target) {
                end = mid - 1;
            }else {
                start = mid + 1;
            }
        }
        // binary search in that particular row
        int row = end;
        start = 0;
        end = n-1;
        while (start <= end) {
            int mid = (start + end) / 2; 
            if (matrix[row][mid] == target) {
                return true;
            }
            if (matrix[row][mid] > target) {
                end = mid - 1;
            }else {
                start = mid + 1;
            }
        }
        return false;
    }
};

Friday, June 14, 2013

Day 36, 71,73 Simplify Path, Set Matrix Zeroes

Simplify Path
Given an absolute path for a file (Unix-style), simplify it.
For example,
path = "/home/", => "/home"
path = "/a/./b/../../c/", => "/c"
Corner Cases:
  • Did you consider the case where path = "/../"?
    In this case, you should return "/".
  • Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/".
    In this case, you should ignore redundant slashes and return "/home/foo".
 -------------------------------------------------
Solution #1, using stack
'/' skip
'.' ignore/continue
'..' pop stack

class Solution {
public:
    string simplifyPath(string path) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int i=0;
        stack<string> s;
        while (i < path.length()) {
            while (path[i] == '/' && i < path.length()) { // skip '/'
                 i++;
            }
            if (i == path.length())  break; // if string ends wiht '/'
            int start = i;
            while (path[i] != '/' && i < path.length()) { // get end point of sub path
                i++;
            }
            string elem = path.substr(start,i - start);
            if (elem == ".") {
                continue;
            }
            if (elem == "..") {
                if (!s.empty()) {
                    s.pop();
                }
                continue;
            }
            s.push(elem);
        }
        if (s.empty()) {
            return "/";
        }
        string ret;
        while (!s.empty()) {
            string temp = "/" + s.top();
            ret = temp + ret; 
            s.pop();
        }
        return ret;
    }
};
Solution #2, using two/three pointers
to be continued
  
Set Matrix Zeroes
Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.
Follow up: Did you use extra space?
A straight forward solution using O(mn) space is probably a bad idea.
A simple improvement uses O(m + n) space, but still not the best solution.
Could you devise a constant space solution?
---------------------------------------
Solution #1, O(m+n) space 
class Solution {
public:
    void setZeroes(vector<vector<int> > &matrix) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int m = matrix.size();
        int n = matrix[0].size();
        vector<bool> row(m,false);
        vector<bool> col(n,false);
        if (m != 1 || n != 1) {
            // find 0
            for (int i=0;i<m;i++) {
                for (int j=0;j<n;j++) {
                    if (matrix[i][j] == 0) {
                        row[i] = true; 
                        col[j] = true;
                    }
                }
            }
            // set to 0
            for (int i=0;i<m;i++) {
                for (int j=0;j<n;j++) {
                    if (row[i] || col[j]) {
                        matrix[i][j] = 0;
                    }
                }
            }
        }
    }
};
Solution #2, in space
instead of allocating two vectors, using the first row and column to store the zero row/col
class Solution {
public:
    void setZeroes(vector<vector<int> > &matrix) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        bool rowZero = false, colZero = false;
        int rows = matrix.size();
        int cols = matrix[0].size();
        // check first row
        for (int i=0;i<cols;i++) {
            if (matrix[0][i] == 0) {
                rowZero = true;
            }
        }
        // check first column
        for (int i=0;i<rows;i++) {
            if (matrix[i][0] == 0) {
                colZero = true;
            }
        }
        
        for (int i=1;i<rows;i++) {
            for (int j=1;j<cols;j++) {
                if (matrix[i][j] == 0) {
                    matrix[0][j] = 0;
                    matrix[i][0] = 0;
                }
            }
        }
        
        for (int i=1;i<rows;i++) {
            for (int j=1;j<cols;j++) {
                if (matrix[0][j] == 0 || matrix[i][0] == 0) {
                    matrix[i][j] = 0;
                }
            }
        }
        // if first row has 0
        if (rowZero) {
            for (int i=0;i<cols;i++) {
                matrix[0][i] = 0;
            }
        }
        // if first col has 0
        if (colZero) {
            for (int i=0;i<rows;i++) {
                matrix[i][0] = 0;
            }
        }
    }
};

Saturday, June 8, 2013

Day 35, 64 Minimum Path Sum

Minimum Path Sum
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
-------------------------------------------
Solution #1, Memoization
matrix[i][j] = min(matrix[i][j-1],matrix[i-1][j]) + grid[i][j] 
class Solution {
public:
    int minP (vector<vector<int> > &grid, int row, int col,vector<vector<int> > &mapping) {
        if (mapping[row][col] != -1) {
            return mapping[row][col];
        }
        if (row == 0 && col == 0) {
            mapping[row][col] = grid[0][0];
            return mapping[row][col];
        }
        if (row != 0 && col != 0) {
           mapping[row][col] = min(minP(grid,row-1,col,mapping) + grid[row][col],
                                minP(grid,row,col-1,mapping) + grid[row][col]);
            return mapping[row][col];
        }
        if (row == 0) {
            mapping[row][col] = minP(grid,0,col-1,mapping) + grid[0][col];
            return mapping[row][col];
        }
        mapping[row][col] = minP(grid,row-1,0,mapping) + grid[row][0];
        return mapping[row][col];
    }
    
    int minPathSum(vector<vector<int> > &grid) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int m = grid.size()-1;
        int n = grid[0].size()-1;
        vector<vector<int> > mapping(m+1);
        for (int i=0;i<m+1;i++) {
            vector<int> v(n+1);
            for (int j=0;j<n+1;j++) {
                v[j] = -1;
            }
            mapping[i] = v;
        }
        return minP(grid,m,n,mapping);
    }
};
Solution #2, DP O(n) space
matrix[i][j] = min(matrix[i][j-1],matrix[i-1][j]) + grid[i][j]
class Solution {
public:
    int minPathSum(vector<vector<int> > &grid) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int m = grid.size();
        int n = grid[0].size();
        vector<int> dp(n+1,INT_MAX);
        dp[1] = 0;
        for (int i=0;i<m;i++) {
            for (int j=0;j<n;j++) {
                dp[j+1] = min(dp[j+1],dp[j]) + grid[i][j];
            }
        }
        return dp[n];
    }
};
因为是minimum,所以dp初始为INT_MAX,如果是maximum,则设为INT_MIN
可先做2d-array的dp,再转化为1d. 注意dp[1] = 0
follow up:增加可以往左
Google interview questions #2 第5题

Friday, June 7, 2013

Day 34, 59, 61,63 Spiral Matrix II, Rotate List, Unique Paths II

Spiral Matrix II
Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order.
For example,
Given n = 3,
You should return the following matrix:
[
 [ 1, 2, 3 ],
 [ 8, 9, 4 ],
 [ 7, 6, 5 ]
]
--------------------------------------
Solution #1 straightforward, follow spiral's track, O(n)
class Solution {
public:
    vector<vector<int> > generateMatrix(int n) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        vector<vector<int> > ret(n);
        if (n == 0) return ret;
        if (n == 1) {
            vector<int> v(1);
            v[0] = 1;
            ret[0] = v;
            return ret;
        }
        for (int i=0;i<n;i++) {
            vector<int> row(n);
            for (int j=0;j<n;j++) {
                row[j] = 0;
            }
            ret[i] = row;
        }
        int row=0,col=0,index=1;  
        while (ret[row][col] == 0) {
            // right
            while (col < n && ret[row][col] == 0) {
                ret[row][col] = index;
                index++;
                col++;
            }
            col--;
            row++;
            // down
            while (row < n && ret[row][col] == 0) {
                ret[row][col] = index;
                index++;
                row++;
            }
            row--;
            col--;
            // left
            while (col >= 0 && ret[row][col] == 0) {
                ret[row][col] = index;
                index++;
                col--;
            }
            col++;
            row--;
            // up
            while (row >= 0 && ret[row][col] == 0) {
                ret[row][col] = index;
                index++;
                row--;
            }
            row++;
            col++;
        }
        return ret;
    }
};
Update on Sep-13-2014
Solution #2
Go google it


Rotate List
Given a list, rotate the list to the right by k places, where k is non-negative.
For example:
Given 1->2->3->4->5->NULL and k = 2,
return 4->5->1->2->3->NULL.
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *rotateRight(ListNode *head, int k) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (head == NULL || k == 0) return head;
        ListNode *cur=head, *end=head;
        int count=1;
        while (end->next != NULL) {
            count++;
            end = end->next;
        }
        k = k % count;
        if (k == 0) return head;
        for (int i=0;i<count-k-1;i++) {
            cur = cur->next;
        }
        ListNode *ret = cur->next;
        end->next = head;
        cur->next = NULL;
        return ret;
    }
};
Unique Paths II
Follow up for "Unique Paths":
Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and empty space is marked as 1 and 0 respectively in the grid.
For example,
There is one obstacle in the middle of a 3x3 grid as illustrated below.
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
The total number of unique paths is 2.
Note: m and n will be at most 100.
-----------------------------------
DP, based on unique path I
class Solution {
public:
    int uniquePathsWithObstacles(vector > &obstacleGrid) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int matrix[101][101] = {0};
        int m = obstacleGrid.size() - 1;
        int n = obstacleGrid[0].size() - 1;
        matrix[m+1][n] = 1;
        for (int i=m;i>=0;i--) {
            for (int j=n;j>=0;j--) {
                if (obstacleGrid[i][j] == 0) {
                    matrix[i][j] = matrix[i+1][j] + matrix[i][j+1];
                }
            }
        }
        return matrix[0][0];
    }
};
Update on Sep-14-2014
Consider the case when matrix[m + 1][n] or matrix[m][n + 1] has an obstacle

O(n) space
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m = obstacleGrid.size(), n = obstacleGrid[0].size();
        vector<int> dp(n + 1,0);
        if (obstacleGrid[m - 1][n - 1] == 1) return 0;
        dp[n - 1] = 1;
        
        for (int i = m - 1; i >= 0; i--) {
            for (int j = n - 1; j >= 0; j--) {
                if (obstacleGrid[i][j] == 1) {
                    dp[j] = 0;
                }else {
                    dp[j] += dp[j + 1];
                }
            }
        }
        return dp[0];
    }
};

Wednesday, June 5, 2013

Day 33, 49, 50,53,55, Anagrams, Pow(x, n), Maximum Subarray,Jump Game

Anagrams
Given an array of strings, return all groups of strings that are anagrams.
Note: All inputs will be in lower-case.
---------------------
Solution#1, hashing
class Solution {
public:    
    vector<string> anagrams(vector<string> &strs) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        unordered_map<string,string> mapping;
        vector<string> ret;
        for (int i=0;i<strs.size();i++) {
            string str = strs[i];
            sort(str.begin(),str.end());
            if (!mapping.count(str)) {
                mapping[str] = strs[i];
            }else {
                if (find(ret.begin(),ret.end(),mapping[str]) == ret.end()) {
                    ret.push_back(mapping[str]);
                }
                ret.push_back(strs[i]);
            }
        }
        return ret;
    }
};
Solution#2, optimized running time, trader off with extra space
class Solution {
public:   
    vector<string> anagrams(vector<string> &strs) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        unordered_map<string,string> mapping;
        unordered_map<string,bool> put; // to record if string has been put in result array
        vector<string> ret;
        
        for (int i=0;i<strs.size();i++) {
            string str = strs[i];
            sort(str.begin(),str.end());
            if (mapping.find(str) == mapping.end()) {
                mapping[str] = strs[i];
                put[strs[i]] = false;
            }else {
                if (put[mapping[str]] == false) {
                    ret.push_back(mapping[str]);
                    put[mapping[str]] = true;
                }
                put[strs[i]] = true;
                ret.push_back(strs[i]);
            }
        }
        return ret;
    }
};
Pow(x, n)
Implement pow(x, n).
-------------------------------
log(n) recursive solution
class Solution {
public:
    double pow(double x, int n) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (n == 0) {
            return 1;
        }
        if (n == 1) {
            return x;
        }
        if (n == -1) {
            return 1/x;
        }
        double result = pow(x,n/2);
        double extra = 1;
        if (n%2 == -1) {
            extra = 1/x;
        }else if (n%2 == 1) {
            extra = x;
        }
        return result * result * extra;
    }
};
bit shift, iterative solution, watch out for casting from internet
proof:
2^4 = 4^2 = 16^1
5^6 = 25^3 = 25^2 * 25 = 625^1 * 25
class Solution {
public:
    double pow(double x, int n) {
        unsigned m = abs((double)n);
        double ret = 1;
        for ( ; m; x *= x, m >>= 1) {
            if (m & 1) {
                ret *= x;
            }
        }
        return (n < 0) ? (1.0 / ret) : (ret);
    }
};
Maximum Subarray Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given the array [−2,1,−3,4,−1,2,1,−5,4], the contiguous subarray [4,−1,2,1] has the largest sum = 6.
More practice:If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
----------------------------------
121 Best time to buy and sell is based on this algorithm  
how is this DP??
class Solution {
public:
    int maxSubArray(int A[], int n) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int max=INT_MIN;
        int sum=0;
        for (int i=0;i<n;i++) {
            if (sum < 0) {
                sum = A[i];
            }else {
                sum += A[i];
            }
            if (sum > max) {
                max = sum;
            }
        }
        return max;
    } 
};
A easier to understand version Kadane's algorithm
sum是局部最优,表示当前连续子集的最后一位必定是在i
maxSum是全局最优
类似题目买卖股票3跟4
class Solution {
public:
    int maxSubArray(int A[], int n) {
        int sum = A[0];
        int maxSum = A[0];
        
        for (int i = 1; i < n; i++) {
            sum = max(A[i], sum + A[i]);
            maxSum = max(sum,maxSum);
        }
        return maxSum;
    }
};

divide and conquer, O(n * lg n)
#1: max subarray is in left part
#2: max subarray is in right part
#3: max subarray is acrossing the middle element
class Solution {
public:
    int maxSub(vector<int> &nums,int left,int right) {
        if (left == right) return nums[left];
        
        int mid = (left + right) / 2;
        int leftMax = maxSub(nums,left,mid);
        int rightMax = maxSub(nums,mid + 1, right);
        int crossMax = nums[mid] + nums[mid + 1];
        int temp = crossMax;
        for (int i = mid - 1; i >= left; i--) {
            temp += nums[i];
            crossMax = max(crossMax,temp);
        }
        
        temp = crossMax; // it's possible temp will be smaller than crossMax
        for (int i = mid + 2; i <= right; i++) {
            temp += nums[i];
            crossMax = max(crossMax,temp);
        }
        
        return max(crossMax,max(leftMax,rightMax));
    }

    int maxSubArray(vector<int>& nums) {
        return maxSub(nums,0,nums.size() - 1);
    }
};
Jump Game Given an array of non-negative integers, you are initially positioned at the first index of the array. Each element in the array represents your maximum jump length at that position. Determine if you are able to reach the last index. For example: A = [2,3,1,1,4], return true. A = [3,2,1,0,4], return false. ------------------------------------ DP bottom up, O(n) starting at [end - 1] towards [0], find out the first elem that can jump to the end, then set it to be the new end
class Solution {
public:
    bool canJump(int A[], int n) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int index = n-1;
        for (int i=n-2;i>=0;i--) {
            if (A[i] >= index-i) {
                index = i;
            }
        }
        return index == 0;
    }
};

Saturday, June 1, 2013

Day 32, 30,39,46, Substring with Concatenation of All Words, Combination Sum,Permutations

Substring with Concatenation of All Words
You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.
For example, given:
S: "barfoothefoobarman"
L: ["foo", "bar"]
You should return the indices: [0,9].
(order does not matter).
------------------------------------------------------------------------
use two maps to count occurrences of all patterns, iterate through S to check if each word in L exactly occurs once in current part of S
solution is from internet
this is a boring and tasteless question
time and space complexity?
notice the conversion (int)S.size() in for loop
class Solution {  
public:  
    vector<int> findSubstring(string S, vector<string> &L) {  
        map<string, int> words;  
        map<string, int> curStr;  
        for(int i = 0; i < L.size(); ++i)  
            ++words[L.at(i)];  
        int N = L.size();  
        vector<int> ret;  
        if(N <= 0)   return ret;  
        int M = L.at(0).size();  
        for(int i = 0; i <= (int)S.size()-N*M; ++i)  
        {  
            curStr.clear();  
            int j = 0;  
            for(j = 0; j < N; ++j)  
            {  
                string w = S.substr(i+j*M, M);  
                if(words.find(w) == words.end())  
                    break;  
                ++curStr[w];  
                if(curStr[w] > words[w])  
                    break;  
            }  
            if(j == N)  ret.push_back(i);  
        }  
        return ret;  
    }  
};
Update on Sep-11-2014
The idea is similar to Longest Substring Without Repeating Characters. Each word has the same length and can be seen as a unique(or not) character.
A slightly different implementation is it can re-assign a new map at the beginning of outer loop.
Update on Feb-17-2015
COME_BACK
inner loop里的算法
#1 如果找不到当前word,重新设置map和start,重新开始
#2 如果找到且数量 > 0
#3 如果找到且数量 == 0: 从start开始pop旧的word,直到找到当前的为止

因为所有词为无序,不用保证维护当前的数组, 如
1 - 2 -..........3 - 2 - 1, 假设扫到3时已经找到所有的词
class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        unordered_map<string,int> dic;
        for (int i = 0; i < words.size(); i++) {
            if (dic.find(words[i]) == dic.end()) {
                dic[words[i]] = 1;
            }else {
                dic[words[i]]++;
            }
        }
        
        vector<int> rt;
        int wordLen = words[0].length();

        for (int i = 0; i < wordLen; i++) {
            int start = i,count = 0;
            unordered_map<string,int> temp = dic;
            for (int j = i; j < s.length(); j += wordLen) {
                string word = s.substr(j,wordLen);
                if (temp.find(word) == temp.end()) {
                    count = 0;
                    temp = dic;
                    start = j + wordLen;
                    continue;
                }else if (temp[word] > 0) {
                    temp[word]--;
                    count++;
                    if (count == words.size()) rt.push_back(start);
                }else if (temp[word] == 0) {
                    while (true) {
                        string begin = s.substr(start,wordLen);
                        if (begin == word) {
                            start += wordLen;
                            if (count == words.size()) rt.push_back(start);
                            break;
                        }
                        temp[begin]++;
                        count--;
                        start += wordLen;
                    }
                }
            }    
        }
        
        return rt;
    }
};

Java, updated on Sep-25th-2018
3种情况:
1. map有单词且次数大于0
2. map有单词但次数等于0
3. map不包含单词
2和3可以揉成一个branch

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        
        Map<String, Integer> map = getMap(words);
        List<Integer> rt = new ArrayList<>();
        if (s.length() == 0 || words.length == 0) return rt;
        
        for (int i = 0; i < words[0].length(); i++) {
            rt.addAll(findSub(s, i, map, words[0].length(), words.length));    
        }
        
        return rt;
    }
    
    private List<Integer> findSub(String s, int i, Map<String, Integer> map, int len, int count) {
        List<Integer> rt = new ArrayList<>();
        Map<String, Integer> local = new HashMap<>(map);
        int start = i;
        int tempCount = count;
        
        while (i < s.length() - len + 1) {
            String word = s.substring(i, i + len);
            if (local.containsKey(word) && local.get(word) > 0) {
                local.put(word, local.get(word) - 1);
                i += len;
                tempCount--;
                
                if (tempCount == 0) {
                    rt.add(start);
                    String old = s.substring(start, start + len);
                    local.put(old, local.get(old) + 1);
                    start += len;
                    tempCount++;
                }
            }else {
                while (true) {
                    String old = s.substring(start, start + len);
                    if (old.equals(word)) {
                        start += len;
                        break;
                    }
                    local.put(old, local.get(old) + 1);
                    start += len;
                    tempCount++;
                }   
                i += len;
            }
        }
        
        return rt;
    }
    
    private Map<String, Integer> getMap(String[] words) {
        Map<String, Integer> map = new HashMap<>();
        for (String word : words) {
            map.put(word, map.getOrDefault(word, 0) + 1);
        }
        
        return map;
    }
}
}
Combination Sum
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.
Note:
  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1, a2, � , ak) must be in non-descending order. (ie, a1 ? a2 ? � ? ak).
  • 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]
-------------------------------------------------------------
combination

class Solution {
public:
    void comb (vector<int> &candidates, int target,vector<vector<int> > &ret,vector<int> cur,int start) {
        if (target == 0) {
            ret.push_back(cur);
        }else {
            for (int i=start;i<candidates.size();i++) {
                if (target - candidates[i] >= 0) {
                    vector<int> v = cur;  // Attention here!!!
                    v.push_back(candidates[i]);
                    comb(candidates,target-candidates[i],ret,v,i);
                }
            }
        }
    }

    vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        sort(candidates.begin(),candidates.end());
        vector<vector<int> > ret;
        vector<int> cur;
        comb(candidates,target,ret,cur,0);
        return ret;
    }
};
class Solution {
public:
    void comb(vector<vector<int> > &rt, vector<int> &candidates, vector<int> cur, int target, int index) {
        if (target == 0) {
            rt.push_back(cur);
            return;
        } 
        if (index >= candidates.size() || target < 0) return;
        
        comb(rt,candidates,cur,target,index + 1);
        cur.push_back(candidates[index]);
        comb(rt,candidates,cur,target - candidates[index],index);
    } 

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector<vector<int> > rt;
        vector<int> cur;
        comb(rt,candidates,cur,target,0);
        
        return rt;
    }
};
Permutations
Given a collection of numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:
[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].
--------------------------------------------------------------------
class Solution {
public:
    void per (vector<int> num,vector<int> cur,vector<vector<int> > &ret) {
        if (num.size() == 0) {
            ret.push_back(cur);
        }
        for (int i=0;i<num.size();i++) {
            vector<int> v = cur;
            vector<int> w = num;
            v.push_back(w[i]);
            w.erase(w.begin()+i);
            per(w,v,ret);
        }
    }

    vector<vector<int> > permute(vector<int> &num) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        vector<vector<int> > ret;
        vector<int> cur;
        per(num,cur,ret);
        return ret;
    }
};

#1 以index为分界线,来区分已经使用和未使用的集合(此条不一定为正确,需看代码)
#2 换句话说,每一个recursive call,都遍历所有未使用的数字确定在index(n次)
index = 0: 123, 213, 321
index = 1: 132, 231, 312
index = 2: 插入
class Solution {
public:
    void swap(vector<int> &nums,int i,int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    void per(vector<vector<int> > &rt, vector<int> &nums, int index) {
        if (nums.size() == index) {
            rt.push_back(nums);
            return;
        }
        
        for (int i = index; i < nums.size(); i++) {
            swap(nums,i,index);
            per(rt,nums,index + 1);
            swap(nums,i,index); // 此行可以不加,结果同样正确,因为每一次都会确定一个数
        }
    }

    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > rt;
        per(rt,nums,0);
        
        return rt;
    }
};

Monday, May 27, 2013

Day 31, 23, Merge k Sorted Lists

Merge k Sorted Lists
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
--------------------------------------------------------------
Solution #1 O(k*n)
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *merge2Lists (ListNode *l1, ListNode *l2) {
        ListNode *ret,*cur;
        if (l1 == NULL) {
            return l2;
        }
        if (l2 == NULL) {
            return l1;
        }
        if (l1->val < l2->val) {
            ret = l1;
            cur = l1;
            l1 = l1->next;
        }else {
            ret = l2;
            cur = l2;
            l2 = l2->next;
        }
        while (l1 != NULL && l2 != NULL) {
            if (l1->val < l2->val) {
                cur->next = l1;
                cur = cur->next;
                l1 = l1->next;
            }else {
                cur->next = l2;
                cur = cur->next;
                l2 = l2->next;
            }
        }
        if (l1 == NULL) {
            cur->next = l2;
        }else {
            cur->next = l1;
        }
        return ret;
    }
    

    ListNode *mergeKLists(vector<ListNode *> &lists) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (lists.size() == 0) return NULL;
        ListNode *ret = lists[0];
        for (int i=1;i<lists.size();i++) {
            ret = merge2Lists(ret,lists[i]);
        }
        return ret;
    }
};

Solution #2, O(nlogk), using Priority Queue
note struct of comparison function and declaration of priority queue
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    struct comp{
        bool operator()(const ListNode* n1, const ListNode* n2){
            return n1->val > n2->val;
        }
    };

    ListNode *mergeKLists(vector<ListNode *> &lists) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        priority_queue<ListNode*,vector<ListNode*>,comp> heap;
        ListNode *ret=NULL,*cur;
        for (int i=0;i<lists.size();i++) {
            if (lists[i] != NULL) {
                heap.push(lists[i]);
            }
        }
        
        while (!heap.empty()) {
            ListNode *min = heap.top();
            heap.pop();
            if (ret == NULL) {
                ret = min;
                cur = min;
            }else {
                cur->next = min;
                cur = cur->next;
            }
            if (min->next != NULL) {
                heap.push(min->next);
            }
        }
        return ret;
    }
};
Update on Sep-11-2014
Solution #3, push all nodes in priority_queue, then output will be in order
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    struct cmp {
        bool operator()(const ListNode* l1, const ListNode* l2) {
            return l1->val > l2->val;
        }
    };

    ListNode *mergeKLists(vector<ListNode *> &lists) {
        ListNode *dummy = new ListNode(INT_MIN);
        priority_queue<ListNode*,vector<ListNode*>,cmp> heap;
        bool flag = true;
        
        while (flag) {
            flag = false;
            for (int i = 0; i < lists.size(); i++) {
                if (lists[i] != NULL) {
                    flag = true;
                    heap.push(lists[i]);
                    lists[i] = lists[i]->next;
                }
            }
        }
        
        ListNode *head = dummy;
        while (!heap.empty()) {
            ListNode *t = heap.top();
            head->next = t;
            heap.pop();
            head = t;
        }
        head->next = NULL; // prevent infinite loop
        
        return dummy->next;
    }
};
Solution #4, merge all pairs of two adjacent lists for each iteration. O(nlog(k)), n is the total elements from all lists
Update on Nov-26-2014
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *merge2Lists (ListNode *l1, ListNode *l2) {
        ListNode *ret,*cur;
        if (l1 == NULL) {
            return l2;
        }
        if (l2 == NULL) {
            return l1;
        }
        if (l1->val < l2->val) {
            ret = l1;
            cur = l1;
            l1 = l1->next;
        }else {
            ret = l2;
            cur = l2;
            l2 = l2->next;
        }
        while (l1 != NULL && l2 != NULL) {
            if (l1->val < l2->val) {
                cur->next = l1;
                cur = cur->next;
                l1 = l1->next;
            }else {
                cur->next = l2;
                cur = cur->next;
                l2 = l2->next;
            }
        }
        if (l1 == NULL) {
            cur->next = l2;
        }else {
            cur->next = l1;
        }
        return ret;
    }

    ListNode *mergeKLists(vector<ListNode *> &lists) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (lists.size() == 0) return NULL;
        
        int size = lists.size();    
        while (size != 1) {
            
            for (int i = 0; i < size; i = i + 2) {
                if (i + 1 < size) {
                    lists[i / 2] = merge2Lists(lists[i],lists[i + 1]);
                }else{
                    lists[i / 2] = lists[i];
                }
            }
            size = size / 2 + size % 2;
        }
        
        return lists[0];
    }
};

与上面同样思路,但是用递归
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode *dummy = new ListNode(0), *itr = dummy;
        while (l1 != NULL && l2 != NULL) {
            if (l1->val > l2->val) {
                itr->next = l2;
                l2 = l2->next;
                itr = itr->next;
            }else {
                itr->next = l1;
                l1 = l1->next;
                itr = itr->next;
            }
        }
        
        if (l1 == NULL) {
            itr->next = l2;
        }
        if (l2 == NULL) {
            itr->next = l1;
        }
        return dummy->next;
    }

    ListNode* helper(vector<ListNode*> &lists,int start,int end) {
        if (start > end) return NULL;
        if (start == end) return lists[start];
        int mid = (start + end) / 2;
        ListNode *l1 = helper(lists,start,mid);
        ListNode *l2 = helper(lists,mid + 1,end);
        return mergeTwoLists(l1,l2);
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return helper(lists,0,lists.size() - 1);
    }
};
Java, 用priority queue
时间O(N * log k), 空间为O(k), N为总node的个数,k为list的数量。
先把所有的头指针插入到queue,然后一个个pop。把刚pop出来的node的一下个,推回queue
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        PriorityQueue que = new PriorityQueue<>((a, b) -> {
            return a.val - b.val;
        });
                
        for (ListNode node : lists) {
            if (node != null) que.add(node);
        }
        
        ListNode dummy = new ListNode(0);
        ListNode itr = dummy;

        while (!que.isEmpty()) {
            ListNode next = que.poll();
            if (next.next != null) que.add(next.next);
            itr.next = next;
            itr = next;
        }
        
        return dummy.next;
    }
}
如果可以重复利用原来的array的话,空间可以算是O(1)
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) return null;
        List rt = Arrays.asList(lists);
        while (rt.size() != 1) {
            rt = divide(rt);
        }
        
        return rt.get(0);
    }
    
    private List divide(List lists) {
        int n = lists.size();
        List rt = new ArrayList<>();
        for (int i = 0; i < n / 2; i++) {
            rt.add(mergeTwo(lists.get(i), lists.get(n - 1 - i)));
        }
        
        if (n % 2 == 1) rt.add(lists.get(n / 2));
        
        return rt;
    }
    
    private ListNode mergeTwo(ListNode node1, ListNode node2) {
        
        if (node1 == null) return node2;
        if (node2 == null) return node1;
            
        ListNode dummy = new ListNode(0);
        ListNode itr;
        if (node1.val > node2.val) {
            dummy.next = node2;
            node2 = node2.next;
        }else {
            dummy.next = node1;
            node1 = node1.next;
        }
        itr = dummy.next;
        
        while (node1 != null && node2 != null) {
            
            if (node1.val > node2.val) {
                itr.next = node2;
                itr = node2;
                node2 = node2.next;
            }else {
                itr.next = node1;
                itr = node1;
                node1 = node1.next;
            }
        }
        
        if (node1 != null) {
            itr.next = node1;
        }
        if (node2 != null) {
            itr.next = node2;
        }
        
        return dummy.next;
    }
}