Showing posts with label 递归. Show all posts
Showing posts with label 递归. Show all posts

Saturday, October 17, 2015

[Leetcode] Different Ways to Add Parentheses, Solution

Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are+- and *.
Example 1
Input: "2-1-1".
((2-1)-1) = 0
(2-(1-1)) = 2
Output: [0, 2]
Example 2
Input: "2*3-4*5"
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10
Output: [-34, -14, -10, -10, 10]

[Thoughts]
这题就是分治法- Divide and Conquer的一个例子。在递归的过程中,根据符号位,不断将一个字符串分成两个子串,然后将两个子串的结果merge起来。


[Code]

1:  class Solution {  
2:  public:  
3:    int compute(int a, int b, char op) {  
4:      switch(op) {  
5:        case '+': return a + b;  
6:        case '-': return a - b;  
7:        case '*': return a * b;  
8:      }  
9:    }  
10:    vector<int> diffWaysToCompute(string input) {  
11:      int number = 0, i=0;  
12:      for(; i< input.length() && isdigit(input[i]); ++i) {  
13:        number = number * 10 + input[i]-'0';  
14:      }  
15:      // if pure number, just return  
16:      if(i == input.length()) return {number};  
17:      vector<int> diffWays, lefts, rights;  
18:      for(int i =0; i< input.length(); i++) {  
19:        if(isdigit(input[i])) continue;  
20:        lefts =   
21:          diffWaysToCompute(input.substr(0, i));  
22:        rights =   
23:          diffWaysToCompute(input.substr(i + 1, input.length() - i - 1));  
24:        for(int j = 0; j < lefts.size(); ++j)   
25:          for( int k =0; k < rights.size(); ++k)   
26:            diffWays.push_back(compute(lefts[j], rights[k], input[i]));  
27:      }  
28:      return diffWays;  
29:    }  
30:  };  



Note: 已有的实现有大量的重复计算,如果想进一步优化时间的话,可以考虑用memoization来避免冗余计算。比如,用个hash map 来保存中间计算的结果,如下:

1:  class Solution {  
2:  public:  
3:    unordered_map<string, vector<int>> memo;  
4:    int compute(int a, int b, char op) {  
5:      switch(op) {  
6:        case '+': return a + b;  
7:        case '-': return a - b;  
8:        case '*': return a * b;  
9:      }  
10:    }  
11:    string generateKey(int startIndex, int endIndex) {  
12:      return to_string(startIndex) + "-" + to_string(endIndex);  
13:    }  
14:    vector<int> diffWaysToCompute(string input) {  
15:      return diffWaysToComputeWithMemo(input, 0, input.size()-1);  
16:    }  
17:    vector<int> diffWaysToComputeWithMemo(string& input, int startIndex, int endIndex) {    
18:      string cache_key = generateKey(startIndex, endIndex);  
19:      if(memo.find(cache_key) != memo.end()) return memo[cache_key];  
20:      int number = 0, i=startIndex;  
21:      for(; i<= endIndex && isdigit(input[i]); ++i) {  
22:        number = number * 10 + input[i]-'0';  
23:      }  
24:      // if pure number, just return  
25:      if(i > endIndex) return {number};  
26:      vector<int> diffWays, lefts, rights;  
27:      for(int i =startIndex; i< endIndex; i++) {  
28:        if(isdigit(input[i])) continue;  
29:        lefts =   
30:          diffWaysToComputeWithMemo(input, startIndex, i-1);  
31:        rights =   
32:          diffWaysToComputeWithMemo(input, i+1, endIndex );  
33:        for(int j = 0; j < lefts.size(); ++j)   
34:          for( int k =0; k < rights.size(); ++k)   
35:            diffWays.push_back(compute(lefts[j], rights[k], input[i]));  
36:      }  
37:      memo[cache_key] = diffWays;  
38:      return diffWays;  
39:    }  
40:  };  


github: https://github.com/codingtmd/leetcode/blob/master/src/Different%20Ways%20to%20Add%20Parentheses(Memoization).cpp










Thursday, March 21, 2013

[LeetCode] Same Tree, Solution


Given two binary trees, write a function to check if they are equal or not.
Two binary trees are considered equal if they are structurally identical and the nodes have the same value.
» Solve this problem


[Thoughts]
递归判断左右子树是否相等。


[Code]
1:    bool isSameTree(TreeNode *p, TreeNode *q) {  
2:      if(!p && !q) return true;  
3:      if(!p || !q) return false;  
4:      return (p->val == q->val) &&  
5:           isSameTree(p->left, q->left) &&   
6:           isSameTree(p->right, q->right);      
7:    }  

Wednesday, March 20, 2013

[LeetCode] Unique Binary Search Trees II, Solution


Given n, generate all structurally unique BST's (binary search trees) that store values 1...n.
For example,
Given n = 3, your program should return all 5 unique BST's shown below.
   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.
» Solve this problem


[Thoughts]
分析请参看http://fisherlei.blogspot.com/2013/03/leetcode-unique-binary-search-trees.html
思路是一致的。划分左右子树,然后递归构造。

[Code]
1:       vector<TreeNode *> generateTrees(int n) {   
2:            if(n ==0) return generate(1,0);  
3:            return generate(1, n);  
4:       }       
5:       vector<TreeNode *> generate(int start, int end)  
6:       {  
7:            vector<TreeNode *> subTree;  
8:            if(start>end)  
9:            {  
10:                 subTree.push_back(NULL);  
11:                 return subTree;  
12:            }  
13:            for(int i =start; i<=end; i++)  
14:            {  
15:                 vector<TreeNode*> leftSubs = generate(start, i-1);  
16:                 vector<TreeNode*> rightSubs = generate(i+1, end);  
17:                 for(int j = 0; j< leftSubs.size(); j++)  
18:                 {  
19:                      for(int k=0; k<rightSubs.size(); k++)  
20:                      {  
21:                           TreeNode *node = new TreeNode(i);  
22:                           node->left = leftSubs[j];  
23:                           node->right = rightSubs[k];  
24:                           subTree.push_back(node);  
25:                      }  
26:                 }  
27:            }  
28:            return subTree;  
29:       }      


[Note]
写完第一个版本之后,立即发现一个严重的问题。上面的function存在大量的对象拷贝,因为所有变量都是在栈上开辟,所以返回值的时候都需要通过拷贝构造函数来重构vector,面试中这个疏忽是不应该的。

修改版,这里应该用指针及堆来存储变量。
1:       vector<TreeNode *> generateTrees(int n) {   
2:            if(n ==0) return *generate(1,0);  
3:            return *generate(1, n);  
4:       }  
5:       vector<TreeNode *>* generate(int start, int end)  
6:       {  
7:            vector<TreeNode *> *subTree = new vector<TreeNode*>();  
8:            if(start>end)  
9:            {  
10:                 subTree->push_back(NULL);  
11:                 return subTree;  
12:            }  
13:            for(int i =start; i<=end; i++)  
14:            {  
15:                 vector<TreeNode*> *leftSubs = generate(start, i-1);  
16:                 vector<TreeNode*> *rightSubs = generate(i+1, end);  
17:                 for(int j = 0; j< leftSubs->size(); j++)  
18:                 {  
19:                      for(int k=0; k<rightSubs->size(); k++)  
20:                      {  
21:                           TreeNode *node = new TreeNode(i);  
22:                           node->left = (*leftSubs)[j];  
23:                           node->right = (*rightSubs)[k];  
24:                           subTree->push_back(node);  
25:                      }  
26:                 }  
27:            }  
28:            return subTree;  
29:       }      


Sunday, March 3, 2013

[LeetCode] Palindrome Partitioning, Solution


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"]
  ]
» Solve this problem

[Thoughts]
这种需要输出所有结果的基本上都是DFS的解法。实现如下。

[Code]
1:       vector<vector<string>> partition(string s) {  
2:            vector<vector<string>> result;  
3:            vector<string> output;  
4:            DFS(s, 0, output, result);  
5:            return result;  
6:       }  
7:       void DFS(string &s, int start, vector<string>& output, vector<vector<string>> &result)  
8:       {      
9:            if(start == s.size())  
10:            {  
11:                 result.push_back(output);  
12:                 return;  
13:            }  
14:            for(int i = start; i< s.size(); i++)  
15:            {    
16:                 if(isPalindrome(s, start, i))  
17:                 {  
18:                      output.push_back(s.substr(start, i-start+1));  
19:                      DFS(s, i+1, output, result);  
20:                      output.pop_back();  
21:                 }  
22:            }  
23:       }  
24:       bool isPalindrome(string &s, int start, int end)  
25:       {  
26:            while(start< end)  
27:            {  
28:                 if(s[start] != s[end])  
29:                 return false;  
30:                 start++; end--;  
31:            }  
32:            return true;  
33:       }  













Friday, February 22, 2013

[LeetCode] Sum Root to Leaf Numbers, Solution


Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.
An example is the root-to-leaf path 1->2->3 which represents the number 123.
Find the total sum of all root-to-leaf numbers.
For example,
    1
   / \
  2   3
The root-to-leaf path 1->2 represents the number 12.
The root-to-leaf path 1->3 represents the number 13.
Return the sum = 12 + 13 = 25.
» Solve this problem


[Thoughts]
Recursion. Similar as [LeetCode] Binary Tree Maximum Path Sum Solution, the difference here is only adding a track variable to sum all the paths.

[Code]
1:       int sumNumbers(TreeNode *root) {  
2:            int sum=0, path =0;            
3:            GenerateSum(root, sum, path);  
4:            return sum;  
5:       }  
6:       void GenerateSum(TreeNode *root, int& sum, int path)  
7:       {  
8:            if(root == NULL) return;      
9:            path = path*10 +root->val;  
10:            if(root->left == NULL && root->right == NULL)  
11:            {  
12:                 sum+=path;  
13:                 return;  
14:            }  
15:            GenerateSum(root->left, sum, path);  
16:            GenerateSum(root->right, sum, path);  
17:       }  










[LeetCode] Word Ladder II, Solution


Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) 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"]
Return
  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]
Note:
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
» Solve this problem

[Thoughts]
解法一,递归
1. 首先生成不同字符串之间的跳转函数(Func[A][B] means how many char need changed if A transfer to B),比如{"a", "b", "c"}
      a        b       c
a    0        1       1
b    1        0       1
c    1        1        0
2. 有了转移方程之后,直接递归就好了。

在实现中,由于unordered_set不支持[]操作,所以我额外拷贝到vector里面来做(没有使用hash),浪费了多余的时间。可以过小数据,但是过不了大数据。

1:  int DiffDict[1000][1000];  
2:  int visited[1000];  
3:  void findtran(string& start, string& end, vector<string> &dict, int curIndex,  
4:  int step, int& min, vector<vector<string>>& result, vector<string>& candidate)  
5:  {  
6:       if(start == end)  
7:       {  
8:            if(step < min)  
9:            {  
10:                 min = step;  
11:                 result.clear();  
12:                 result.push_back(candidate);  
13:            }  
14:            else if(step == min)  
15:            {  
16:                 result.push_back(candidate);  
17:            }       
18:            return;  
19:       }  
20:       for(int i =1; i< dict.size(); i++)  
21:       {  
22:            if(visited[i] ==1 || DiffDict[curIndex][i] !=1)  
23:                 continue;  
24:            visited[i] =1;  
25:            candidate.push_back(dict[i]);  
26:            findtran(dict[i], end, dict, i, step+1, min, result, candidate);  
27:            candidate.pop_back();  
28:            visited[i] =0;  
29:       }  
30:  }  
31:  vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {  
32:       vector<vector<string>> result;  
33:       assert(dict.size() < 1000);  
34:       vector<string> dictV;  
35:       //copy data to vector since unordered_set not support []  
36:       for(unordered_set<string>::iterator it = dict.begin(); it!=dict.end(); ++it)  
37:       {  
38:            dictV.push_back(*it);  
39:       }  
40:       //add start as head  
41:       vector<string>::iterator it = std::find(dictV.begin(), dictV.end(),start);  
42:       if(it!= dictV.end())  
43:       {  
44:            dictV.erase(it);  
45:       }  
46:       dictV.insert(dictV.begin(),start);  
47:       visited[0] =1;  
48:       //add end as tail  
49:       it = std::find(dictV.begin(), dictV.end(),end);  
50:       if(it!= dictV.end())  
51:       {  
52:            dictV.erase(it);  
53:       }  
54:       dictV.push_back(end);  
55:       //preprocess trans metrics  
56:       for(int i=0; i<dictV.size(); i++)  
57:       {  
58:            for(int j=i; j<dictV.size(); j++)  
59:            {  
60:                 int diff=0;  
61:                 for(int k=0; k< it->size(); k++)  
62:                 {  
63:                      if(dictV[i][k] != dictV[j][k]) diff++;  
64:                 }  
65:                 DiffDict[i][j] = diff;  
66:                 DiffDict[j][i] = diff;  
67:            }  
68:       }  
69:       int step =0;  
70:       int min = INT_MAX;  
71:       vector<string> candidate;  
72:       candidate.push_back(start);  
73:       findtran(start, end, dictV, 0,step, min, result, candidate);  
74:       return result;  
75:  }  


考虑到题目已经提示了应该使用unordered_set来做,应该有基于hash的解法。

Saturday, February 2, 2013

[Google] Inorder Successor in Binary Search Tree, Solution


In Binary Tree, Inorder successor of a node is the next node in Inorder traversal of the Binary Tree. Inorder Successor is NULL for the last node in Inoorder traversal.
In Binary Search Tree, Inorder Successor of an input node can also be defined as the node with the smallest key greater than the key of input node. So, it is sometimes important to find next node in sorted order.

In the above diagram, inorder successor of 8 is 10, inorder successor of 10 is 12 and inorder successor of 14 is 20.
Method 1 (Uses Parent Pointer)
In this method, we assume that every node has parent pointer.
The Algorithm is divided into two cases on the basis of right subtree of the input node being empty or not.
Input: node, root // node is the node whose Inorder successor is needed.
output: succ // succ is Inorder successor of node.
1) If right subtree of node is not NULL, then succ lies in right subtree. Do following.
Go to right subtree and return the node with minimum key value in right subtree.
2) If right sbtree of node is NULL, then succ is one of the ancestors. Do following.
Travel up using the parent pointer until you see a node which is left child of it’s parent. The parent of such a node is the succ.
Implementation
Note that the function to find InOrder Successor is highlighted (with gray background) in below code.
1:  #include <stdio.h>  
2:  #include <stdlib.h>  
3:  /* A binary tree node has data, pointer to left child  
4:    and a pointer to right child */  
5:  struct node  
6:  {  
7:    int data;  
8:    struct node* left;  
9:    struct node* right;  
10:    struct node* parent;  
11:  };  
12:  struct node * minValue(struct node* node);  
13:  struct node * inOrderSuccessor(struct node *root, struct node *n)  
14:  {  
15:   // step 1 of the above algorithm  
16:   if( n->right != NULL )  
17:    return minValue(n->right);  
18:   // step 2 of the above algorithm  
19:   struct node *p = n->parent;  
20:   while(p != NULL && n == p->right)  
21:   {  
22:     n = p;  
23:     p = p->parent;  
24:   }  
25:   return p;  
26:  }  
27:  /* Given a non-empty binary search tree, return the minimum data   
28:    value found in that tree. Note that the entire tree does not need  
29:    to be searched. */  
30:  struct node * minValue(struct node* node) {  
31:   struct node* current = node;  
32:   /* loop down to find the leftmost leaf */  
33:   while (current->left != NULL) {  
34:    current = current->left;  
35:   }  
36:   return current;  
37:  }  
Time Complexity: O(h) where h is height of tree.


Method 2 (Don't Use Parent Pointer)
Inorder travel the tree and
1) If current visit node is target node,  mark the indicator as true.
2) If indicator is true, print the node and return.

Implementation
1:  struct node * inOrderSuccessor(struct node *n, struct node* target, bool& indicator)  
2:  {  
3:   if( n== NULL )  
4:    return NULL;  
5:   if(indicator) return n;  
6:   if(n == target) { indicator = true; return;}  
7:   node* left = inOrderSuccessor(n->left, target, indicator);  
8:   node * right =inOrderSuccessor(n->right, target, indicator);  
9:   if(left != NULL) return left;  
10:   if(right!= NULL) return right;  
11:   return NULL;  
12:  }  

Monday, January 28, 2013

[FaceBook] Hanoi Moves, Solution


There are K pegs. Each peg can hold discs in decreasing order of radius when looked from bottom to top of the peg. There are N discs which have radius 1 to N; Given the initial configuration of the pegs and the final configuration of the pegs, output the moves required to transform from the initial to final configuration. You are required to do the transformations in minimal number of moves.
A move consists of picking the topmost disc of any one of the pegs and placing it on top of anyother peg.
At anypoint of time, the decreasing radius property of all the pegs must be maintained.

Constraints:
1<= N<=8
3<= K<=5


Input Format:
N K
2nd line contains N integers.
Each integer in the second line is in the range 1 to K where the i-th integer denotes the peg to which disc of radius i is present in the initial configuration.
3rd line denotes the final configuration in a format similar to the initial configuration.

Output Format:
The first line contains M - The minimal number of moves required to complete the transformation.
The following M lines describe a move, by a peg number to pick from and a peg number to place on.
If there are more than one solutions, it's sufficient to output any one of them. You can assume, there is always a solution with less than 7 moves and the initial confirguration will not be same as the final one.

Sample Input #00:

2 3
1 1
2 2
Sample Output #00:

3
1 3
1 2
3 2


Sample Input #01:
6 4
4 2 4 3 1 1
1 1 1 1 1 1
Sample Output #01:
5
3 1
4 3
4 1
2 1
3 1
NOTE: You need to write the full code taking all inputs are from stdin and outputs to stdout
If you are using "Java", the classname is "Solution"


[Thoughts]
No good idea, only brute-force can hit my mind now. seems a simple question, but the implementation really costs me some time.

Update: some people talk about using tree to do the BFS (http://comments.gmane.org/gmane.comp.programming.algogeeks/30920) or A* search (http://en.wikipedia.org/wiki/A*_search_algorithm). But I would say this is a bit over engineering.


[Code]
1:  /*  
2:  Please write complete compilable code.  
3:  Read input from standard input (STDIN) and print output to standard output(STDOUT).  
4:  For more details, please check https://www.interviewstreet.com/recruit/challenges/faq/view#stdio  
5:  */  
6:  #include <climits>  
7:  #include <iostream>  
8:  using namespace std;   
9:  int initial[9];  
10:  int expected[9];  
11:  int CurDiscInPeg[9];  
12:  int n, k;  
13:  int moveSeq[9][2];  
14:  int minSteps = 7;  
15:  int minMoveSeq[9][2];  
16:  void refreshPeg()  
17:  {  
18:    for(int i =1; i<= k; i++)  
19:    {  
20:      CurDiscInPeg[i] = INT_MAX; //no disk on it.  
21:      for(int j =1; j<=n; j++)  
22:      {  
23:        if(initial[j] == i)  
24:        {  
25:          CurDiscInPeg[i] =j;  
26:          break;  
27:        }  
28:      }  
29:    }  
30:  }  
31:  bool verify(int depth)  
32:  {  
33:    int z = 1;  
34:    for(; z<=n; z++)  
35:    {  
36:      if(initial[z]!=expected[z])  
37:        return false;  
38:    }  
39:    minSteps = depth;  
40:    for(int z = 1; z<=minSteps; z++)  
41:    {  
42:      minMoveSeq[z][0] = moveSeq[z][0];  
43:      minMoveSeq[z][1] = moveSeq[z][1];  
44:    }       
45:    return true;        
46:  }  
47:  void Move(int depth)  
48:  {  
49:    if(depth > minSteps) return;  
50:    for(int i =1; i<=k; i++)  
51:    {  
52:      for(int j=1; j<=k; j++)  
53:      {  
54:        if(CurDiscInPeg[i] >= CurDiscInPeg[j])  
55:          continue;  
56:        int disc = CurDiscInPeg[i];  
57:        initial[disc] = j;  
58:        moveSeq[depth][0] = i;  
59:        moveSeq[depth][1] = j;  
60:        if(verify(depth)) return;  
61:        refreshPeg();  
62:        Move(depth+1);  
63:        initial[disc] = i;  
64:        refreshPeg();  
65:      }  
66:    }  
67:  }  
68:  int main()  
69:  {  
70:    cin>>n;  
71:    cin>>k;  
72:    for(int i =1; i<=n; i++)  
73:    {  
74:      cin>>initial[i];  
75:    }  
76:    for(int i =1; i<=n; i++)  
77:    {  
78:      cin>>expected[i];  
79:    }  
80:    refreshPeg();  
81:    Move(1);  
82:    cout<<minSteps<<endl;  
83:    for(int i =1; i<=minSteps; i++)  
84:    {      
85:      cout<<minMoveSeq[i][0]<<" "<<minMoveSeq[i][1]<<endl;  
86:    }  
87:  }  


Sunday, January 27, 2013

[LeetCode] Convert Sorted List to Binary Search Tree, Solution


Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.
» Solve this problem

[Thoughts]
It is similar with "Convert Sorted Array to Binary Search Tree". But the difference here is we have no way to random access item in O(1).

If we build BST from array, we can build it from top to bottom, like
1. choose the middle one as root,
2. build left sub BST
3. build right sub BST
4. do this recursively.

But for linked list, we can't do that because Top-To-Bottom are heavily relied on the index operation.
There is a smart solution to provide an Bottom-TO-Top as an alternative way, http://leetcode.com/2010/11/convert-sorted-list-to-balanced-binary.html

With this, we can insert nodes following the list’s order. So, we no longer need to find the middle element, as we are able to traverse the list while inserting nodes to the tree.

[Code]
1:    TreeNode *sortedListToBST(ListNode *head) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      int len =0;  
5:      ListNode *p = head;  
6:      while(p)  
7:      {  
8:        len++;  
9:        p = p->next;  
10:      }  
11:      return BuildBST(head, 0, len-1);  
12:    }  
13:    TreeNode* BuildBST(ListNode*& list, int start, int end)  
14:    {  
15:      if (start > end) return NULL;  
16:      int mid = (start+end)/2;   //if use start + (end - start) >> 1, test case will break, strange!
17:      TreeNode *leftChild = BuildBST(list, start, mid-1);  
18:      TreeNode *parent = new TreeNode(list->val);  
19:      parent->left = leftChild;  
20:      list = list->next;  
21:      parent->right = BuildBST(list, mid+1, end);  
22:      return parent;  
23:    }  


[LeetCode] Construct Binary Tree from Preorder and Inorder Traversal, Solution


Given preorder and inorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
» Solve this problem

[Thoughts]

There is an example.
        _______7______
       /              \
    __10__          ___2
   /      \        /
   4       3      _8
            \    /
             1  11
The preorder and inorder traversals for the binary tree above is:
preorder = {7,10,4,3,1,2,8,11}
inorder = {4,10,3,1,7,11,8,2}

The first node in preorder alwasy the root of the tree. We can break the tree like:
1st round:
preorder:  {7}, {10,4,3,1}, {2,8,11}
inorder:     {4,10,3,1}, {7}, {11, 8,2}

        _______7______
       /              \
    {4,10,3,1}       {11,8,2}
Since we alreay find that {7} will be the root, and in "inorder" sert, all the data in the left of {7} will construct the left sub-tree. And the right part will construct a right sub-tree. We can the left and right part agin based on the preorder.
2nd round
left part                                                                            right part
preorder: {10}, {4}, {3,1}                                              {2}, {8,11}
inorder:  {4}, {10}, {3,1}                                                {11,8}, {2}


        _______7______
       /              \
    __10__          ___2
   /      \        /
   4      {3,1}   {11,8}
see that, {10} will be the root of left-sub-tree and {2} will be the root of right-sub-tree.

Same way to split {3,1} and {11,8}, yo will get the complete tree now.

        _______7______
       /              \
    __10__          ___2
   /      \        /
   4       3      _8
            \    /
             1  11
So, simulate this process from bottom to top with recursion as following code.

[Code]
1:    TreeNode *buildTree(  
2:      vector<int> &preorder,   
3:      vector<int> &inorder) {  
4:      // Start typing your C/C++ solution below  
5:      // DO NOT write int main() function  
6:      return BuildTreePI(  
7:        preorder, inorder, 0, preorder.size()-1, 0, preorder.size());  
8:    }    
9:    TreeNode* BuildTreePI(  
10:      vector<int> &preorder,  
11:      vector<int> &inorder,  
12:      int p_s, int p_e,  
13:      int i_s, int i_e)  
14:    {  
15:      if(p_s > p_e)  
16:        return NULL;  
17:      int pivot = preorder[i_s];  
18:      int i =p_s;  
19:      for(;i< p_e; i++)  
20:      {  
21:        if(inorder[i] == pivot)  
22:          break;  
23:      }  
24:      TreeNode* node = new TreeNode(pivot);  
25:      node->left = BuildTreePI(preorder, inorder, p_s, i-1, i_s+1, i-p_s+i_s);  
26:      node->right = BuildTreePI(preorder, inorder, i+1, p_e, i-p_s+i_s+1, i_e);  
27:      return node;      
28:    }  




Saturday, January 26, 2013

[LeetCode] Combinations, Solution


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],
]
» Solve this problem

[Thoughts]
Similar as "Conbination Sum". But here the terminate condition is "k", not sum.

[Code]
1:    vector<vector<int> > combine(int n, int k) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      vector<vector<int> > result;  
5:      vector<int> solution;  
6:      GetCombine(n,k,1, solution, result);  
7:      return result;  
8:    }  
9:    void GetCombine(  
10:      int n,   
11:      int k,   
12:      int level,  
13:      vector<int>& solution,  
14:      vector<vector<int> >& result)  
15:    {      
16:      if(solution.size() == k)  
17:      {  
18:        result.push_back(solution);  
19:        return;  
20:      }  
21:      for(int i =level; i<= n; i++)  
22:      {  
23:        solution.push_back(i);  
24:        GetCombine(n,k,i+1, solution, result);  
25:        solution.pop_back();  
26:      }  
27:    }  


[LeetCode] Combination Sum II, Solution


Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C may only be used once in the combination.
Note:
  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1a2, … , ak) must be in non-descending order. (ie, a1 â‰¤ a2 â‰¤ … ≤ ak).
  • The solution set must not contain duplicate combinations.
For example, given candidate set 10,1,2,7,6,1,5 and target 8
A solution set is: 
[1, 7] 
[1, 2, 5] 
[2, 6] 
[1, 1, 6] 
» Solve this problem

[Thoughts]
Very similar with previous "Combination Sum". The only difference is marked as red in Code part. Need to handle the index and skip duplicate candidate.


[Code]
1:    vector<vector<int> > combinationSum2(vector<int> &num, int target) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      // Start typing your C/C++ solution below  
5:      // DO NOT write int main() function  
6:      vector<vector<int> > result;  
7:      vector<int> solution;  
8:      int sum=0;  
9:      std::sort(num.begin(), num.end());  
10:      GetCombinations(num,sum, 0, target, solution, result);  
11:      return result;  
12:    }  
13:    void GetCombinations(  
14:      vector<int>& candidates,  
15:      int& sum,  
16:      int level,  
17:      int target,  
18:      vector<int>& solution,  
19:      vector<vector<int> >& result)  
20:    {  
21:      if(sum > target) return;  
22:      if(sum == target)  
23:      {  
24:        result.push_back(solution);  
25:        return;  
26:      }  
27:      for(int i =level; i< candidates.size(); i++)  
28:      {  
29:        sum+=candidates[i];  
30:        solution.push_back(candidates[i]);  
31:        GetCombinations(candidates, sum, i+1, target, solution, result);  
32:        solution.pop_back();  
33:        sum-=candidates[i];    
34:        while(i<candidates.size()-1 && candidates[i] == candidates[i+1]) i++;  
35:      }  
36:    }  


[LeetCode] Combination Sum, Solution


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 (a1a2, … , 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] 
» Solve this problem

[Thoughts]
This is a normal recursion question. For each candidate, add and verify the target. If it hit, add it as a part of solution.



[Code]
1:    vector<vector<int> > combinationSum(vector<int> &candidates, int target) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      vector<vector<int> > result;  
5:      vector<int> solution;  
6:      int sum=0;  
7:      std::sort(candidates.begin(), candidates.end());  
8:      GetCombinations(candidates,sum, 0, target, solution, result);  
9:      return result;  
10:    }  
11:    void GetCombinations(  
12:      vector<int>& candidates,  
13:      int& sum,  
14:      int level,  
15:      int target,  
16:      vector<int>& solution,  
17:      vector<vector<int> >& result)  
18:    {  
19:      if(sum > target) return;  
20:      if(sum == target)  
21:      {  
22:        result.push_back(solution);  
23:        return;  
24:      }  
25:      for(int i =level; i< candidates.size(); i++)  
26:      {  
27:        sum+=candidates[i];  
28:        solution.push_back(candidates[i]);  
29:        GetCombinations(candidates, sum, i, target, solution, result);  
30:        solution.pop_back();  
31:        sum-=candidates[i];        
32:      }  
33:    }  






Sunday, January 20, 2013

[LeetCode] Binary Tree Maximum Path Sum Solution


Given a binary tree, find the maximum path sum.
The path may start and end at any node in the tree.
For example:
Given the below binary tree,
       1
      / \
     2   3
Return 6.
» Solve this problem

[Thoughts]
For each node like following, there should be four ways existing for max path:

1. Node only
2. L-sub + Node
3. R-sub + Node
4. L-sub + Node + R-sub

Keep trace the four path and pick up the max one in the end.

[Code]
1:    int maxPathSum(TreeNode *root) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      int maxAcrossRoot=INT_MIN;  
5:      int maxEndByRoot = GetMax(root, maxAcrossRoot);  
6:      return std::max(maxAcrossRoot, maxEndByRoot);  
7:    }  
8:    int GetMax(TreeNode *node, int& maxAcrossRoot)  
9:    {  
10:      if(node == NULL) return 0;  
11:      int left = GetMax(node->left, maxAcrossRoot);  
12:      int right = GetMax(node->right, maxAcrossRoot);  
13:      int cMax = node->val;  
14:      if(left>0)  
15:        cMax+=left;  
16:      if(rifht>0)  
17:        cMax+=right;  
18:      maxAcrossRoot = std::max(maxAcrossRoot, cMax);  
19:      return std::max(  
20:        node->val,   
21:        std::max(node->val+left, node->val+right));  
22:    }  




Wednesday, January 16, 2013

[LeetCode] Binary Tree Inorder Traversal Solution


Given a binary tree, return the inorder traversal of its nodes' values.
For example:
Given binary tree {1,#,2,3},
   1
    \
     2
    /
   3
return [1,3,2].
Note: Recursive solution is trivial, could you do it iteratively?
confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.
» Solve this problem

[Thoughts]
For recursion version, it's very easy to write.

But for iterative version, we need a stack to help.


[Code]
Recursion version
1:    vector<int> inorderTraversal(TreeNode *root) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      vector<int> result;  
5:      inorderTra(root, result);  
6:      return result;  
7:    }  
8:    void inorderTra(TreeNode* node, vector<int> &result)  
9:    {  
10:      if(node == NULL)  
11:      {        
12:        return;  
13:      }  
14:      inorderTra(node->left, result);  
15:      result.push_back(node->val);      
16:      inorderTra(node->right, result);  
17:    }  

Iteration version
1:    vector<int> inorderTraversal(TreeNode *root) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      vector<TreeNode*> sta;  
5:      vector<int> result;  
6:      if(root == NULL) return result;  
7:      TreeNode* node =root;  
8:      while(sta.size()>0 || node!=NULL)  
9:      {  
10:        while(node!=NULL)  
11:        {  
12:          sta.push_back(node);  
13:          node = node->left;  
14:        }  
15:        node= sta.back();  
16:        sta.pop_back();  
17:        result.push_back(node->val);  
18:        node =node->right;  
19:      }  
20:      return result;  
21:    }  



[LeetCode] Balanced Binary Tree Solution


Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of everynode never differ by more than 1.
» Solve this problem

[Thoughts]
recursion. For each node, check the left branch and right branch.

[Code]
1:    bool isBalanced(TreeNode *root) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      if(root == NULL) return true;  
5:      int val = GetBalance(root);  
6:      if(val ==-1) return false;  
7:      return true;      
8:    }    
9:    int GetBalance(TreeNode* node)  
10:    {  
11:      if(node == NULL)  
12:        return 0;  
13:      int left = GetBalance(node->left);  
14:      if(left == -1) return -1;  
15:      int right = GetBalance(node->right);  
16:      if(right == -1) return -1;  
17:      if(left-right>1 || right-left>1)  
18:        return -1;  
19:      return left>right? left+1:right+1;  
20:    }   



Monday, January 14, 2013

[LeetCode] 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.
» Solve this problem

[解题思路]
一道递归题。跟前面一道robot路径的问题一样,只不过取值变成了上下左右四个方向,而不是仅仅下右两个方向。

这里加了一个visited的数组,用于避免重复统计字母。比如如果word在board里面是个环的话。

[Code]
1:    bool exist(vector<vector<char> > &board, string word) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      if(word.size() ==0) return false;  
5:      if(board.size() ==0 || board[0].size() == 0) return false;  
6:      int row = board.size();  
7:      int col = board[0].size();  
8:      int * visited = new int[row*col];  
9:      memset(visited, 0, row*col*sizeof(int));  
10:      for(int i =0; i< board.size(); i++)  
11:      {  
12:        for(int j =0; j< board[0].size(); j++)  
13:        {  
14:          if(board[i][j] == word[0])  
15:          {  
16:            visited[i*col+j] = 1;  
17:            if(search(board, word, visited, -1, 1, i, j))  
18:              return true;  
19:            visited[i*col+j] =0;  
20:          }  
21:        }  
22:      }  
23:      delete visited;  
24:      return false;  
25:    }    
26:    bool search(vector<vector<char> > &board,   
27:      string& word,  
28:      int* visited,  
29:      int op, //0 up, 1 down, 2 left, 3 right  
30:      int matchLen,  
31:      int i,  
32:      int j)  
33:    {  
34:      if(matchLen == word.size()) return true;  
35:      int row = board.size();  
36:      int col = board[0].size();  
37:      if(i+1<row && op!=0)  
38:      {  
39:        if(visited[(i+1)*col+j] ==0 &&   
40:        board[i+1][j] == word[matchLen])  
41:        {  
42:          visited[(i+1)*col+j] =1;  
43:          if(search(board, word, visited, 1, matchLen+1, i+1, j))  
44:            return true;  
45:          visited[(i+1)*col+j] =0;  
46:        }  
47:      }  
48:      if(i-1>=0 && op!=1)  
49:      {  
50:        if(visited[(i-1)*col+j] ==0 && board[i-1][j] == word[matchLen])  
51:        {  
52:          visited[(i-1)*col+j] =1;  
53:          if(search(board, word, visited, 0, matchLen+1, i-1, j))  
54:            return true;  
55:          visited[(i-1)*col+j] =0;  
56:        }  
57:      }  
58:      if(j+1<col && op!=2)  
59:      {  
60:        if(visited[i*col+j+1] ==0 && board[i][j+1] == word[matchLen])  
61:        {  
62:          visited[i*col+j+1] =1;  
63:          if(search(board, word, visited, 3, matchLen+1, i, j+1))  
64:            return true;  
65:          visited[i*col+j+1] =0;  
66:        }  
67:      }  
68:      if(j-1>=0 && op!=3)  
69:      {  
70:        if(visited[i*col+j-1] ==0 && board[i][j-1] == word[matchLen])  
71:        {  
72:          visited[i*col+j-1] =1;  
73:          if(search(board, word, visited, 2, matchLen+1, i, j-1))  
74:            return true;  
75:          visited[i*col+j-1] =0;  
76:        }  
77:      }  
78:      return false;      
79:    }