Tuesday, December 31, 2013

Day 71, ##, Single Number, Single Number II

Single Number
Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
------------------------------------------------------------
XOR
we know A^A = 0 and A^A^B  == A^B^A == B;
class Solution {
public:
    int singleNumber(int A[], int n) {
        int ret = 0;
        for (int i = 0; i < n; i++) {
            ret = ret ^ A[i];
        }
        return ret;
    }
};
Update on Dec-26-2014
other solutions:
#1 hashmap
#2 sort
Single Number II
Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
-----------------------------------------------------------------
Solution #1
Consider all numbers in binary format. Using an array to contain the result of bits count mod by 3
class Solution {
public:
    int singleNumber(int A[], int n) {
        vector<int> v(32,0);
        int ret = 0;
        for (int i = 0; i < 32; i++) {
            for (int j = 0; j < n; j++) {
                if ((A[j] >> i) & 1) {
                    v[i] = (v[i] + 1) % 3;
                }
            }
            ret |= (v[i] << i); 
        }
        return ret;
    }
};
Update on Dec-26-2014
vector can be replaced with a single variable
Solution #2
one contains bits that are shown once, two is for twice.
on
class Solution {
public:
    int singleNumber(int A[], int n) {
        int one = 0, two = 0, three = 0;
        for (int i = 0; i < n; i++) {
            two = two | (one & A[i]); // plus bits shown in both one and A[i], now two may contain bits that show 3 times 
            one = one ^ A[i]; // discard bits that have been shown twice
            three = ~ (one & two); // find bits that are in both one and two, then invert them
            
            // discard bits that have been shown 3 times
            one = one & three; 
            two = two & three;
        }
        return one;
    }
};
COME_BACK
https://leetcode.com/discuss/6632/challenge-me-thx
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int one = 0, two = 0;
        for (int i = 0; i < nums.size(); i++) {
            one = ~two & (nums[i] ^ one);
            two = ~one & (nums[i] ^ two);
        }
        
        return one;
    }
};

Day 70, ##, Candy

Candy
There are N children standing in a line. Each child is assigned a rating value.
You are giving candies to these children subjected to the following requirements:
  • Each child must have at least one candy.
  • Children with a higher rating get more candies than their neighbors.
What is the minimum candies you must give?
---------------------------------------------------------
Solution #1, O(n) space and complexity
scan ratings twice, from beginning to end then backwards
class Solution {
public:
    int candy(vector<int> &ratings) {
        int n = ratings.size();
        vector<int> candy(n,1);
        for (int i = 1; i < n; i++) {
            if (ratings[i] > ratings[i - 1]) {
                candy[i] = candy[i - 1] + 1;
            }
        }
        
        int sum = candy[n - 1];
        for (int i = n -2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1] && candy[i] <= candy[i + 1]) {
                candy[i] = candy[i + 1] + 1;
            }
            sum += candy[i];
        }
        return sum;
    }
};
Solution#2, O(1) space, but hard to get all corner cases right
Update on Dec-24-2014 
constant space
Constant space, O(n) complexity
#1 When index reaches 1 or 2, all candies at indexes before 1 or 2 can be finalized. So update totalCandy, clear curSum, reset current candy given at current index, top index and topCandy
#2 When ratings[i] < ratings[i - 1], increment all candies between current index and top(both should be exclusive) by one, and add 1 candy for current index. Then check if candies at [top], which is topCandy, is equal to i - top. if it is the case, increment topCandy and curSum.
for example, index_1 has 3 candies, index_3 has 3, index_4 has 2, we have to give one more candy to index_1


class Solution {
public:
    int candy(vector<int> &ratings) {
        int top = 0;
        int totalCandy = 0;
        int curSum = 1;
        int candy = 1;
        int topCandy = 1;
        
        for (int i= 1; i < ratings.size(); i++) {
            if (ratings[i] < ratings[i - 1]) {
                curSum += i - top - 1 + 1; // for clarity
                if (topCandy == i - top) {
                    curSum++;
                    topCandy++;
                }
                candy = 1;
            }else if (ratings[i] == ratings[i - 1]) {
                candy = 1;
                top = i;
                totalCandy += curSum;
                curSum = 1;
                topCandy = 1;
            }else {
                top = i;
                candy++;
                totalCandy += curSum;
                curSum = candy;
                topCandy = candy;
            }
        }
        
        return totalCandy + curSum;
    }
};

Sunday, December 29, 2013

Day 69, #130, #132, ##, Surrounded Regions, Palindrome Partitioning II, Clone Graph

Surrounded Regions
Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region .
For example,

X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:
X X X X
X X X X
X X X X
X O X X
------------------------------------------------------------------------------
Solution #1 dfs, cannot pass the latest test case, which has size of 200*200
Slot that is neither on the borders or has no path leading to the borders is to be turned.
class Solution {
public:
    void turn (int row, int col, vector<vector<char>> &board) {
        if (row < 0 || row >= board.size() || col < 0 || col >= board[0].size() || board[row][col] != 'O' ) {
            return;
        }
        
        board[row][col] = 'T';
        turn(row + 1, col, board);
        turn(row - 1, col, board);
        turn(row, col + 1, board);
        turn(row, col - 1, board);
    }

    void solve(vector<vector<char>> &board) {
        int m = board.size();
        if (m == 0) return;
        int n = board[0].size();
        
        for (int row = 0; row < m; row++) {
            turn(row,0,board); 
            turn(row,n - 1,board); 
        }
        
        for (int col = 0; col < n; col++) {
            turn(0,col,board); 
            turn(m - 1,col,board); 
        }
        
        for (int row = 0; row < m; row++) {
            for (int col = 0; col < n; col++) {
                if (board[row][col] == 'O') {
                    board[row][col] = 'X';
                }else if (board[row][col] == 'T') {
                    board[row][col] = 'O';
                }  
            }
        }
        
    }
};
Update on Nov-25-2014
Solution #2 another dfs, cannot pass the latest test case, which is size of 200*200
class Solution {
public:
    bool turn(vector<vector<char> > &board, vector<vector<bool> > &visit, int row, int col) {
        if (row < 0 || row >= board.size() || col < 0 || col >= board[0].size()) {
            return false;
        }

        if (board[row][col] == 'X' || !visit[row][col]) {
            return true;
        }
        
        visit[row][col] = false;
        if (turn(board,visit,row - 1,col) && turn(board,visit,row + 1,col) 
            && turn(board,visit,row,col - 1) && turn(board,visit,row,col + 1)) {
            board[row][col] = 'X';
        }
    }

    void solve(vector<vector<char>> &board) {
        int rows = board.size();
        if (rows == 0) return;
        int cols = board[0].size();
        vector<vector<bool> > visit(rows,vector<bool>(cols,true));
        
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                
                if (board[row][col] == 'O' && visit[row][col]) {
                    turn(board,visit,row,col);
             
                }
            }
        }
        
    }
};
Solution #3, bfs, similar approach as solution #1
class Solution {
public:
    void turn (vector<vector<char>> &board, int row, int col) {
        queue<pair<int,int>> que;
        que.push(make_pair(row,col));
        board[row][col] = 'T';
        
        while (!que.empty()) {
            row = que.front().first;
            col = que.front().second;
            que.pop();
            
            if (row > 0 && board[row - 1][col] == 'O') {
                que.push(make_pair(row - 1,col));
                board[row - 1][col] = 'T';
            }
            if (row < board.size() - 1 && board[row + 1][col] == 'O') {
                que.push(make_pair(row + 1,col));
                board[row + 1][col] = 'T';
            }
            if (col > 0 && board[row][col - 1] == 'O') {
                que.push(make_pair(row,col - 1));
                board[row][col - 1] = 'T';
            }
            if (col < board[0].size() - 1 && board[row][col + 1] == 'O') {
                que.push(make_pair(row,col + 1));
                board[row][col + 1] = 'T';
            }
        }
    }

    void solve(vector<vector<char>> &board) {
        int m = board.size();
        if (m == 0) return;
        int n = board[0].size();
        
        for (int i = 0; i < m; i++) {
            if (board[i][n - 1] == 'O') {
                turn(board,i,n - 1);
            }
            if (board[i][0] == 'O') {
                turn(board,i,0);
            }
        }
        
        for (int i = 0; i < n; i++) {
            if (board[0][i] == 'O') {
                turn(board,0,i);
            }
            if (board[m - 1][i] == 'O') {
                turn(board,m - 1,i);
            }
        }
        
        for (int row = 0; row < m; row++) {
            for (int col = 0; col < n; col++) {
                if (board[row][col] == 'O') {
                    board[row][col] = 'X';
                }else if (board[row][col] == 'T') {
                    board[row][col] = 'O';
                } 
            }
        }
        
    }
};
Palindrome Partitioning II
Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.
-------------------------------------------------------------------------
DP
dp[i] has the minimum cuts of string s[i : end]
if s[i : j], i <= j < n  forms a palindrome, dp[i] = min(dp[i], dp[j] + 1)
watch out for the special case: s[i : end] is a palindrome

using dp for palindrome verification as well

class Solution {
public:
    int minCut(string s) {
        int n = s.length();
        vector<int> dp(n + 1,0);
        vector<vector<bool> > pal(n,vector<bool>(n,false));
        
        // populate tables
        for (int i = n - 1; i >= 0; i--) {
            dp[i] = n - 1 - i;
            for (int j = i; j < n; j++) {
                if (s[i] == s[j] && (j - i < 2 || pal[i + 1][j - 1])) {
                    pal[i][j] = true;    
                }
            }
        }
        
        // dp
        for (int i = n - 1; i >= 0; i--) {
            for (int j = i; j < n; j++) {
                if (pal[i][j]) {
                    if (j == n-1) { 
                        // special case: s[i:e] is a palindrome
                        // hence no cut needed
                        dp[i] = 0;
                    }
                    else {
                        dp[i] = min(dp[i],dp[j + 1] + 1);
                    }
                }
            }
        }
        return dp[0];
    }
};

recursion with memoization
class Solution {
public:
    bool isPal(string s) {
        for (int i = 0; i < s.length() / 2; i++) {
            if (s[i] != s[s.length() - 1 - i]) {
                return false;
            }
        }
    
        return true;
    }

    int cuts(string s, unordered_map<string,int> &dic) {
        int minC = INT_MAX;
        for (int i = 0; i < s.length() - 1; i++) {
         string s1 = s.substr(0,i + 1);
         string s2 = s.substr(i + 1);
         int temp1 = 0;
            int temp2 = 0;
            
            if (dic.find(s1) != dic.end()) {
                temp1 = dic[s1];
            }else {
                if (isPal(s1)) {
                    temp1 = 0;
                }else {
                    temp1 = cuts(s1,dic);
                }
          dic[s1] = temp1;
            }
            
            if (dic.find(s2) != dic.end()) {
                temp2 = dic[s2];
            }else {
                if (isPal(s2)) {
                    temp2 = 0;
                }else {
                    temp2 = cuts(s2,dic);
                }
             dic[s2] = temp2;
            }
            
            minC = min(minC, temp1 + temp2 + 1);
        }
        
        dic[s] = minC;
        return minC;
    }

    int minCut(string s) {
        if (isPal(s)) return 0;
        unordered_map<string,int> dic;
        return cuts(s,dic);
    }
};
Clone Graph
Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.
-----------------------------------------------------------
Typical BFS, can be solved iteratively by using a queue
Note: map new node to old node, updates have to be done with nodes stored in the map

/**
 * Definition for undirected graph.
 * struct UndirectedGraphNode {
 *     int label;
 *     vector<UndirectedGraphNode *> neighbors;
 *     UndirectedGraphNode(int x) : label(x) {};
 * };
 */
class Solution {
public:
    UndirectedGraphNode* cpGraph (UndirectedGraphNode *node, unordered_map<UndirectedGraphNode*,UndirectedGraphNode*>& mapping) {
        if (mapping.find(node) != mapping.end()) {
            return mapping[node];
        }
        
        UndirectedGraphNode *cp = new UndirectedGraphNode(node->label);
        mapping[node] = cp;
        mapping[node]->neighbors = node->neighbors;
        for (int i = 0; i < node->neighbors.size(); i++) {
            mapping[node]->neighbors[i] = cpGraph(node->neighbors[i],mapping);     
        }
        
        return cp;
    }

    UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        if (node == NULL) return NULL;
        unordered_map<UndirectedGraphNode*, UndirectedGraphNode*> mapping;
        
        UndirectedGraphNode *cp = new UndirectedGraphNode(node->label);
        mapping[node] = cp;
        mapping[node]->neighbors = node->neighbors;
        for (int i = 0; i < node->neighbors.size(); i++) {
            mapping[node]->neighbors[i] = cpGraph(node->neighbors[i],mapping);     
        }
        return cp;
    }
};
Update on Dec-23-2014
refactoried
 
/**
 * Definition for undirected graph.
 * struct UndirectedGraphNode {
 *     int label;
 *     vector<UndirectedGraphNode *> neighbors;
 *     UndirectedGraphNode(int x) : label(x) {};
 * };
 */
class Solution {
public:
    UndirectedGraphNode *clone (UndirectedGraphNode *node,unordered_map<int,UndirectedGraphNode*> &dic) {
        if (dic.find(node->label) != dic.end()) {
            return dic[node->label];
        }
        
        UndirectedGraphNode *cp = new UndirectedGraphNode(node->label);
        dic[node->label] = cp;
        cp->neighbors = node->neighbors;
        for (int i = 0; i < node->neighbors.size(); i++) {
            cp->neighbors[i] = clone(node->neighbors[i],dic);
        }
        
        return cp;
    }

    UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
        if (node == NULL) return NULL;
        
        unordered_map<int,UndirectedGraphNode*> dic;
        return clone(node,dic);
    }
};

Update on Jun-23-2018
Java, bfs,
要记得存map!!!
/**
 * Definition for undirected graph.
 * class UndirectedGraphNode {
 *     int label;
 *     List neighbors;
 *     UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList(); }
 * };
 */
public class Solution {
    public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
        if (node == null) return null;
        
        Queue que = new LinkedList<>();
        Map map = new HashMap<>();
        
        que.add(node);
        map.put(node, new UndirectedGraphNode(node.label));
        
        while (!que.isEmpty()) {
            UndirectedGraphNode top = que.poll();
            UndirectedGraphNode clone = map.get(top);
                
            for (UndirectedGraphNode n : top.neighbors) {
                UndirectedGraphNode nClone;
                if (map.containsKey(n)) {
                    nClone = map.get(n);
                }else {
                    nClone = new UndirectedGraphNode(n.label);
                    que.add(n);
                    map.put(n, nClone);
                }
                
                clone.neighbors.add(nClone);
            }
        }
        
        return map.get(node);
    }
}

Saturday, December 28, 2013

Day 68, #128, Longest Consecutive Sequence

Longest Consecutive Sequence
Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
For example,
Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.
Your algorithm should run in O(n) complexity.
----------------------------------------------------------------------------
O(n),using a hash to map an integer and its number of consecutive integers found so far, initialized as 0
3 scenarios we have to tackle:
1) found connecting number on both left and right sides, attach 2 segments together
2) only the right
3) only the left
class Solution {
public:
    int longestConsecutive(vector<int> &num) {
        unordered_map<int,int> mapping;
        int maxLen = 0;
        for (int i = 0; i < num.size(); i++) {
            int key = num[i]; 

            // skip duplicates
            if (mapping.find(key) == mapping.end()) {
                mapping[key] = 0;
            }else continue;
            
            if (mapping.find(key - 1) != mapping.end() && mapping.find(key + 1) != mapping.end() ) {
                int left = key - 1 - mapping[key - 1]; // find index of the left most number on current segment
                int right = key + 1 + mapping[key + 1]; // find index of the rightmost number on current segment
                mapping[left] += 2 + mapping[right]; // watch out for 2 
                mapping[right] = mapping[left];
                maxLen = max(mapping[left],maxLen);
            }else if (mapping.find(key - 1) != mapping.end()) {
                int left = key - 1 - mapping[key - 1];
                mapping[left]++;
                mapping[key] = mapping[left];
                maxLen = max(mapping[left],maxLen);
            }else if (mapping.find(key + 1) != mapping.end() ) {
                int right = key + 1 + mapping[key + 1];
                mapping[right]++;
                mapping[key] = mapping[right];
                maxLen = max(mapping[right],maxLen);
            }
        }
        return maxLen + 1;
    }
};
Update Nov-23-2014
Another approach
class Solution {
public:
    int longestConsecutive(vector<int> &num) {
        unordered_map<int,bool> mapping;
        for (int i = 0; i < num.size(); i++) {
            mapping[num[i]] = true;
        }
        
        int longest = 0;
        for (int i = 0; i < num.size(); i++) {
            if (!mapping[num[i]]) continue;
            mapping[num[i]] = false;
            int left = num[i] - 1, right = num[i] + 1;
            int length = 1;
            
            while (mapping[left] || mapping[right]) {
                if (mapping[left]) {
                    mapping[left] = false;
                    length++;
                    left--;
                }
                if (mapping[right]) {
                    mapping[right] = false;
                    length++;
                    right++;
                }
            }
            
            longest = max(longest,length);
        }
        
        return longest;
    }
};
变种题:array可能变为tree,对于无重复的可以只记录范围,来节省空间

Friday, December 27, 2013

Day 67, #117, #123, #124, Populating Next Right Pointers in Each Node II, Best Time to Buy and Sell Stock III, Binary Tree Maximum Path Sum

Populating Next Right Pointers in Each Node II
Follow up for problem "Populating Next Right Pointers in Each Node".
What if the given tree could be any binary tree? Would your previous solution still work?
Note:
  • You may only use constant extra space.
For example,
Given the following binary tree,

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

         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \    \
    4-> 5 -> 7 -> NULL
-----------------------------------------------------------------------
Same exact solution to #116 Populating Next Right Pointers in Each Nod
/**
 * 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 travese (TreeLinkNode* root, vector<TreeLinkNode*> &tails, int level) {
        if (root == NULL) {
            return;
        }
        if (tails.size() < level) {
            tails.push_back(root);
        }else {
            tails[level - 1]->next = root;
            tails[level - 1] = root;
        }
        travese(root->left,tails,level + 1);
        travese(root->right,tails,level + 1);
    }

    void connect(TreeLinkNode *root) {
        vector<TreeLinkNode*> tails;
        travese(root,tails,1);
    }
};
Update Feb-19-2015
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) {
            TreeLinkNode *cur = root, *pre = NULL, *nextLevel = NULL;
            
            while (cur) {
                if (cur->left != NULL) {
                    if (nextLevel == NULL) nextLevel = cur->left;
                    if (pre == NULL) pre = cur->left;
                    else {
                        pre->next = cur->left;
                        pre = cur->left;
                    }
                }
                
                if (cur->right != NULL) {
                    if (nextLevel == NULL) nextLevel = cur->right;
                    if (pre == NULL) pre = cur->right;
                    else {
                        pre->next = cur->right;
                        pre = cur->right;
                    }
                }
                
                cur = cur->next;
            }
            root = nextLevel;
        }
    }
};
Best Time to Buy and Sell Stock III
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 at most two transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
------------------------------------------------------------------------------------------
DP
Divide prices[] in two parts, each which is solved as in #121 Best Time to Buy and Sell Stock
the max profit would be the largest value of  firstPart[i] + secondPart[i]
class Solution {
public:
    int maxProfit(vector<int> &prices) {
        if (prices.size() == 0) return 0;
        vector<int> dp1(prices.size(),0);
        vector<int> dp2 = dp1;
        
        int minimun = prices[0];
        for (int i = 1; i < prices.size(); i++) {
            dp1[i] = max(dp1[i - 1], prices[i] - minimun);
            minimun = min(prices[i],minimun);
        }
        
        int maximum = prices.back();
        for (int i = prices.size() - 2; i >= 0; i--) {
            dp2[i] = max(dp2[i + 1], maximum - prices[i]);
            maximum = max(prices[i],maximum);
        }
        
        int maxProfit = 0;
        for (int i = 0; i < prices.size(); i++) {
            maxProfit = max(dp1[i] + dp2[i],maxProfit);
        }
        return maxProfit;
    }
};
Binary Tree Maximum Path Sum
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.
--------------------------------------------------------------------------
Two scenarios:
1) Current node is the root(top) node of the path
2) Current node is in either left or right sub-tree of the path
Hence, according to the 1st, we have to include the sum of both left and right sub-trees when we calculate maximum. In another word, we produce its maximum value for each node in binary tree. But according to the 2nd, return back to upper level in recursive stack with only one or non of sub-trees.  
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int pathSum(TreeNode *root,int &maximumPath) {
        if (root == NULL) {
            return INT_MIN;
        }
        
        int leftSum = max(0,pathSum(root->left,maximumPath));
        int rightSum = max(pathSum(root->right,maximumPath),0);
        
        maximumPath = max(maximumPath,leftSum + rightSum + root->val);
        return max(leftSum,rightSum) + root->val;
    }

    int maxPathSum(TreeNode* root) {
        int m = INT_MIN;
        pathSum(root,m);
        return m;
    }
};


另一种写法
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int helper(TreeNode *root,int *sum) {
        if  (root == NULL) {
            *sum = 0;
            return INT_MIN;
        }
        
        int ls = 0, rs = 0;
        int leftM = helper(root->left,&ls);
        int rightM = helper(root->right,&rs);
        
        ls = max(ls,0);
        rs = max(rs,0);
        *sum = max(ls,rs) + root->val;
        
        return max(ls + rs + root->val, max(leftM,rightM));
    }


    int maxPathSum(TreeNode* root) {
        int sum = 0;
        return helper(root,&sum);
    }
};

Thursday, December 26, 2013

Day 66, #103, #115, Binary Tree Zigzag Level Order Traversal, Distinct Subsequences

Binary Tree Zigzag Level Order Traversal
Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).
For example:
Given binary tree {3,9,20,#,#,15,7},

    3
   / \
  9  20
    /  \
   15   7
return its zigzag level order traversal as:

[
  [3],
  [20,9],
  [15,7]
]
----------------------------------------------------------------------
Similar to #102 Binary Tree Level Order 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:
    vector<vector<int> > ret;
    
    void stackOrder2 (vector<int>& level, stack<TreeNode*>& cur, stack<TreeNode*>& next) {
        while (!cur.empty()) {
            TreeNode* node = cur.top();
            cur.pop();
            level.push_back(node->val);
            if (node->right != NULL) {
                next.push(node->right);
            }
            if (node->left != NULL) {
                next.push(node->left);
            }
        }
    }

    void stackOrder1 (vector<int>& level, stack<TreeNode*>& cur, stack<TreeNode*>& next) {
        while (!cur.empty()) {
            TreeNode* node = cur.top();
            cur.pop();
            level.push_back(node->val);
            if (node->left != NULL) {
                next.push(node->left);
            }
            if (node->right != NULL) {
                next.push(node->right);
            }
        }
    }

    vector<vector<int> > zigzagLevelOrder(TreeNode *root) {
        stack<TreeNode*> st1, st2;
        if (root == NULL) return ret;
        int levelCount = 0;
        st1.push(root);
        while (!st1.empty() || !st2.empty()) {
            vector<int> level;
            if (levelCount % 2 == 0) {
                stackOrder1(level,st1,st2);
            }else {
                stackOrder2(level,st2,st1);
            }
            ret.push_back(level);
            levelCount++;
        }
        return ret;
    }
};

更新,Sep-10-2015
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> zig(vector<vector<int>> &rt,queue<TreeNode*> &que) {
        int size = que.size();
        vector<int> cur;
        
        while (size > 0) {
            TreeNode *t = que.front();
            que.pop();
            cur.push_back(t->val);
            if (t->left != NULL) que.push(t->left);
            if (t->right != NULL) que.push(t->right);
            size--;
        }
        
        return cur;
    }


    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> rt;
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        int level = 0;
        
        while (!que.empty()) {
            vector<int> cur = zig(rt,que);
            if (level % 2 == 1) {
                reverse(cur.begin(),cur.end());
            }
            rt.push_back(cur);
            level++;
        }
        
        return rt;
    }
};

Distinct Subsequences
--------------------------------------------------------------
Classic DP
Further reading:
http://stackoverflow.com/questions/20459262/distinct-subsequences-dp-explanation
class Solution {
public:
    int numDistinct(string S, string T) {
        int m = S.length();
        int n = T.length();
        vector<vector<int> > dp(m+1,vector<int>(n+1,0));
        
        for (int i = 0; i < m + 1; i++) {
            dp[i][n] = 1;
        }
        
        for (int i = m - 1; i >= 0; i--) {
            for (int j = 0; j < n; j++) {
                if (S[i] == T[j]) {
                    dp[i][j] = dp[i+1][j] + dp[i+1][j+1];
                }else {
                    dp[i][j] = dp[i+1][j];
                }
            }
        }
        return dp[0][0];
    }
};
Update Nov-21-2014
If S[i] != T[j], we know that N[i][j] = N[i+1][j]
If S[i] = T[j], we have a choice. We can either 'match' these characters and go on with the next characters of both S and T, or we can ignore the match (as in the case that S[i] != T[j]).

递归:
COME_BACK
遇到这种题时,找小的test case,为了发现规律:如(ab, b)
int distinct(string s,string t) {
    if (t.length() == 0) return 1;
    if (s.length() == 0) return 0; 
    
    if (s[0] == t[0]) {
        return foo(s.substr(1),t.substr(1)) + foo(s.substr(1),t);
    }
    return foo(s.substr(1),t);
}

Wednesday, December 25, 2013

Day 65 - 2, #95, #99, Unique Binary Search Trees II, Recover Binary Search Tree

Unique Binary Search Trees II
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
-----------------------------------------------------------------------------------------
COME_BACK, Catalan number
Similar to #96 Unique Binary Search Trees
resource: http://mathcircle.berkeley.edu/BMC6/pdf0607/catalan.pdf
there is space for optimization
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<TreeNode *> helper(int start, int end) {
        vector<TreeNode*> rt;
        for (int i = start; i <= end; i++) {
            vector<TreeNode*> left = helper(start,i - 1);
            vector<TreeNode *> right = helper(i + 1, end);
            for (int j = 0; j < left.size(); j++) {
                for (int k = 0; k < right.size(); k++) {
                    TreeNode *root = new TreeNode(i + 1);
                    root->left = left[j];
                    root->right = right[k];
                    rt.push_back(root);
                }
            }
        }
        if (rt.size() == 0) rt.push_back(NULL);
        return rt;
    }

    vector<TreeNode*> generateTrees(int n) {
        return helper(0,n - 1);
    }
};

iterative,
OJ的要求的root左边的value一定比它小,右边一定被它大,因为是BST
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode *deepCopy(TreeNode *root,int offset) {
        if (root == NULL) return NULL;
        TreeNode *newRoot = new TreeNode(root->val + offset);
        newRoot->left = deepCopy(root->left,offset);
        newRoot->right = deepCopy(root->right,offset);
        return newRoot;
    }

    vector<TreeNode*> generateTrees(int n) {
        vector<TreeNode*> rt;
        vector<vector<TreeNode *>> dp(n + 1,vector<TreeNode*>());
        dp[0].push_back(NULL);
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < i; j++) {
                for (int left = 0; left < dp[j].size(); left++) {
                    for (int right = 0; right < dp[i - j - 1].size(); right++) {
                        TreeNode *root = new TreeNode(j + 1);
                        root->left = deepCopy(dp[j][left],0);
                        //root->left = dp[j][left];
                        root->right = deepCopy(dp[i - j - 1][right],j + 1);
                        dp[i].push_back(root);
                    }
                }
            }
        }
        
        return dp[n];
    }
};
O(1)额外空间
https://leetcode.com/discuss/20399/share-a-c-dp-solution-with-o-1-space
Recover Binary Search Tree
Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?
-------------------------------------------------------
Solution #1: O(n) space - construct an array of size n, populate it by traversing tree in in-order...

Solution #2: in-space and iterative. Morris traversal:
http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-stack/ 

Solution #3: In-space - typical in-order traversal , reach to the left most node, then walk back to the right most.
pre points to the node right before the current node in serialized binary tree.
The following code implements #3.
/**
 * 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 *pre;
    TreeNode* first;
    TreeNode* second;

    void inorder (TreeNode *root) {
        if (root == NULL) {
            return;
        }
        
        inorder(root->left);
        if (pre == NULL) {
            pre = root;
        }
        
        // found it!
        if (pre->val > root->val) {
            if (first == NULL) {
                first = pre;
            }
            second = root;
        }
        
        pre = root;
        inorder(root->right);
    }

    void recoverTree(TreeNode *root) {
        pre = NULL;
        first = NULL;
        inorder(root);
        int temp = first->val;
        first->val = second->val;
        second->val = temp;
    }
};
Update Nov-19-2014 
watch out for pointer passing  as argument in C++