Saturday, May 31, 2014

LeetCode: Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.


We can copy each nodes first and make the copied node connected to the old one. And then it is easier to copy the random pointer by node.next.random = node.random.next because each node, its next node is its copied node.

C++ Code:

/*
 * func: copy_list_with_random_pointer
 * goal: deep copy a list with random pointer
 * @param head: head node of the list
 * return: new head node of the list
 */
RandomListNode *copy_list_with_random_pointer(RandomListNode *head){
    if(head == nullptr){
        return nullptr;
    }
    
    RandomListNode *iter = head;
    //Copy the list sequentially first
    //t1->t1_cpy->t2->t2_cpy->NULL
    while(iter != nullptr){
        //Get current node's next first
        RandomListNode *next = iter->next;
        //Copy current node
        iter->next = new RandomListNode(iter->label);
        //Connect copied node to the next node
        iter->next->next = next;
        //Go to the next node
        iter = next;
    }

    iter = head;
    while(iter != nullptr){
        //Get current node's next node first
        RandomListNode *next = iter->next->next;
        //Copy random pointer
        iter->next->random = iter->random == nullptr ? nullptr : iter->random->next;
        //Go to the next node
        iter = next;
    }
    
    //Set the new head
    RandomListNode *new_head = head->next;
    iter = head;
    while(iter != nullptr){
        RandomListNode *next = iter->next->next;
        //Connect the current node's next to the next node's copy node
        iter->next->next = next == nullptr ? nullptr : next->next;
        //Re-connect current node to its original next node
        iter->next = next;
        //Go to the next node
        iter = next;
    }


    return new_head;
}

Python Code:

# func: copy linked list with random pointers
# @param head: head node of the list
# @return: new head node
def copy_random_list(head):
    if not head:
        return None

    #Copy nodes first
    curr = head
    while curr:
        next_node = curr.next
        curr.next = RandomListNode(curr.label)
        curr.next.next = next_node
        curr = next_node

    #Copy random pointer
    curr = head
    while curr:
        next_node = curr.next.next
        curr.next.random = curr.random.next if curr.random else None
        curr = next_node

    #Split two lists
    new_head = head.next
    curr = head
    while curr:
        next_node = curr.next.next
        curr.next.next = next_node.next if next_node else None
        curr.next = next_node
        curr = next_node
    return new_head

LeetCode: 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?


We can solve this in bit level. Each integer is also a bit array of size 32. We can count the number of 1 occurred in each bit. If its 4 or 1, then the bit of the single number is also 1. Otherwise it is 0.

C++ Code:

/*
 * func: single_number
 * goal: find the single number in an array that occurs once
 * @param A: input array A
 * @param n: size of the array
 * return: the single number
 */
int singleNumber(int A[], int n) {
    vector<int> tmp;
    for(int i = 0; i < 32; ++i){
        int bit_count = 0;
        int curr_bit = 1 << i;
        for(int j = 0; j < n; j++){
            if(A[j] & curr_bit)
                ++bit_count;
        }
        (bit_count % 3) ? tmp.emplace_back(1) : tmp.emplace_back(0);
    }
    int num = 1;
    int result = 0;
    for(const int &digit : tmp){
        if(digit){
            result += num;
        }
        num <<= 1;
    }
    return result;
}

Python Code:

# func: find the single number in a list
# @param A: input list
# @return: single number
def single_numer(A):
    if not A:
        return 0
    digits = []
    for i in xrange(32):
        curr = 1 << i
        digit_count = 0
        for num in A:
            if num & curr:
                digit_count += 1
        if digit_count % 3:
            digits.append(1)
        else:
            digits.append(0)

    result = 0
    bit_helper = 1
    for digit in digits:
        if digit == 1:
            result += bit_helper
        bit_helper <<= 1

    if digits[-1] == 1:
        return result - (1 << 32)
    else:
        return result

LeetCode: 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?


We can use the binary operation xor to find out the single number. Since a xor a = 0 and 0 xor 0 = 0 and 0 xor 1 = 1.

C++ Code:

/*
 * func: single_number
 * goal: find the single number in an array that occurs once
 * @param A: input array A
 * @param n: size of the array
 * return: the single number
 */
int single_number(int A[], int n){
    if(n <= 0){
        return 0;
    }
    int num = A[0];
    for(int i=1; i<n; ++i){
        num ^= A[i];
    }
    return num;
}

Python Code:

# func: find the single number in a list
# @param A: input list
# @return: single number
def single_numer(A):
    if not A:
        return 0
    result = A[0]
    for i in xrange(1, len(A)):
        result ^= A[i]

    return result

LeetCode: 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?


We can start distribution by giving each child 1 candy. And then if child i has a higher rating than child i-1, give him one more. Then from back to the front, if child i has a higher rating than child i+1, given him the number of candies as child i+1's plus 1.

C++ Code:

/*
 * func: candy
 * goal: find the minimum candies needed to distribute
 * @param ratings: ratings of the children
 * return: minimum candies
 */
/*
 * distribute from start to end and then from end to start
 * complexity: time O(n), space O(n)
 */
int candy(vector<int> &ratings){
    if(ratings.size() == 0){
        return 0;
    }
    vector<int> candies(ratings.size(), 0);
    candies[0] = 1;
    for(int i = 1; i < ratings.size(); ++i){
        //If the child's ratings at i is higher than i-1, he should have at least one more candy
        candies[i] = ratings[i] > ratings[i-1] ? candies[i-1]+1 : 1;
    }
    //check from end to the start to ensure every child get what they need to have
    int total_candy = candies[ratings.size() - 1];
    for(int i = ratings.size() - 2; i >= 0; --i){
        candies[i] = (ratings[i] > ratings[i+1] && candies[i+1] + 1 > candies[i]) ? candies[i+1] + 1 : candies[i];
        total_candy += candies[i];
    }
    return total_candy;
}

Python Code:

# func: find the minimum candies
# @param ratings: the ratings of child
# @return: minimum candies needed
# complexity: time O(n), space O(n)
def candy(ratings):
    if not ratings:
        return 0
    candies = [1] * len(ratings)
    for i in xrange(1, len(ratings)):
        if ratings[i] > ratings[i-1]:
            candies[i] = candies[i-1]+1

    total_candies = candies[-1]
    for i in xrange(len(ratings)-2, -1, -1):
        if ratings[i] > ratings[i+1] and candies[i] < candies[i+1] + 1:
            candies[i] = candies[i+1]+1
        total_candies += candies[i]

    return total_candies

LeetCode: Gas Station

There are N gas stations along a circular route, where the amount of gas at station i is gas[i].

You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.

Return the starting gas station's index if you can travel around the circuit once, otherwise return -1.

Note:
The solution is guaranteed to be unique.


Since it is a circle, we can assume the start point is 0, when the gas is not enough to use, we can make the start point backwards one stop and see if current start point is available.

C++ Code:

/*
 * func: can_complete_circuit
 * goal: find the starting gas station that can make the truck travel the circuit
 * @param gas: gas vector
 * @param cost: cost vector
 * return: starting index
 */
int can_complete_circuit(vector<int> &gas, vector<int> &cost){
    int stop_num = gas.size();
    int start = 0;
    int end = stop_num-1;
    int current = 0;
    int remaining = 0;
    while(current <= end){
        remaining += gas[current] - cost[current];
        while(remaining < 0 && end != current){
            start = end;
            end = end-1;
            remaining += gas[start] - cost[start];
        }
        ++current;
    }
    
    return remaining < 0 ? -1 : start;
}

Python Code:

# func: find the starting gas station that can make the truck travel the circuit
# @param gas: gas list
# @param cost: cost list
# @return: the start position
def can_complete_circuit(gas, cost):
    start = 0
    end = len(gas)-1
    current = 0
    remaining = 0
    while current <= end:
        remaining += gas[current] - cost[current]
        while remaining < 0 and current != end:
            start = end
            end -= 1
            remaining += gas[start] - cost[start]
        current += 1

    if remaining < 0:
        return -1
    else:
        return start

LeetCode: Clone Graph

Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.


We can use BFS to search the graph can clone it at the same time. A map can be used to store those nodes that are already cloned.

C++ Code:

/*
 * func: clone_graph_helper
 * goal: helper function to perform BFS
 * @param node: current node to be cloned
 * @param visited: node already existed in the new graph
 * return: newly cloned node
 */
UndirectedGraphNode *clone_graph_helper(UndirectedGraphNode *node, unordered_map<int, UndirectedGraphNode*> &visited){
    UndirectedGraphNode *new_node = new UndirectedGraphNode(node->label);
    visited[node->label] = new_node;
    for(int i = 0; i < node->neighbors.size(); ++i){
        if(visited.find(node->neighbors[i]->label) != visited.end()){
            new_node->neighbors.emplace_back(visited[node->neighbors[i]->label]);
        }else{
            new_node->neighbors.emplace_back(clone_graph_helper(node->neighbors[i], visited[node->neighbors[i]->label]));
        }
    }
    
    return new_node;
}

/*
 * func: clone_graph
 * goal: clone a undirected graph
 * @param node: a start node
 * return: a cloned start node
 */
UndirectedGraphNode *clone_graph(UndirectedGraphNode *node){
    if(node == nullptr){
        return nullptr;
    }
    unordered_map<int, UndirectedGraphNode*> visited;
    UndirectedGraphNode* new_node = clone_graph_helper(node, visited);
    return new_node;
}

Python Code:

# func: clone graph
# @param node: start node
# @return: new start node
def clone_graph(node):
    if not node:
        return None

    visited = {}
    def clone_graph_helper(start):
        new_node = UndirectedGraphNode(start.label)
        visited[start.label] = new_node
        for neighbor in start.neighbors:
            if neighbor.label in visited:
                new_node.neighbors.append(visited[neighbor.label])
            else:
                new_node.neighbors.append(clone_graph_helper(neighbor))
        return new_node

    return clone_graph_helper(node)

Friday, May 30, 2014

LeetCode: 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.


The problem can be transformed to the following: minimum[i:n] means the minimum cut we needed for substring s[i:n], and it could be the minimum of minimum[j+1:n]+1 for all i <= j < n.

C++ Code:

/*
 * func: min_cut
 * goal: find the minimum number of min_cut so that each partition is a palindrome
 * @param s: input string
 * return: minimum cut
 */
int min_cut(string s){
    size_t str_length = s.length();
    if(str_length == 0){
        return 0;
    }
    //a 2D array which indicate if substring(i, j) is a palindrome
    vector<vector<bool> > palindrome(str_length, vector<bool>(str_length, false));
    for(int i = 0; i < str_length; ++i){
        //Check palindrome taking s[i] as symmetry axis
        int left = i;
        int right = i;
        while(left >= 0 && right < str_length && s[left] == s[right]){
            palindrome[left][right] = true;
            --left;
            ++right;
        }
        //Check palindrome taking s[i] s[i+1] as symmetry axis
        left = i;
        right = i+1;
        while(left >= 0 && right < str_length && s[left] == s[right]){
            palindrome[left][right] = true;
            --left;
            ++right;
        }
    }
    vector<int> minimum_cut(str_length, str_length);
    for(int i = 0; i < str_length; ++i){
        if(palindrome[0][i]){
            minimum_cut[i] = 0;
        }else{
            int min_cut_now = str_length;
            for(int j = 1; j <= i; ++j){
                if(palindrome[j][i] && min_cut_now > minimum_cut[j-1] + 1){
                    min_cut_now = minimum_cut[j-1] + 1;
                }
            }
            minimum_cut[i] = min_cut_now;
        }
    }
    return minimum_cut.back();
}

Python Code:

# func: find the minimum cut needed for a palindrome partitioning of string
# @param s: input string
# @return: minimum cut
def min_cut(s):
    if not s:
        return 0
    palindrome = [[False] * len(s) for _ in xrange(len(s))]
    minimum_cut = [len(s) - i for i in xrange(len(s)+1)]
    for i in xrange(len(s)-1, -1, -1):
        for j in xrange(i, len(s)):
            if s[i] == s[j] and (j-i < 2 or palindrome[i+1][j-1]):
                palindrome[i][j] = True
                minimum_cut[i] = min(minimum_cut[i], minimum_cut[j+1] + 1)

    return minimum_cut[0]-1

Reference Link:

1. 水中的鱼: [LeetCode] Palindrome Partitioning II, Solution: http://fisherlei.blogspot.com/2013/03/leetcode-palindrome-partitioning-ii.html

LeetCode: 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"]
  ]


Use DFS to check every possible partition.

C++ Code:

/*
 * func: valid_palindrome
 * goal: to validate the input string
 * @param s: input string
 * @param left: left searching index
 * @param right: right searching index
 * return:
 */
bool valid_palindrome(string s, int left, int right){
    while(left <= right){
        if(s[left] != s[right]){
            return false;
        }else{
            ++left;
            --right;
        }
    }
    return true;
}

/*
 * func: generate_combination
 * goal: use DFS to generate combinations
 * @param s: input string
 * @param start: start searching index
 * @param combination: current combination
 * @param result: final result set
 * return:
 */
void generate_combination(string s, int start, vector<string> &combination, vector<vector<string> > &result){
    if(start >= s.length()){
        result.emplace_back(combination);
        return;
    }
    for(int i = start; i < s.length(); ++i){
        if(valid_palindrome(s, start, i)){
            string tmp = s.substr(start, i-start+1);
            combination.emplace_back(tmp);
            generate_combination(s, i+1, combination, result);
            combination.pop_back();
        }
    }
}


/*
 * func: palindrome_partition
 * goal: return all possible palindrome partitioning of input string
 * @param s: input string
 * return: all possible combinations
 */
vector<vector<string> > palindrome_partition(string s){
    vector<vector<string> > result;
    vector<string> combination;
    generate_combination(s, 0, combination, result);
    return result;
}

Python Code:

# func: valid if current string is a palindrome
# @param start: start searching index
# @param end: end searching index
# @return: True or False
def valid_palindrome(s, start, end):
    while start <= end:
        if s[start] != s[end]:
            return False
        else:
            start += 1
            end -= 1
    return True

# func: find all possible palindrome partitioning of input string
# @param s: input string
# @return: all possible partitions
def palindrome_partition(s):
    result = []
    combination = []
    def palindrome_partition_helper(start):
        if start >= len(s):
            result.append(combination[:])
            return

        for i in xrange(start, len(s)):
            if valid_palindrome(s, start, i):
                combination.append(s[start:i+1])
                palindrome_partition_helper(i+1)
                combination.pop(-1)
    palindrome_partition_helper(0)
    return result

LeetCode: 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


To solve this problem, we can find those 'O' that is not in the surrounded first and then the remaining parts are in surrounded regions. To achieve this, we can start from the boarder line of the matrix and perform a BFS to find all 'O' that can be reached from the 'O' on boarder line.

C++ Code:

/*
 * func: surrounded_region
 * goal: find all regions surrounded by 'X'
 * @param board: check board
 * return:
 */
/*
 * find all the 'O' that can be reached from 'O' on boarder line. 
 * Then the remaining is surrounded.
 * complexity: time O(n^2), space O(n^2)
 */
void surrounded_region(vector<vector<char> > &board){
    if(board.size() <= 2){
        return;
    }
    size_t board_size_row = board.size();
    size_t board_size_column = board[0].size();
    queue<pair<int, int> > BFS_helper;
    
    //Find 'O' in row boarder line
    for(int column = 0; column < board_size_column; ++column){
        if(board[0][column] == 'O'){
            board[0][column] = 'N';
            BFS_helper.emplace(pair<int, int>{0, column});
        }
        if(board[board_size_row-1][column] == 'O'){
            board[board_size_row-1][column] = 'N';
            BFS_helper.emplace(pair<int, int>{board_size_row-1, column});
        }
    }
    //Find 'O' in column boarded line
    for(int row = 0; row < board_size_row; ++row){
        if(board[row][0] == 'O'){
            board[row][0] = 'N';
            BFS_helper.emplace(pair<int, int>{row, 0});
        }
        if(board[row][board_size_column-1] == 'O'){
            board[row][board_size_column-1] = 'N';
            BFS_helper.emplace(pair<int, int>{row, board_size_column-1});
        }
    }
    //Use a queue to do BFS
    while(!BFS_helper.empty()){
        pair<int, int> current = BFS_helper.front();
        BFS_helper.pop();
        if(current.first > 0 && board[current.first-1][current.second] == 'O'){
            board[current.first-1][current.second] = 'N';
            BFS_helper.emplace(pair<int, int>{current.first-1, current.second});
        }
        if(current.first < board_size_row-1 && board[current.first+1][current.second] == 'O'){
            board[current.first+1][current.second] = 'N';
            BFS_helper.emplace(pair<int, int>{current.first+1, current.second});
        }
        if(current.second > 0 && board[current.first][current.second-1] == 'O'){
            board[current.first][current.second-1] = 'N';
            BFS_helper.emplace(pair<int, int>{current.first, current.second-1});
        }
        if(current.second < board_size_column-1 && board[current.first][current.second+1] == 'O'){
            board[current.first][current.second+1] = 'N';
            BFS_helper.emplace(pair<int, int>{current.first, current.second+1});
        }
    }
    
    for(int row = 0; row < board_size_row; ++row){
        for(int column = 0; column < board_size_column; ++column){
            if(board[row][column] == 'O'){
                board[row][column] = 'X';
            }
            if(board[row][column] == 'N'){
                board[row][column] = 'O';
            }
        }
    }
}

Python Code:

# func: find all regions surrounded by 'X'
# @param board: input board
# @return:
# complexity: time O(n^2), space O(n^2)
def surrounded_region(board):
    if len(board) <= 2:
        return
    row_top = board[0]
    row_bottom = board[len(board)-1]
    column_left = [row[0] for row in board]
    column_right = [row[len(row)-1] for row in board]

    queue = []
    for i in xrange(len(row_top)):
        if row_top[i] == 'O':
            board[0][i] = 'N'
            queue.append((0, i))
        if row_bottom[i] == 'O':
            board[-1][i] = 'N'
            queue.append((len(board)-1, i))

    for j in xrange(len(column_left)):
        if column_left[j] == 'O':
            board[j][0] = 'N'
            queue.append((j, 0))
        if column_right[j] == 'O':
            board[j][-1] = 'N'
            queue.append((j, len(board[0])-1))

    while queue:
        x_curr, y_curr = queue.pop(0)
        if x_curr - 1 > 0 and board[x_curr-1][y_curr] == 'O':
            board[x_curr-1][y_curr] = 'N'
            queue.append((x_curr-1, y_curr))
        if x_curr + 1 < len(board) and board[x_curr+1][y_curr] == 'O':
            board[x_curr+1][y_curr] = 'N'
            queue.append((x_curr+1, y_curr))
        if y_curr - 1 > 0 and board[x_curr][y_curr-1] == 'O':
            board[x_curr][y_curr-1] = 'N'
            queue.append((x_curr, y_curr-1))
        if y_curr + 1 < len(board[0]) and board[x_curr][y_curr+1] == 'O':
            board[x_curr][y_curr+1] = 'N'
            queue.append((x_curr, y_curr+1))

    for i in xrange(len(board)):
        for j in xrange(len(board[0])):
            if board[i][j] == 'O':
                board[i][j] = 'X'
            if board[i][j] == 'N':
                board[i][j] = 'O'

LeetCode: Sum Root to Leaf Numbers

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.


We can start from the root node and perform a breadth first search. If one path reaches to the end, push the current num into a list and finally add them together.

C++ Code:

/*
 * func: root_leaf_sum_helper
 * goal: helper function for root_leaf_sum to perform BFS
 * @param root: root node of the tree
 * @param vec: vector to store each value
 * @param num: current num in string format
 * return:
 */
void root_leaf_sum_helper(TreeNode *root, vector<string> &vec, string num){
    if(root == nullptr){
        return;
    }else if(root->left == nullptr && root->right == nullptr){
        num += char(root->val + '0');
        vec.emplace_back(num);
        return;
    }else{
        num += char(root->val + '0');
        root_leaf_sum_helper(root->right, vec, num);
        root_leaf_sum_helper(root->left, vec, num);
    }
}

/*
 * func: root_leaf_sum
 * goal: find the total sum of all root-to-leaf numbers
 * @param root: root node of the tree
 * return: total sum
 */
int root_leaf_sum(TreeNode *root){
    vector<string> vec;
    string num = "";
    root_leaf_sum_helper(root, vec, num);
    int result = 0;
    for(const string &str : vec){
        result += atoi(str.c_str());
    }
    return result;
}

Python Code:

# func: find the sum of all numbers constructed from root to leaf
# @param root: root node of the tree
# @return: sum
def sum_root_leaf(root):
    if not root:
        return 0
    else:
        def sum_root_leaf_helper(val, node):
            if not node.left and not node.right:
                return val
            elif not node.left:
                return sum_root_leaf_helper(val * 10 + node.right.val, node.right)
            elif not node.right:
                return sum_root_leaf_helper(val * 10 + node.left.val, node.left)
            else:
                return sum_root_leaf_helper(val * 10 + node.left.val, node.left) + \
                sum_root_leaf_helper(val * 10 + node.right.val, node.right)
        return sum_root_leaf_helper(root.val, root)

Thursday, May 29, 2014

LeetCode: 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.


Since the problem asked us to solve it in O(n), we cannot use any sort-based approach. Hence, we need to find a way to record the current longest sequence. A hashmap can be used here. Each time a element is inserted to the map, we check to see if element-1 is in the map. If it exists, we set the value of element to map[element-1]+1. Then we check to see if element+1 is in the map. It it exists, we update the value of element and the end of sequence starting from element+1. At the end, we can reset the value of the starting element in the sequence. Until now, the starting element and ending element of the sequence have the latest length info.

C++ Code:

/*
 * func: longest_consecutive
 * goal: find the longest consecutive sequence
 * @param num: input number array
 * return: the length of longest consecutive sequence
 */
int longest_consecutive(vector<int> &num){
    int max_length = 0;
    unordered_map<int, int> count_helper;
    for(const int &number : num){
        if(count_helper.find(number) != count_helper.end()){
            continue;
        }
        count_helper[number] = 1;
        
        //If the previous value is in the map, connection them together
        if(count_helper.find(number-1) != count_helper.end()){
            count_helper[number] = count_helper[number-1] + 1;
        }
        //If the next value is in the map, update the biggest number's value
        if(count_helper.find(number+1) != count_helper.end()){
            int last = number+1+count_helper[number+1]-1;
            count_helper[number] = count_helper[last] = count_helper[number] + count_helper[last];
        }
        //Update the count of the smallest value in the chain
        if(count_helper.find(number-1) != count_helper.end()){
            int first = number-1-count_helper[number-1]+1;
            count_helper[first] = count_helper[number];
        }
        
        max_length = max(max_length, count_helper[number]);
    }
    return max_length;
}

Python Code:

# func: find the longest consecutive sequence
# @param num: input number list
# @return: the length of the sequence
def longest_consecutive(num):
    count_helper = {}
    max_length = 0
    for number in num:
        if number not in count_helper:
            count_helper[number] = 1

            #Find if number-1 is in the map
            if number-1 in count_helper:
                count_helper[number] = count_helper[number-1] + 1

            #Find if number+1 in the map
            if number+1 in count_helper:
                #Find the last element starting from number+1
                last = count_helper[number+1] + number
                #Update the value in last and number
                count_helper[last] = count_helper[number] = count_helper[number] + count_helper[last]
            #Find the start position of the sequence
            if number-1 in count_helper:
                first = number - count_helper[number-1]
                count_helper[first] = count_helper[number]

            max_length = max(max_length, count_helper[number])

    return max_length

LeetCode: Word Ladder II

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.


We can still use BFS to find the shortest path for this problem. What we need to do additionally is record the path when we do BFS. Here we can use a map to record the list of words that can transform to one word in the dict. Then we can use backtracking to generate the path.

C++ Code:

/*
 * func: generate_path
 * goal: generate shortest parth from the the map
 * @param prev_map: a word map to show the words connected to
 * @param path: a path vector
 * @param word: current word
 * @param result: final result set
 * return:
 */
void generate_path(unordered_map<string, vector<string> > &prev_map, vector<string> &path,
                   string word, vector<vector<string> > &result){
    if(prev_map[word].size() == 0){
        path.emplace_back(word);
        vector<string> curr_path = path;
        reverse(curr_path.begin(), curr_path.end());
        result.emplace_back(curr_path);
        path.pop_back();
        return;
    }
    
    path.push_back(word);
    for(auto iter = prev_map[word].begin(); iter != prev_map[word].end(); ++iter){
        generate_path(prev_map, path, *iter);
    }
    path.pop_back();
}

/*
 * func: find_ladders
 * goal: find all shortest transformation sequences
 * @param start: start string
 * @param end: end string
 * @param dict: words dict
 * return: all possible sequences
 */
vector<vector<string> > find_ladders(string start, string end, unordered_set<string> &dict){
    vector<vector<string> > result;
    
    unordered_map<string, vector<string> > prev_map;
    for(auto it = dict.begin(); it != dict.end(); ++it){
        prev_map[*it] = vector<string>();
    }
    
    vector<unordered_set<string> > candidates(2);
    int current = 0;
    int previous = 1;
    candidates[current].insert(start);
    
    while(true){
        current = !current;
        previous = !previous;
        
        for(auto it = candidates[previous].begin(); it != candidates[previous].end(); ++it){
            dict.erase(*it);
        }
        
        candidates[current].clear();
        for(auto it = candidates[previous].begin(); it != candidates[previous].end(); ++it){
            for(size_t pos = 0; pos < it->size(); ++pos){
                string word = *it;
                for(char c = 'a'; c <= 'z'; ++c){
                    word[pos] = c;
                    if(dict.count(word) > 0){
                        prev_map[word].push_back(*it);
                        candidates[current].insert(word);
                    }
                }
            }
        }
        
        if(candidates[current].size() == 0){
            return result;
        }
        if(candidates[current].count(end)){
            break;
        }
    }
    
    vector<string> path;
    generate_path(prev_map, path, end, result);
    
    return result;
}

Python Code:

# func: find all shortest transformation sequences
# @param start: start string
# @param end: end string
# @param dict: words dict
# @return: all sequences
def find_ladders(start, end, dict):
    dict.add(end)
    dict.add(start)
    result = []
    path = []
    #a map store current word as key and words can connected to it as value
    prev_map = {word:[] for word in dict}
    #two sets help BFS
    current = set()
    previous = set()
    current.add(start)
    while end not in current:
        current, previous = previous, current
        for word in previous:
            dict.remove(word)

        current.clear()
        for word in previous:
            for i in xrange(len(word)):
                for ch in 'abcdefghijklmnopqrstuvwxyz':
                    transformed = word[:i] + ch + word[i+1:]
                    if transformed in dict:
                        prev_map[transformed].append(word)
                        current.add(transformed)

        if not current:
            return []
    #Generate path based on the prev_map
    #It is a backtracking
    def generate_path(word):
        if len(prev_map[word]) == 0:
            path.append(word)
            result.append(path[::-1])
            path.pop(-1)
            return

        path.append(word)
        for prev_word in prev_map[word]:
            generate_path(prev_word)

        path.pop(-1)

    generate_path(end)
    return result

LeetCode: 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.


We can treat the dictionary as a graph, and those pairs of words that can transform to each other are connected in the graph. The this problem is to find the shortest path from start word to the end word. Since the edge is bidirectional. We can use BFS to find the shortest path. In my solution, a queue is used to help BFS.

C++ Code:

/*
 * func: ladder_length
 * goal: find the shortest length of transformation
 * @param start: start word
 * @param end: end word
 * @param dict: word dictionary
 * return: shortest length
 */
/*
 * Use a queue to do BFS
 * complexity: time O(n), space O(n)
 */
int ladder_length(string start, string end, unordered_set<string> &dict){
    if(dict.size() == 0){
        return 0;
    }
    
    queue<string> word_queue;
    queue<int> distance_queue;
    
    word_queue.emplace(start);
    distance_queue.emplace(1);
    
    while(!word_queue.empty()){
        string curr_word = word_queue.front();
        int curr_dis = distance_queue.front();
        
        word_queue.pop();
        distance_queue.pop();
        
        for(int i=0; i<curr_word.length(); ++i){
            char tmp_c = curr_word[i];
            for(char c = 'a'; c <= 'z'; ++c){
                curr_word[i] = c;
                if(dict.find(curr_word) != dict.end()){
                    word_queue.emplace(curr_word);
                    distance_queue.emplace(curr_dis+1);
                    dict.erase(curr_word);
                }
                if(curr_word == end){
                    return curr_dis + 1;
                }
            }
            curr_word[i] = tmp_c;
        }
    }
    
    return 0;
}

Python Code:

# func: find the shortest length of transformation
# @param start: start word
# @param end: end word
# @param dict: words dict
# @return: shortest length
def ladder_length(start, end, dict):
    word_queue = [start]
    distance_queue = [1]

    while word_queue:
        curr_word = word_queue[0]
        curr_dis = distance_queue[0]

        word_queue.pop(0)
        distance_queue.pop(0)

        for i in xrange(len(curr_word)):
            for c in 'abcdefghijklmnopqrstuvwxyz':
                transformed_word = curr_word[:i] + c + curr_word[i+1:]
                if transformed_word in dict:
                    word_queue.append(transformed_word)
                    distance_queue.append(curr_dis+1)
                    dict.remove(transformed_word)
                if transformed_word == end:
                    return curr_dis + 1
    return 0

LeetCode: Valid Palindrome

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.

For example,
"A man, a plan, a canal: Panama" is a palindrome.
"race a car" is not a palindrome.

Note:
Have you consider that the string might be empty? This is a good question to ask during an interview.

For the purpose of this problem, we define empty string as valid palindrome.


If the size of the string is even, the start checking position will be the middle two chars. Else if it is odd, the start checking position is the middle char.

C++ Code:

/*
 * func: is_palindrome
 * goal: to test if the input string is a palindrome
 * @param s: input string
 * return: true or false
 */
/*
 * find the symmetry axis and then validate
 * complexity: time O(n), space O(n)
 */
bool is_palindrome(string s){
    string convert = "";
    //remove non-alphanumeric chars
    for(const char &ch : s){
        if(isalnum(ch)){
            convert += isupper(ch) ? (ch + 32) : ch;
        }
    }
    int s_length = convert.length();
    if(s_length <= 1){
        return true;
    }
    //Find symmetry axis
    int mid_left = 0;
    int mid_right = 0;
    if(s_length & 1){
        mid_left = s_length/2;
        mid_right = s_length/2;
    }else{
        mid_left = s_length/2 - 1;
        mid_right = s_length/2;
    }
    while(mid_left >= 0 && mid_right <s_length){
        if(convert[mid_left] == convert[mid_right]){
            --mid_left;
            ++mid_right;
        }else{
            return false;
        }
    }
    return true;
}

Python Code:

# func: to determine if the input string is a palindrome
# @param s: input string
# @return: True or False
def is_palindrome(s):
    str = ''.join(x.lower() for x in s if x.isalnum())
    if len(str) <= 1:
        return True
    if len(str) & 1:
        mid_left = len(str)/2
        mid_right = len(str)/2
    else:
        mid_left = len(str)/2 - 1
        mid_right = mid_left + 1

    while mid_left >= 0 and mid_right < len(str):
        if str[mid_left] == str[mid_right]:
            mid_left -= 1
            mid_right += 1
        else:
            return False
    return True

LeetCode: 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.


For a binary tree, the max sum path may be one of the following situations:

1. The path only contains the root node.

2. The path contains the root node and its left subtree path.

3. The path contains the root node and its right subtree path.

4. The path contains the root node, its left subtree path and right subtree path.

5. The path is from its left subtree path, and doesn't include root node.

6. The path is from its right subtree path, and doesn't include root node.

C++ Code:

/*
 * func: binary_tree_max_path_sum_helper
 * goal: helper function to find the maximum value
 * @param root: root node of the tree
 * @param max_sum: current max sum
 * return: max sum passing current node
 */
int binary_tree_max_path_sum_helper(TreeNode *root, int &max_sum){
    if(root == nullptr){
        return 0;
    }
    
    //Get the maximum value the path of which includes root.left
    int left_max = binary_tree_max_path_sum_helper(root->left, max_sum);
    //Get the maximum value the path of which includes root.left
    int right_max = binary_tree_max_path_sum_helper(root->right, max_sum);
    //Get the maximum value the path of which includes root node
    int current_max = max(root->val, max(root->val + left_max, root->val + right_max));
    //Update global maximum value
    max_sum = max(max(current_max, root->val + left_max + right_max), max_sum);
    
    return current_max;
}
 
/*
 * func: binary_tree_max_path_sum
 * goal: find the maximum path sum, the path may start and end at any node
 * @param root: root node of the tree
 * return: maximum path sum
 */
int binary_tree_max_path_sum(TreeNode *root){
    if(root == nullptr){
        return 0;
    }
    int max_sum = root->val;
    binary_tree_max_path_sum_helper(root, max_sum);
    return max_sum;
}

Python Code:

# func: find the maximum path sum
# @param root: root node of the tree
# @return: maximum value
def max_path_sum(self, root):
    if not root:
        return 0
    self.max_value = root.val
    def max_path_sum_helper(node):
        if not node:
            return 0
        left_value = max_path_sum_helper(node.left)
        right_value = max_path_sum_helper(node.right)

        current_value = max(node.val, node.val+left_value, node.val+right_value)
        self.max_value = max(self.max_value, current_value, node.val + left_value + right_value)

        return current_value
    max_path_sum_helper(root)
    return self.max_value

Wednesday, May 28, 2014

LeetCode: 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).


We can divide the array into two parts. We can find the maximum profit in prices[0:i] with one transaction and then find the maximum profit in prices[i+1:end] with one transaction. Then we can find the maximum sum of profit in prices[0:i] and profit in prices[i+1:end].

C++ Code:

/*
 * func: maximum_profit
 * goal: find the maximum profits if at most two transactions are permitted
 * @param prices: daily price of the stock
 * return: maximum profit
 */
/*
 * find the maximum profit in [0:i] + [i+1:end]
 * complexity: time O(n), space O(n)
 */
int maximum_profit(vector<int> &prices){
    if(prices.size() == 0){
        return 0;
    }
    vector<int> max_profit_array;
    int hold_price = prices[0];
    int max_profit = 0;
    for(const int &price : prices){
        int curr_profit = price - hold_price;
        max_profit = max(max_profit, curr_profit);
        max_profit_array.emplace_back(max_profit);
        if(price < hold_price){
            hold_price = price;
        }
    }
    
    int final_profit = max_profit_array.back();
    hold_price = prices[prices.size()-1];
    max_profit = 0;
    for(int i=prices.size()-2; i >= 0; --i){
        int curr_profit = hold_price - prices[i];
        max_profit = max(max_profit, curr_profit);
        final_profit = max(final_profit, max_profit + max_profit_array[i]);
        hold_price = max(hold_price, prices[i]);
    }
    
    return final_profit;
}

Python Code:

# func: find the maximum profit if at most two transactions are permitted
# @param prices: daily price of the stock
# @return: the max profit
# complexity: time O(n), space O(n)
def maximum_profit(prices):
    if not prices:
        return 0
    hold_price = prices[0]
    max_profit = 0
    max_profit_until = []
    for price in prices:
        curr_profit = price - hold_price
        #Find the maximum profit until now for one transaction
        max_profit = max(max_profit, curr_profit)
        max_profit_until.append(max_profit)
        hold_price = min(price, hold_price)

    #Find the maximum profit from i to the end
    hold_price = price[-1]
    max_profit = 0
    final_profit = max_profit_until[-1]
    for i in xrange(len(prices)-2, -1, -1):
        curr_profit = hold_price - prices[i]
        max_profit = max(max_profit, curr_profit)
        final_profit = max(final_profit, max_profit + max_profit_until[i])
        hold_price = max(hold_price, prices[i])
    return final_profit

LeetCode: 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).


To make the maximum profit, we can do it greedily. When the price is increasing, we hold. When the price is decreasing, we watch.

C++ Code:

/* 
 * func: maximum_profit
 * goal: find the maximum profit if we can complete as many transaction as possible
 * @param prices: daily price of the stock
 * return: maximum profit
 */
/*
 * Do it greedily.
 * complexity: time O(n), space O(1)
 */
int maximum_profit(vector<int> &prices){
    int max_profit = 0;
    for(int i=1; i<prices.size(); ++i){
        //If price is increasing, we hold
        if(prices[i] >= prices[i-1]){
            max_profit += prices[i] - prices[i-1];
        }
    }
    return max_profit;
}

Python Code:

# func: find the maximum profits if we can complete multiple transactions
# @param prices: daily price of the stock
# @return: maximum price
# complexity: time O(n), space O(1)
def maximum_profit(prices):
    max_profit = 0
    for i in xrange(1, len(prices)):
        if prices[i] >= prices[i-1]:
            max_profit += prices[i] - prices[i-1]
    return max_profit

LeetCode: Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.


We can keep record the maximum profit we can make while reading price data.

C++ Code:

/*
 * func: best_time_buy_sell
 * goal: find the maximum profit if only one trasaction permitted
 * @param prices: the prices of stock
 * return: maximum profit
 */
/*
 * keep recording the profit when reading the price data
 * complexity: time O(n), space O(1)
 */
int best_time_buy_sell(vector<int> &prices){
    int max_profit = 0;
    if(prices.size() <= 1){
        return 0;
    }
    int curr_min = prices[0];
    int curr_max = prices[0];
    for(const int &price : prices){
        //If current price is lower than the minimum
        //Reset the minimum and maximum
        //The reason for resetting the curr_max is that we
        //Can only find a higher price occuring later than
        //Current price.
        if(price < curr_min){
            curr_min = price;
            curr_max = price;
        }
        //If current price is higher than the maximum
        //Then a potential higher profit may be found
        if(price > curr_max){
            curr_max = price;
        }
        max_profit = max(max_profit, curr_max-curr_min);
    }
    
    return max_profit;
}

Python Code:

# func: find the maximum profit if only one transaction is permitted
# @param prices: daily price of the stock
# @return: maximum price
# complexity: time O(n), space O(1)
def maximum_profit(prices):
    if not prices:
        return 0
    max_profit = 0
    curr_min = prices[0]
    curr_max = prices[0]
    for price in prices:
        if price < curr_min:
            curr_min = price
            curr_max = price

        if price > curr_max:
            curr_max = price

        max_profit = max(max_profit, curr_max - curr_min)

    return max_profit

Tuesday, May 27, 2014

LeetCode: 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.


We can create an array of the same size as the last row of the triangle, so the minimum sum to each element in the row is the minimum sum from its above left and above right.

C++ Code:

/*
 * func: minimum_path_sum
 * goal: find the minimum path sum from top to bottom.
 * @param triangle: input number triangle
 * return: minimum sum
 */
int minimum_path_sum(vector<vector<int> > &triangle){
    if(triangle.size() == 0){
        return 0;
    }
    vector<int> sum(triangle.size(), 0);
    sum[0] = triangle[0][0];
    for(int i=1; i<triangle.size(); ++i){
        vector<int> prev_sum = sum;
        for(int j = 0; j < triangle[i].size(); ++j){
            if(j == 0){
                sum[j] = prev_sum[j] + triangle[i][j];
            }else if(j == triangle[i].size()-1){
                sum[j] = prev_sum[j-1] + triangle[i][j];
            }else{
                sum[j] = min(prev_sum[j-1], prev_sum[j]) + triangle[i][j];
            }
        }
    }
    
    int min_sum = sum[0];
    for(const int &it : sum){
        min_sum = std::min(it, min_sum);
    }
    
    return min_sum;
}

Python Code:

# func: find the minimum path sum from top to bottom
# @param triangle: input triangle
# @return: minimum sum
def minimum_path_sum(triangle):
    if not triangle:
        return 0
    
    #Compute the sum bottom up
    prev_sum_list = triangle[-1]
    for i in xrange(2, len(triangle)+1):
        curr_sum_list = []
        for j in xrange(len(triangle[-i])):
            curr_sum_list += [triangle[-i][j] + min(prev_sum_list[j], prev_sum_list[j+1])]

        prev_sum_list = curr_sum_list

    return prev_sum_list[0]

LeetCode: Pascal's Triangle II

Given an index k, return the kth row of the Pascal's triangle.

For example, given k = 3,
Return [1,3,3,1].

Note:
Could you optimize your algorithm to use only O(k) extra space?


Just follow the definition and generate row by row.

C++ Code:

/*
 * func: generate_pascal_row
 * goal: generate the specific row of pascal triangle
 * @param rowIndex: input row number
 * return: that row
 */
vector<int> generate_pascal_row(int rowIndex){
    vector<int> row;
    if(rowIndex < 0){
        return row;
    }
    row.resize(rowIndex+2);
    for(int i=0; i<rowIndex + 2; ++i){
        row[i] = 0;
    }
    row[1] = 1;
    for(int i=0; i<rowIndex; ++i){
        for(int j = rowIndex+1; j > 0; j--){
            row[j] = row[j-1] + row[j];
        }
    }
    row.erase(row.begin());
    return row;
}

Python Code:

# func: generate specific pascal row
# @param rowIndex: given row index
# @return: specific pascal row
def generate_pascal_row(rowIndex):
    if rowIndex < 0:
        return []
    result = [0,1,0]
    for _ in xrange(0, rowIndex):
        result = [0] + [result[i] + result[i+1] for i in xrange(len(result)-1)] + [0]
        print result

    return result[1:-1]

Reference Link:

1. 水中的鱼: [LeetCode] Pascal's Triangle II 解题报告: http://fisherlei.blogspot.com/2012/12/leetcode-pascals-triangle-ii.html

LeetCode: Pascal's Triangle

Given numRows, generate the first numRows of Pascal's triangle.

For example, given numRows = 5,
Return

[
     [1],
    [1,1],
   [1,2,1],
  [1,3,3,1],
 [1,4,6,4,1]
]


We can generate each row based on the definition, each element is the sum of the number above and to the left with the number above and to the right.

C++ Code:

/*
 * func: generate_pascal_triangle
 * goal: to generate input number of rows of pascal triangle
 * @param numRows: numer of rows
 * return: all rows
 */
vector<vector<int> > generate_pascal_triangle(int numRows){
    vector<vector<int> > result;
    if(numRows < 1){
        return result;
    }
    vector<int> row(1, 1);
    result.emplace_back(row);
    for(int i=0; i<numRows-1; ++i){
        vector<int> prev = result.back();
        vector<int> curr;
        for(int j = 0; j < prev.size()+1; ++j){
            if(j == 0 || j == prev.size()){
                curr.emplace_back(1);
            }else{
                curr.emplace_back(prev[j-1] + prev[j]);
            }
        }
        result.emplace_back(curr);
    }
    return result;
}

Python Code:

# func: generate pascal triangle
# @param numRows: given number of rows
# @return: all rows generated
def generate_pascal_triangle(numRows):
    if numRows < 1:
        return []
    result = [[1]]
    for _ in xrange(1, numRows):
        prev = [0] + result[-1] + [0]
        curr = []
        for i in xrange(len(prev)-1):
            curr.append(prev[i] + prev[i+1])
        result.append(curr)

    return result

LeetCode: 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


We can use a tracker to record the starting node of each level and then linking nodes in each level.

C++ Code:

/*
 * func: populate_right
 * goal: populate each next pointer to its next right node
 * @param root: root node of the tree
 * return:
 */
/*
 * Use pointer to record the prev node in the process of linking in current level
 * and a next node to record starting node in the next level
 * complexity: time O(n), space O(1)
 */
void populate_right(TreeLinkNode *root){
    TreeLinkNode *iter = root;
    while(iter){
        TreeLinkNode *prev_node = nullptr;
        TreeLinkNode *next_node = nullptr;
        while(iter){
            if(next_node == nullptr){
                if(iter->left)
                    next_node = iter->left;
                else
                    next_node = iter->right;
            }
            
            if(iter->left){
                if(prev_node)
                    prev_node->next = iter->left;
                prev_node = iter->left;
            }
            
            if(iter->right){
                if(prev_node)
                    prev_node->next = iter->right;
                prev_node = iter->right;
            }
            
            iter = iter->next;
        }
        iter = next_node;
    }
}

Python Code:

# func: populate each next pointer to its next right node
# @param root: root node of the tree
# @return:
def populate_right(root):
    node = root
    while node:
        prev_node = None
        next_node = None
        while node:
            #Setting the starting node for the next level
            if next_node is None:
                if node.left:
                    next_node = node.left
                else:
                    next_node = node.right
            #Link the node in the current level
            if node.left:
                if prev_node:
                    prev_node.next = node.left
                prev_node = node.left

            if node.right:
                if prev_node:
                    prev_node.next = node.right
                prev_node = node.right

            node = node.next
        node = next_node

Reference Link:

1. Connect nodes at same level using constant extra space | GeeksforGeekshttp://www.geeksforgeeks.org/connect-nodes-at-same-level-with-o1-extra-space/

LeetCode: 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 -> NULL


For the root node, its next is NULL, and its left node is linked to its right node. If the node is not a root node, its left node is still linked to its right node and its right node will linked to the node's next node's left node.

C++ Code:

/*
 * func: populate_right_helper
 * goal: recursive helper function for connecting nodes in the same level
 * @param root: root node
 * return:
 */
void populate_right_helper(TreeLinkNode *root){
    if(root == nullptr){
        return;
    }
    
    if(root->left){
        root->left->next = root->right;
    }
    
    if(root->right){
        root->right->next = (root->next) ? root->next->left : nullptr;
    }
    
    populate_right_helper(root->left);
    populate_right_helper(root->right);
}

/*
 * func: populate_right
 * goal: populate each next pointer to its next right node
 * @param root: root node of the tree
 * return:
 */
void populate_right(TreeLinkNode *root){
    if(root == nullptr){
        return;
    }
    root->next = nullptr;
    populate_right_helper(root);
}

Python Code:

# func: populate each next pointer to its next right node
# @param root: root node of the tree
# @return:
def populate_right(root):
    if not root:
        return
    root.next = None
    def populate_right_helper(node):
        if not node:
            return
        if node.left:
            node.left.next = node.right

        if node.right:
            if node.next:
                node.right.next = node.next.left
            else:
                node.right.next = None

        populate_right_helper(node.left)
        populate_right_helper(node.right)

    populate_right_helper(root)

Reference Link:

1. Connect nodes at same level | GeeksforGeeks: http://www.geeksforgeeks.org/connect-nodes-at-same-level/

LeetCode: Distinct Subsequences

Given a string S and a string T, count the number of distinct subsequences of T in S.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).

Here is an example:
S = "rabbbit", T = "rabbit"

Return 3.


We can use dynamic programming to solve this problem. Let dp[i] be the number of ways to match T[i:] in S. Then we start from the end of S string and check backwards, if S[j] == T[i], dp[i] += dp[i+1]. Let's take an example:

S: rabbbitt; T: rabbit ; Si = 7; dp:[0, 0, 0, 0, 0, 1, 1]

S: rabbbitt; T: rabbit ; Si = 6; dp:[0, 0, 0, 0, 0, 2, 1]

S: rabbbitt; T: rabbit ; Si = 5; dp:[0, 0, 0, 0, 2, 2, 1]

S: rabbbitt; T: rabbit ; Si = 4; dp:[0, 0, 0, 2, 2, 2, 1]

S: rabbbitt; T: rabbit ; Si = 3; dp:[0, 0, 2, 4, 2, 2, 1]

S: rabbbitt; T: rabbit ; Si = 2; dp:[0, 0, 6, 6, 2, 2, 1]

S: rabbbitt; T: rabbit ; Si = 1; dp:[0, 6, 6, 6, 2, 2, 1]

S: rabbbitt; T: rabbit ; Si = 0; dp:[6, 6, 6, 6, 2, 2, 1]

C++ Code:

/*
 * func: distinct_sequence
 * goal: count the number of distinct subsequences of T in S
 * @param S: source string
 * @param T: target string
 * return: total number
 */
/*
 * using DP: dp_helper[i] means the number of ways to match until the ith char in T
 * complexity: time O(ST), space O(T)
 */
int distinct_sequence(string S, string T){
    vector<int> dp_helper(T.size() + 1);
    dp_helper[T.size()] = 1;
    for(int i = S.size()-1; i >= 0; --i){
        for(int j = 0; j < T.size(); ++j){
            if(S[i] == T[j])
                dp_helper[j] += dp_helper[j+1];
        }
    }
    return dp_helper[0];
}

Python Code:

# func: count the number of distinct subsequences of T in S
# @param S: source string
# @param T: target string
# @return: total count
def distinct_subsequence(S, T):
    dp_helper = [0] * (len(T)+1)
    dp_helper[-1] = 1
    for i in xrange(len(S)-1, -1, -1):
        for j in xrange(len(T)):
            if S[i] == T[j]:
                dp_helper[j] += dp_helper[j+1]
    return dp_helper[0]

LeetCode: 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

click to show hints.

If you notice carefully in the flattened tree, each node's right child points to the next node of a pre-order traversal.


Since the next node is the next node of a pre-order traversal, we can solve this recursively. We can convert its right subtree first, and then convert its left subtree. Finally concatenate them all to the right side.

C++ Code:

/*
 * func: flatten_binary_tree_helper
 * goal: recursive helper function to flatten the tree
 * @param root: current root node of the tree
 * return: root node after flatten
 */
TreeNode *flatten_binary_tree_helper(TreeNode *root){
    if(root == nullptr){
        return root;
    }
    
    //Convert right subtree to list
    TreeNode *right_subtree = flatten_binary_tree_helper(root->right);
    
    //Convert left tree to list and concatenate it to the right of the tree
    root->right = flatten_binary_tree_helper(root->left);
    
    root->left = nullptr;
    
    TreeNode *tmp_root = root;
    //Concatenate right subtree
    while(tmp_root->right){
        tmp_root = tmp_root->right;
    }
    
    tmp_root->right = right_subtree;
    
    return root;
}

/*
 * func: flatten_binary_tree
 * goal: flatten a binary tree to a linked list in place
 * @param root: root node of the tree
 * return:
 */
void flatten_binary_tree(TreeNode *root){
    flatten_binary_tree_helper(root);
}

Python Code:

# func: flatten binary tree to a list
# @param root: root node of the tree
# @return:
def flatten_binary_tree(root):
    def flatten_binary_tree_helper(node):
        if not node:
            return node
        #Faltten right subtree first
        right_subtree = flatten_binary_tree_helper(node.right)
        #Faltten left subtree and concatenate it to the right side of the tree
        node.right = flatten_binary_tree_helper(node.left)
        node.left = None
        #Find the spot to concatenate remaining right subtree
        iter = node
        while iter.right:
            iter = iter.right
        iter.right = right_subtree
        return node
    flatten_binary_tree_helper(root)

Reference Link:

1. My Leetcode: Flatten Binary Tree to Linked List (Java): http://rleetcode.blogspot.com/2014/02/flatten-binary-tree-to-linked-list-java.html

LeetCode: Path Sum II

Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.

For example:
Given the below binary tree and sum = 22,
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1

return

[
   [5,4,11,2],
   [5,8,4,5]
]


Also the same idea as the Path Sum, additionally, we can use a vector to record the search path. If we find one path, push the path to the final result.

C++ Code:

/*
 * func: find_all_path_helper
 * goal: helper function to traverse the tree recursively
 * @param root: root node of the tree
 * @param sum: current sum needed
 * @param result: final result set
 * @param candidate: current candidate path
 * return:
 */
void find_all_path_helper(TreeNode *root, int sum, vector<vector<int> > &result, vector<int> candidate){
    if(root == nullptr){
        return;
    }
    if(root->left == nullptr && root->right == nullptr){
        if(root->val == sum){
            candidate.emplace_back(root->val);
            result.emplace_back(candidate);
            return;
        }else{
            return;
        }
    }else{
        candidate.emplace_back(root->val);
        find_all_path_helper(root->left, sum-root->val, result, candidate);
        find_all_path_helper(root->right, sum-root->val, result, candidate);
    }
}

/*
 * func: find_all_path
 * goal: find all paths that sum up to the given
 * @param root: root node of the tree
 * @param sum: given sum
 */
vector<vector<int> > find_all_path(TreeNode *root, int sum){
    vector<vector<int> > result;
    vector<int> candidate;
    find_all_path_helper(root, sum, result, candidate);
    return result;
}

Python Code:

# func: find all paths from root to leaf that sum up to the given
# @param root: root node of the tree
# @param sum: given sum
# @return: all paths
def find_all_path(root, sum):
    result = []
    def find_all_path_helper(node, sum, candidate):
        if not node:
            return
        elif not node.left and not node.right:
            if node.val == sum:
                candidate.append(node.val)
                result.append(candidate)
            return
        else:
            find_all_path_helper(node.left, sum-node.val, candidate[:]+[node.val])
            find_all_path_helper(node.right, sum-node.val, candidate[:]+[node.val])

    find_all_path_helper(root, sum, [])
    return result

LeetCode: Path Sum

Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.

For example:
Given the below binary tree and sum = 22,
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1

return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.


We can use recursive call to solve this problem. If current node is a leaf node, check its value is equal to the sum. If it not a leaf node, check if its left subtree or right subtree can form sum - node.val

C++ Code:

/*
 * func: has_path_sum
 * goal: to determine if there exists such a path from root to leaf which sum up to the given
 * @param root: root node of the tree
 * @param sum: given sum
 * return: true or false
 */
bool has_path_sum(TreeNode *root, int sum){
    if(root ==  nullptr){
        return false;
    }if(root->left == nullptr && root->right == nullptr){
        return sum == root->val;
    }else{
        return has_path_sum(root->left, sum-root->val) ||
        has_path_sum(root->right, sum-root->val);
    }
}

Python Code:

# func: to determine if there exists such a path from root to leaf which sum up to the given
# @param root: root node of the tree
# @param sum: given sum
# @return True or False
def has_path_sum(root, sum):
    if not root:
        return False
    elif not root.left and not root.right:
        return sum == root.val
    else:
        return has_path_sum(root.left, sum-root.val) or has_path_sum(root.right, sum-root.val)

LeetCode: Minimum Depth of Binary Tree

Given a binary tree, find its minimum depth.

The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.


According to the definition, the minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. The problem can be split into several cases: if it is a empty tree, depth is 0; if its left subtree is empty, its depth is its right subtree's depth plus 1; if its right left subtree is empty, its depth is its left subtree's depth plus 1; otherwise, its depth is the minimum of its left subtree's depth and its right subtree's depth plus 1.

C++ Code:

/*
 * func: min_depth
 * goal: find the minimum depth of the tree
 * @param root: root node of the tree
 * return: minimum depth
 */
int min_depth(TreeNode *root){
    if(root ==  nullptr){
        return 0;
    }else if(root->left == nullptr && root->right==nullptr){
        return 1;
    }else if(root->left == nullptr){
        return min_depth(root->right) + 1;
    }else if(root->right == nullptr){
        return min_depth(root->left) + 1;
    }else{
        return std::min(min_depth(root->left), min_depth(root->right)) + 1;
    }
}

Python Code:

# func: find the minimum depth from root node down to the nearest leaf node
# @param root: root node of the tree
# @return: minimum depth
def min_depth(root):
    if not root:
        return 0
    elif not root.left and not root.right:
        return 1
    elif not root.left:
        return min_depth(root.right)+1
    elif not root.right:
        return min_depth(root.left)+1
    else:
        return min(min_depth(root.left), min_depth(root.right)) + 1

Monday, May 26, 2014

LeetCode: Balanced Binary Tree

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 every node never differ by more than 1.


We can check by the definition: left subtree is balanced, right subtree is balanced and the depth of two subtrees never defer by more than 1.

C++ Code:

/*
 * func: get_height
 * goal: get the height of the binary tree
 * @param root: root node of the tree
 * return: the height of the tree
 */
int get_height(TreeNode *root){
    if(root == nullptr){
        return 0;
    }else{
        int left_height = get_height(root->left);
        int right_height = get_height(root->right);
        
        return left_height > right_height ? left_height + 1 : right_height + 1;
    }
}

/*
 * func: is_balanced
 * goal: to check if the tree is height balanced
 * @param root: root node of the tree
 * return: true or false
 */
bool is_balanced(TreeNode *root){
    if(root == nullptr){
        return true;
    }else{
        int left_height = get_height(root->left);
        int right_height = get_height(root->right);
        
        return is_balanced(root->left) && is_balanced(root->right) && (abs(left_height-right_height) <= 1);
    }
}

Python Code:

# func: to get the height of the current node
#       if tree start from current node is not balanced, return -2
#       height starts from -1
# @param: root node of the tree
# @return: height
def get_height(node):
    if not node:
        return -1
    left_height = get_height(node.left)
    if left_height == -2:
        return -2

    right_height = get_height(node.right)
    if right_height == -2:
        return -2

    if abs(left_height-right_height) > 1:
        return -2

    return max(left_height, right_height) + 1

# func: to check if the tree is height balanced
# @param root: root node of the tree
# @return: True or False
def is_balanced(root):
    return get_height(root) != -2

LeetCode: 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.


We can construct the tree recursively. First step is to find the size of the linked list and then left part of the list will be the left subtree and right part of the list will be the right subtree.

C++ Code:

/* 
 * func: sorted_list_to_BST_helper
 * goal: recursive function to construct BST
 * @param head: head node of the linked list
 * @param start: start index
 * @param end: end index
 * return: root node of the tree
 */
TreeNode *sorted_list_to_BST_helper(ListNode *&head, int start, int end){
    if(start > end)
        return nullptr;
    
    int mid = start + (end - start) / 2;
    TreeNode *left = sorted_list_to_BST_helper(head, start, mid-1);
    TreeNode *root = new TreeNode(head->val);
    root->left = left;
    head = head->next;
    root->right = sorted_list_to_BST_helper(head, mid+1, end);
    return root;
}

/*
 * func: sorted_list_to_BST
 * goal: convert a sorted linked list to BST
 * @param head: head node of the linked list
 * return: root node of the tree
 */
TreeNode *sorted_list_to_BST(ListNode *head){
    ListNode *it = head;
    int length = 0;
    while(it){
        ++length;
        it = it->next;
    }
    
    return sorted_list_to_BST_helper(head, 0, length-1);
}

Python Code:

# func: convert sorted list to BST
# @param head: head node of the list
# @return: root node of the tree
def sorted_list_to_BST(head):
    def sorted_list_to_BST_helper(head, start, end):
        if start > end:
            return head, None
        mid = start + (end - start) / 2
        head, left_child = sorted_list_to_BST_helper(head, start, mid-1)
        root = TreeNode(head.val)
        head = head.next
        root.left = left_child
        head, root.right = sorted_list_to_BST_helper(head, mid+1, end)
        return head, root
    #Count the total number
    it = head
    count = 0
    while it:
        count += 1
        it = it.next


    head, root = sorted_list_to_BST_helper(head, 0, count-1)
    return root

LeetCode: Convert Sorted Array to Binary Search Tree

Given an array where elements are sorted in ascending order, convert it to a height balanced BST.


We can choose the mid point as the root node each time and put left part as the left subtree and right part as the right subtree recursively.

C++ Code:

/*
 * func: sorted_array_to_BST_helper
 * goal: recursive helper function 
 * @param num: input sorted array
 * @param start: starting index
 * @param end: ending index
 * return: root node
 */
TreeNode *sorted_array_to_BST_helper(vector<int> &num, int start, int end){
    if(start > end){
        return nullptr;
    }
    int mid = start + (end - start)/2;
    TreeNode *root = new TreeNode(num[mid]);
    root->left = sorted_array_to_BST_helper(num, start, mid-1);
    root->right = sorted_array_to_BST_helper(num, mid+1, end);
    return root;
}

/*
 * func: sorted_array_to_BST
 * goal: convert a sorted array to a height balanced BST
 * @param num: input sorted array
 * return: root node of the tree
 */
TreeNode *sorted_array_to_BST(vector<int> &num){
    return sorted_array_to_BST_helper(num, 0, num.size()-1);
}

Python Code:

# func: convert sorted array to balanced BST
# @param num: input sorted list
# @return: root node
def sorted_array_to_BST(num):
    if not num:
        return None

    mid = len(num)/2
    root = TreeNode(num[mid])
    root.left = sorted_array_to_BST(num[:mid])
    root.right = sorted_array_to_BST(num[mid+1:])

    return root

LeetCode: 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],
]


We can use the same code as Binary Tree Level Order Traversal. Just reverse the result at the end.

C++ Code:

/*
 * func: get_height
 * goal: get the height of the binary tree
 * @param root: root node of the tree
 * return: the height of the tree
 */
int get_height(TreeNode *root){
    if(root == nullptr){
        return 0;
    }else{
        int left_height = get_height(root->left);
        int right_height = get_height(root->right);
        
        return left_height > right_height ? left_height + 1 : right_height + 1;
    }
}

/*
 * func: traverse_given_level
 * goal: traverse the given level
 * @param root: root node of the tree
 * @param level: given level
 * @param routine: traversal list
 * return:
 */
void traverse_given_level(TreeNode *root, int level, vector<int> &routine){
    if(root == nullptr){
        return;
    }
    if(level == 1){
        routine.emplace_back(root->val);
    }else if(level > 1){
        traverse_given_level(root->left, level-1, routine);
        traverse_given_level(root->right, level-1, routine);
    }
}

/*
 * func: level_order_traversal_ii
 * goal: traverse the tree in level order from bottom up
 * @param root: root node of the tree
 * return: a vector of each level
 */
vector<vector<int> > level_order_traversal_ii(TreeNode *root){
    int level = get_height(root);
    vector<int> curr_level;
    vector<vector<int> > result;
    for(int i=level; i >= 1; --i){
        traverse_given_level(root, i, curr_level);
        result.emplace_back(curr_level);
        curr_level.clear();
    }
    return result;
}

Python Code:

# func: traverse the tree in level order from bottom up
# @param root: root node of the tree
# @return: a list of nodes in each level
def level_order_traversal_ii(root):
    if not root:
        return []
    result = []
    curr_level = [root]
    while curr_level:
        result.append([x.val for x in curr_level])
        next_level = []
        for node in curr_level:
            if node.left:
                next_level.append(node.left)
            if node.right:
                next_level.append(node.right)
        curr_level = next_level[:]

    return result[::-1]

LeetCode: 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.


The same idea as the previous problem. The root node for the tree is the last element of postorder list.

C++ Code:

/*
 * func: build_tree_postorder_inorder_helper
 * goal: helper function to build tree
 * @param postorder: preorder traversal list
 * @param post_start: starting index
 * @param post_end: ending index
 * @param inorder: inorder traversal list
 * @param in_start: starting index for inorder
 * @param in_end: ending index for inorder
 * return: root node
 */
TreeNode *build_tree_postorder_inorder_helper(vector<int> &postorder, int post_start, int post_end,
                                             vector<int> &inorder, int in_start, int in_end){
    if(in_start > in_end){
        return nullptr;
    }
    
    TreeNode *root;
    int i;
    //Find the root node in inorder list
    for(i = in_start; i <= in_end; i++)
        if(inorder[i] == postorder[post_end])
            break;
    
    root = new TreeNode(inorder[i]);
    if(i > in_start)
        root->left = build_tree_postorder_inorder_helper(postorder, post_start, post_end-1-in_end+i, inorder, in_start, i-1);
    if(i < in_end)
        root->right = build_tree_postorder_inorder_helper(postorder, post_end - i, post_end-1, inorder, i+1, in_end);
    
    return root;
}
/*
 * func: build_tree_postorder_inorder
 * goal: build the tree from the postorder and inorder traversal of the tree
 * @param preorder: preorder list of the tree
 * @param inorder: inorder list of the tree
 * return: root node of the tree
 */
TreeNode *build_tree_postorder_inorder(vector<int> &preorder, vector<int> &inorder){
    if(postorder.size() == 0){
        return nullptr;
    }
    
    return build_tree_preorder_inorder_helper(postorder, 0, postorder.size()-1, inorder, 0, inorder.size()-1);
}

Python Code:

# func: construct tree from post order and in order
# @param postorder: postorder traversal list
# @param inorder: inorder traversal list
# @return: root node
def build_tree_postorder_inorder(postorder, inorder):
    if not inorder:
        return None
    root = TreeNode(postorder[-1])
    id = inorder.index(postorder[-1])
    root.left = build_tree_postorder_inorder(postorder[:id], inorder[:id])
    root.right = build_tree_postorder_inorder(postorder[id:-1], inorder[id+1:])

    return root

LeetCode: 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.


We can construct the tree recursively. The first node of preorder list will be the root node of the tree. Then we can find the root node in inorder list. And elements on the left side of the root node will construct the left subtree. Elements on the right side of the root node will construct the right subtree.

C++ Code:

/*
 * func: build_tree_preorder_inorder_helper
 * goal: helper function to build tree
 * @param preorder: preorder traversal list
 * @param pre_start: starting index
 * @param pre_end: ending index
 * @param inorder: inorder traversal list
 * @param in_start: starting index for inorder
 * @param in_end: ending index for inorder
 * return: root node
 */
TreeNode *build_tree_preorder_inorder_helper(vector<int> &preorder, int pre_start, int pre_end,
                                             vector<int> &inorder, int in_start, int in_end){
    if(in_start > in_end){
        return nullptr;
    }
    
    TreeNode *root;
    int i;
    //Find the root node in inorder list
    for(i = in_start; i <= in_end; i++)
        if(inorder[i] == preorder[pre_start])
            break;
    root = new TreeNode(inorder[i]);
    if(i > in_start)
        root->left = build_tree_preorder_inorder_helper(preorder, pre_start+1, pre_start+i-in_start, inorder, in_start, i-1);
    if(i < in_end)
        root->right = build_tree_preorder_inorder_helper(preorder, pre_start + i - in_start + 1, pre_end, inorder, i+1, in_end);
    
    return root;
}
/*
 * func: build_tree_preorder_inorder
 * goal: build the tree from the preorder and inorder traversal of the tree
 * @param preorder: preorder list of the tree
 * @param inorder: inorder list of the tree
 * return: root node of the tree
 */
TreeNode *build_tree_preorder_inorder(vector<int> &preorder, vector<int> &inorder){
    if(preorder.size() == 0){
        return nullptr;
    }
    
    return build_tree_preorder_inorder_helper(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1);
}

Python Code:

# func: construct binary tree from preoder and inorder traversal
# @param preorder: preorder traversal list
# @param inorder: inorder traversal list
def build_tree_from_preorder_inorder(preorder, inorder):
    if not preorder:
        return None
    root = TreeNode(preorder[0])
    id = inorder.index(preorder[0])
    root.left = build_tree_from_preorder_inorder(preorder[1:id+1], inorder[0:id])
    root.right = build_tree_from_preorder_inorder(preorder[id+1:], inorder[id+1:])

    return root

LeetCode: Maximum Depth of Binary Tree

Given a binary tree, find its maximum depth.

The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.


Use a recursive call. The maximum depth is the maximum depth of its left subtree and right subtree plus 1.

C++ Code:

/*
 * func: max_depth
 * goal: find the max depth of the given binary tree
 * @param root: root node of the tree
 * return: maximum depth
 */
int max_depth(TreeNode *root){
    if(root == nullptr){
        return 0;
    }
    else{
        return std::max(max_depth(root->left), max_depth(root->right)) + 1;
    }
}

Python Code:

# func: find the maximum depth of binary tree
# @param root: root node of the tree
# @return: maximum depth
def max_depth(root):
    if not root:
        return 0
    else:
        return max(max_depth(root.left), max_depth(root.right)) + 1

LeetCode: 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]
]


We can use the same idea as level order traversal, just reverse the traversal list when current level is even.

C++ Code:

/*
 * func: get_height
 * goal: get the height of the binary tree
 * @param root: root node of the tree
 * return: the height of the tree
 */
int get_height(TreeNode *root){
    if(root == nullptr){
        return 0;
    }else{
        int left_height = get_height(root->left);
        int right_height = get_height(root->right);
        
        return left_height > right_height ? left_height + 1 : right_height + 1;
    }
}

/*
 * func: traverse_given_level
 * goal: traverse the given level
 * @param root: root node of the tree
 * @param level: given level
 * @param routine: traversal list
 * return:
 */
void traverse_given_level(TreeNode *root, int level, vector<int> &routine){
    if(root == nullptr){
        return;
    }
    if(level == 1){
        routine.emplace_back(root->val);
    }else if(level > 1){
        traverse_given_level(root->left, level-1, routine);
        traverse_given_level(root->right, level-1, routine);
    }
}

/*
 * func: zigzag_level_order
 * goal: traverse the tree in zigzag level order
 * @param root: root node of the tree
 * return: a vector of each level
 */
vector<vector<int> > zigzag_level_order(TreeNode *root){
    int level = get_height(root);
    vector<int> curr_level;
    vector<vector<int> > result;
    for(int i=1; i <= level; ++i){
        traverse_given_level(root, i, curr_level);
        if(i & 1)
            result.emplace_back(curr_level);
        else{
            reverse(curr_level.begin(), curr_level.end());
            result.emplace_back(curr_level);
        }
        curr_level.clear();
    }
    return result;
}

Python Code:

# func: traverse tree in zig zag level order
# @param root: root node of the tree
# @return: a list of nodes in level order
def zigzag_level_order(root):
    if not root:
        return []
    result = []
    curr_level = [root]
    level = 1
    while curr_level:
        if level & 1 == 0:
            result.append([x.val for x in curr_level[::-1]])
        else:
            result.append([x.val for x in curr_level])
        result.append([x.val for x in curr_level])
        next_level = []
        for node in curr_level:
            if node.left:
                next_level.append(node.left)
            if node.right:
                next_level.append(node.right)
        curr_level = next_level[:]
        level += 1

    return result