Woodstock Blog

a tech blog for general algorithmic interview questions

[LeetCode 145] Binary Tree Postorder Traversal

Question

link

Given a binary tree, return the postorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},

   1
    \
     2
    /
   3

return [3,2,1].

Note: Recursive solution is trivial, could you do it iteratively?

Stats

Adjusted Difficulty 4
Time to use --------

Ratings/Color = 1(white) 2(lime) 3(yellow) 4/5(red)

Analysis

Unlike pre-order traversal, this is a very difficult question.

Solution

First, I wrote the solution using a HashSet, and it works. However, this solution is not good because it uses some space. For more generalized way to write DFS code, read another post Implement DFS using a Stack.

The best and most popular solution is proposed by 1337c0d3r. It basically uses 1 more pointer to track the current status (whether I’m traversing down, or up, and in which direction etc.). The extra pointer is called ‘prev’.

We use a prev variable to keep track of the previously-traversed node. Let’s assume curr is the current node that’s on top of the stack. When prev is curr‘s parent, we are traversing down the tree. In this case, we try to traverse to curr‘s left child if available (ie, push left child to the stack). If it is not available, we look at curr‘s right child. If both left and right child do not exist (ie, curr is a leaf node), we print curr‘s value and pop it off the stack.

If prev is curr‘s left child, we are traversing up the tree from the left. We look at curr‘s right child. If it is available, then traverse down the right child (ie, push right child to the stack), otherwise print curr‘s value and pop it off the stack.

If prev is curr‘s right child, we are traversing up the tree from the right. In this case, we print curr‘s value and pop it off the stack.

Referring to his code, I wrote the 2nd piece of code below and it works.

Amazingly, that code can be simplified, which becomes the 3rd code (I thought it won’t pass at first). The way that code got simplified is by keeping current pointer steady, so that the 2 pointers can meet. Altough program logic is exactly same, this interesting code is worth reading.

Code

First, my solution using HashSet

public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> ans = new LinkedList<Integer>();
    Stack<TreeNode> stack = new Stack<TreeNode>();
    if (root != null) stack.push(root);
    HashSet<TreeNode> visited = new HashSet<TreeNode>();
    while (!stack.isEmpty()) {
        TreeNode cur = stack.pop();
        if (visited.contains(cur))
            ans.add(cur.val);
        else {
            stack.push(cur);
            visited.add(cur);
            if (cur.right != null) stack.push(cur.right);
            if (cur.left != null) stack.push(cur.left);
        }
    }
    return ans;
}

Second, using 2 pointers

public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> ans = new LinkedList<Integer>();
    if (root == null) {
        return ans;
    }
    Stack<TreeNode> stack = new Stack<TreeNode>();
    stack.push(root);
    TreeNode pre = null, cur = null;
    while (!stack.isEmpty()) {
        cur = stack.peek();
        if (pre == null || pre.left == cur || pre.right == cur) {
            if (cur.left == null && cur.right == null) {
                ans.add(stack.pop().val);
            }
            else if (cur.left != null) {
                stack.push(cur.left);
            }
            else if (cur.right != null) {
                stack.push(cur.right);
            }
        }
        else if (cur.left == pre) {
            if (cur.right != null) {
                stack.push(cur.right);
            }
            else {
                ans.add(stack.pop().val);
            }
        }
        else if (cur.right == pre) {
            ans.add(stack.pop().val);
        }
        pre = cur;
    }
    return ans;
}

Third, simplified version of 2nd code

Commented on June 10th: Note that ‘pre’ and ‘cur’ are never going to be apart for more then 1 edge (they can overlap)

public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<Integer>();
    Stack<TreeNode> stack = new Stack<TreeNode>();
    TreeNode prev = null; // previously traversed node
    TreeNode curr = root;
    if (root == null) {
        return result;
    }
    stack.push(root);
    while (!stack.empty()) {
        curr = stack.peek();
        if (prev == null || prev.left == curr || prev.right == curr) {
        // traverse down the tree
            if (curr.left != null) {
                stack.push(curr.left);
            } else if (curr.right != null) {
                stack.push(curr.right);
            }
        } else if (curr.left == prev) {
        // traverse up the tree from the left
            if (curr.right != null) {
                stack.push(curr.right);
            }
        } else if (curr.right == prev || curr == prev){
        // traverse up the tree from the right
        // or at a leaf point
            result.add(curr.val);
            stack.pop();
        }
        prev = curr;
    }
    return result;
}

[Design] Big Endian and Little Endian

Difference

Big-endian systems store the most significant byte of a word in the smallest address and the least significant byte is stored in the largest address.

Little-endian systems, in contrast, store the least significant byte in the smallest address.

Both forms of endianness are in widespread use in computing and networking.

Example

The data word “0A 0B 0C 0D” (a set of 4 bytes written out using left-to-right positional, hexadecimal notation) and the four memory locations with addresses a, a+1, a+2 and a+3.

In Big-endian systems, byte 0A is stored in a, 0B in a+1, 0C in a+2 and 0D in a+3. In Little-endian systems, the order is reversed with 0D stored in memory address a, 0C in a+1, 0B in a+2, and 0A in a+3.

Why ?

IBMs and Intel x86 are little endian, while Motorolas and Sun are big endian.

Big-endian is the most common convention in data networking (including IPv6), and little-endian is popular among microprocessors in part due to Intel.

Why is endianness so important? Suppose you are storing int values to a file, then you send the file to a machine which uses the opposite endianness and read in the value. You’ll run into problems because of endianness. You’ll read in reversed values that won’t make sense.

Endianness is also a big issue when sending numbers over the network. Again, if you send a value from a machine of one endianness to a machine of the opposite endianness, you’ll have problems. This is even worse over the network, because you might not be able to determine the endianness of the machine that sent you the data.

The solution is to send 4 byte quantities using network byte order which is arbitrarily picked to be one of the endianness (not sure if it’s big or little, but it’s one of them). If your machine has the same endianness as network byte order, then great, no change is needed. If not, then you must reverse the bytes.

[LeetCode 140] Word Break II

Question

link

Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.

Return all such possible sentences.

For example, given
s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].

A solution is ["cats and dog", "cat sand dog"].

Stats

Adjusted Difficulty 5
Time to use --------

Ratings/Color = 1(white) 2(lime) 3(yellow) 4/5(red)

Analysis

This is a tough question. Standard DFS search would work, but we need to check ‘breakable’ first. Otherwise, I got TLE.

Check breakable is a easy DP, and we do not need to remove any elements from the dictionary. (Word ladder needs remove elements from dictionary, don’t confuse them).

Solution

Updated on July 4th, 2014. The DFS code actually standard, but keep in mind to check breakable first (using DP).

Code

DFS with pruning and DP breakable check, with the again-updated code on Sep 12th, 2014.

public List<String> wordBreak(String s, Set<String> dict) {
    List<String> ans = new ArrayList<String>();
    if (s == null || s.length() == 0 || dict == null) {
        return ans;
    } else if (!canBreak(s, dict)) {
        return ans;
    }
    helper(ans, "", s, 0, dict);
    return ans;
}

private void helper(List<String> ans, String str, String s, int pos, Set<String> dict) {
    int len = s.length();
    if (pos == len) {
        ans.add(str.substring(1));
        return;
    }
    for (int i = pos; i < len; i++) {
        String sub = s.substring(pos, i + 1);
        if (dict.contains(sub)) {
            helper(ans, str + " " + sub, s, i + 1, dict);
        }
    }
}

public boolean canBreak(String s, Set<String> dict) {
    if (s == null || s.length() == 0) {
        return true;
    }
    int len = s.length();
    boolean[] dp = new boolean[len + 1];
    dp[0] = true;
    for (int i = 1; i <= len; i++) {
        for (int j = 0; j < i; j++) {
            if (!dp[j]) {
                continue;
            }
            if (dict.contains(s.substring(j, i))) {
                dp[i] = true;
                break;
            }
        }
    }
    return dp[len];
}

[LeetCode 139] Word Break

Question

link

Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

For example, given
s = "leetcode",
dict = ["leet", "code"].

Return true because "leetcode" can be segmented as "leet code".

Stats

Adjusted Difficulty 4
Time to use --------

Ratings/Color = 1(white) 2(lime) 3(yellow) 4/5(red)

Analysis

This is a standard DP question.

Solution

I see a lot of people solve this DP problem with 2D array. It actually requires only 1D aray.

Declare an boolean array of (input string length) + 1, and dp[i] mean whether or not subtring(0,i) is work-breakable. Then the problem is clear and easy.

Pay attention to index while coding.

Code

my code

public boolean wordBreak(String s, Set<String> dict) {
    int len = s.length();
    if (len == 0 || dict.isEmpty())  {
        return false;
    }
    boolean[] dp = new boolean[len + 1];
    dp[0] = true;
    for (int i = 1; i <= len; i ++)  {
        for (int j = 0; j < i; j ++)  {
            if (dp[j] && dict.contains(s.substring(j, i)))  {
                dp[i] = true;
                break;
            }
        }
    }
    return dp[len];
}

[LeetCode 148] Sort List

Question

link

Sort a linked list in O(n log n) time using constant space complexity.

Stats

Adjusted Difficulty 4
Time to use --------

Ratings/Color = 1(white) 2(lime) 3(yellow) 4/5(red)

Analysis

This is a difficult question.

To sort with O(nlgn) time, we must use either quick sort or merge sort.

Solution

This is a standard merge sort algorithm. The details can be found here.

I am being lazy here, I reused the code from “Merge Two Sorted Lists”. Surprisingly it worked! Just remember, we must set the last node of first half to point to null.

Code

public ListNode sortList(ListNode head) {
    if (head == null || head.next == null) 
        return head;
    int len = 0;
    ListNode temp = head;
    while (temp != null) {
        temp = temp.next;
        len ++;
    }
    temp = head;
    for (int i = 1; i < len / 2; i ++)
        temp = temp.next;
    ListNode firstHalf = head, secondHalf = temp.next;
    temp.next = null;
    return mergeTwoLists(sortList(firstHalf), 
                         sortList(secondHalf));
}

// The following code is copied from
// Question - Merge Two Sorted Lists
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode pre = new ListNode(Integer.MIN_VALUE);
    ListNode cur = pre;
    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            cur.next = l1;
            l1 = l1.next;
        } else {
            cur.next = l2;
            l2 = l2.next;
        }
        cur = cur.next;
    }
    if (l1 == null) cur.next = l2;
    else cur.next = l1;
    return pre.next;
}

[LeetCode 142] Linked List Cycle II

Question

link

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Follow up:
Can you solve it without using extra space?

Stats

Adjusted Difficulty 5
Time to use --------

Ratings/Color = 1(white) 2(lime) 3(yellow) 4/5(red)

Analysis

This is an famous question, historically know as the Tortoise and hare.

Solution

This blog has a great solution.

现在有两个指针,第一个指针,每走一次走一步,第二个指针每走一次走两步,如果他们走了t次之后相遇在K点

那么       指针一  走的路是      t = X + nY + K        ①

             指针二  走的路是     2t = X + mY+ K       ②          m,n为未知数

把等式一代入到等式二中, 有

2X + 2nY + 2K = X + mY + K

=>   X+K  =  (m-2n)Y    ③

这就清晰了,X和K的关系是基于Y互补的。等于说,两个指针相遇以后,再往下走X步就回到Cycle的起点了。这就可以有O(n)的实现了。

Code

public ListNode detectCycle(ListNode head) {
    if (head == null || head.next == null) 
        return null;
    ListNode first = head.next, second = first.next;
    ListNode found = null;
    while (first != null && second != null) {
        if (first == second) {
            found = first;
            break;
        }
        first = first.next;
        second = second.next;
        if (second == null) break;
        second = second.next;
    }
    if (found == null) return null;
    first = head;
    while (first != second) {
        first = first.next;
        second = second.next;
    }
    return first;
}

[LeetCode 141] Linked List Cycle

Question

link

Given a linked list, determine if it has a cycle in it.

Follow up:
Can you solve it without using extra space?

Stats

Adjusted Difficulty 4
Time to use --------

Ratings/Color = 1(white) 2(lime) 3(yellow) 4/5(red)

Analysis

This is an famous question, historically know as the Tortoise and hare.

Solution

This blog has a great solution.

Use fast and low pointer. The advantage about fast/slow pointers is that when a circle is located, the fast one will catch the slow one for sure.

Code

public boolean hasCycle(ListNode head) {
    if (head == null || head.next == null) 
        return false;
    ListNode first = head.next, second = first.next;
    while (first != null && second != null) {
        if (first == second) return true;
        first = first.next;
        second = second.next;
        if (second == null) return false;
        second = second.next;
    }
    return false;
}

[LeetCode 138] Copy List With Random Pointer

Question

link

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.

Stats

Adjusted Difficulty 4
Time to use 20 minutes

Ratings/Color = 1(white) 2(lime) 3(yellow) 4/5(red)

Analysis

This is not a difficult question, however I mark it as difficulty level “4” because there are 2 solution, the second of which is hard to think of.

Solution

Solution 1 which is my initial idea is using HashMap to store mappings from original nodes to copied nodes. This solution become exactly same as another question “Clone Graph”, only easier. It works fine.

However such solution uses O(n) extra space. Can we do it with less space?

Solution 2 is a in-place method which directly creates the copied list. It is well explained in here:

  1. Create a copy of first node and insert it between Node 1 & Node 2 in original list. Then create a copy of second node and insert it between Node 2 & Node 3… Continue in this fashion
  2. Set random link of the copied nodes (by referring to original.random.next)
  3. Restore the original and copied lists (and return answer)

This solution (although uses 3 while-loops) is O(n) and O(1) extra space.

Code

First, my solution using HashMap

public RandomListNode copyRandomList(RandomListNode head) {
    if (head == null) return null;
    RandomListNode newHead = new RandomListNode(head.label);
    HashMap<RandomListNode, RandomListNode> map = 
            new HashMap<RandomListNode, RandomListNode>();
    map.put(head, newHead);
    RandomListNode orin = head, cp = newHead;
    while (orin != null) {
        if (orin.next != null) {
            if (!map.containsKey(orin.next))
                map.put(orin.next, new RandomListNode(orin.next.label));
            cp.next = map.get(orin.next);
        }
        if (orin.random != null) {
            if (!map.containsKey(orin.random))
                map.put(orin.random, new RandomListNode(orin.random.label));
            cp.random = map.get(orin.random);
        }
        orin = orin.next;
        cp = cp.next;
    }
    return newHead;
}

Second, constent space solution

public RandomListNode copyRandomList(RandomListNode head)  {
    if (head == null)  {
        return null;
    }
    // copy each node and append right after original node
    RandomListNode p = head;
    while (p != null)  {
        RandomListNode cp = new RandomListNode(p.label);
        cp.next = p.next;
        p.next = cp;
        p = p.next.next;
    }
    // now set random pointer of all copied nodes
    p = head;
    while (p != null)  {
        if (p.random != null)  {
            p.next.random = p.random.next;
        }
        p = p.next.next;
    }
    // now restore original list, and connected all copied nodes
    RandomListNode ans = head.next;
    RandomListNode m = head, n = head.next;
    while (m != null)  {
        if (n.next == null)  {
            m.next = null;
            m = null;
        }
        else  {
            m.next = n.next;
            n.next = n.next.next;
            m = m.next;
            n = n.next;
        }
    }
    return ans;
}

[LeetCode 144] Binary Tree Preorder Traversal

Question

link

Given a binary tree, return the preorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},

   1
    \
     2
    /
   3

return [1,2,3].

Note: Recursive solution is trivial, could you do it iteratively?

Stats

Adjusted Difficulty 1
Time to use --------

Ratings/Color = 1(white) 2(lime) 3(yellow) 4/5(red)

Analysis

This is the easiest question of this series.

In-order and post-order are not easy at all!

Code

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> ans = new LinkedList<Integer>();
    if (root == null) return ans;
    Stack<TreeNode> stack = new Stack<TreeNode>();
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode cur = stack.pop();
        ans.add(cur.val);
        // should it do reversely, right?
        if (cur.right != null) stack.push(cur.right);
        if (cur.left != null) stack.push(cur.left);
    }
    return ans;
}

[LeetCode 137] Single Number II

Question

link

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?

Stats

$
Adjusted Difficulty 5
Time to use --------

Ratings/Color = 1(white) 2(lime) 3(yellow) 4/5(red)

Analysis

This is an extremely difficult question. There are 2 solutions (both are bit manipulation).

Solution

First solution comes from this forum.

A straightforward implementation is to use an array of size 32 to keep track of the total count of ith bit.

A more detailed explanation:

For eg : A = [ 2, 3, 3, 3]
We count the number of 1s for each bit position. Then find mod 3 of each of them. The bit positions having mod 3  equal to one are the bits that are set due to the number occurring once.
Writing the Binary Representation of the numbers.
                                                                  0 0 1 0
                                                                  0 0 1 1
                                                                  0 0 1 1
                                                                  0 0 1 1
                                                            ----------------
We count the number of 1s for each bit ->  0 0 4 3
Taking modulo 3 we get                             0 0 1 0
and that's our answer. -> 2

Second solution is different, and very hard to read/write. I will not cover this solution. An analysis is found here:

The basic idea is use two integer, ones and twos. Ones is used to record the bits only exist once in current iterated number. Twos is used to record the bits only exist twice in all number. If a bit exists up to three times, we should clear it in both ones and twos.

Code

my code

public int singleNumber(int[] A) {
    int result = 0;
    for (int i = 0; i < 32; i++) {
        int count = 0;
        for (Integer in: A) {
            count += (in & (1 << i)) == 0 ? 0 : 1;
        }
        if (count % 3 != 0) {
            result = result | (1 << i);
        }
    }
    return result;
}

a different solution

public int singleNumber(int[] A) {
    int ones = 0, twos = 0;
    for (int i = 0; i < A.length; i++) {
        twos = twos | (ones & A[i]);
        ones = ones ^ A[i];

        int common_mask = ~(ones & twos);
        ones &= common_mask;
        twos &= common_mask;
    }
    return ones;
}