Leetcode 11: Container With Most Water

11. Container With Most Water 

  • Total Accepted: 99353
  • Total Submissions: 277586
  • Difficulty: Medium
  • Contributors: Admin

Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.

Note: You may not slant the container.

 

Code

class Solution(object):
    def maxArea(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        lp, rp = 0, len(height)-1
        max_area = 0
        while lp < rp:
            max_area = max(max_area, min(height[lp],height[rp]) * (rp-lp))
            if height[lp] < height[rp]:
                lp += 1
            else:
                rp -= 1
        return max_area

 

Idea

The time complexity is O(N). The idea is that if height[lp] < height[rp], then the bottleneck to determine the container volume is height[lp]. That means the container formed by height[lp] and height[rp'] for any rp' < rp must have smaller volume than that formed by height[lp] and height[rp]. In this case, lp should move to right.

You can easily deduct the other case: height[rp] < height[lp].

Reference: https://discuss.leetcode.com/topic/3462/yet-another-way-to-see-what-happens-in-the-o-n-algorithm

 

Leetcode 125: Valid Palindrome

125. Valid Palindrome 

  • Total Accepted: 124387
  • Total Submissions: 499823
  • Difficulty: Easy
  • Contributors: Admin

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.

 

Code

class Solution(object):
    def isPalindrome(self, s):
        """
        :type s: str
        :rtype: bool
        """
        lp, rp = 0, len(s)-1
        while lp < rp:
            while lp < rp and not s[lp].isalnum():
                lp += 1
            while lp < rp and not s[rp].isalnum():
                rp -= 1
            if s[lp].lower() != s[rp].lower():
                return False
            lp += 1
            rp -= 1
        
        return True

 

Idea

Not much to say. First time to use string.isalnum().

Leetcode 131: Palindrome Partitioning

131. Palindrome Partitioning

  • Total Accepted: 77657
  • Total Submissions: 260955
  • Difficulty: Medium
  • Contributors: Admin

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

 

Code

 

class Solution(object):
    def partition(self, s):
        """
        :type s: str
        :rtype: List[List[str]]
        """
        res = []
        self.recur(0, s, [], res)
        return res

    def recur(self, cur_idx, s, splits, res):
        if cur_idx == len(s):
            res.append(list(splits))
            return

        for i in xrange(cur_idx + 1, len(s)+1):
            if self.isPalindrome(s[cur_idx:i]):
                splits.append(s[cur_idx:i])
                self.recur(i, s, splits, res)
                splits.pop()

    def isPalindrome(self, ss):
        return ss == ss[::-1]

 

Idea

You progressively try every split position in the string. Check whether substring between the last split position to current split position is palindrome. If so, recursively try the rest of split positions, with the current substring being added to splits.

Reference: https://discuss.leetcode.com/topic/10955/clean-c-backtracking-solution 

 

Leetcode 118: Pascal’s Triangle

https://leetcode.com/problems/pascals-triangle/

118. Pascal’s Triangle 

  • Total Accepted: 103611
  • Total Submissions: 290013
  • Difficulty: Easy
  • Contributors: Admin

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

 

Code

class Solution(object):
    def generate(self, numRows):
        """
        :type numRows: int
        :rtype: List[List[int]]
        """
        if numRows == 0:
            return []
        
        res = [[1]]
        for i in xrange(2, numRows+1):
            new_row = [0] * i
            for j in xrange(i):
                if j == 0:
                    new_row[j] = 1
                elif j == i-1:
                    new_row[j] = 1
                else: 
                    new_row[j] = res[-1][j-1] + res[-1][j]
            res.append(new_row)
            
        return res   

 

Idea

Each element is the sum of adjacent elements in the above line. That’s how Pascal’s Triangle is defined: https://en.wikipedia.org/wiki/Pascal%27s_triangle

 

 

Leetcode 120: Triangle

120. Triangle 

  • Total Accepted: 84503
  • Total Submissions: 265352
  • Difficulty: Medium
  • Contributors: Admin

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.

 

 

Code 

class Solution(object):
    def minimumTotal(self, triangle):
        """
        :type triangle: List[List[int]]
        :rtype: int
        """
        if len(triangle) == 0:
            return 0
        
        if len(triangle) == 1:
            return triangle[0][0] 
        
        last_level_sum = {0:triangle[0][0]}
        for i in xrange(1, len(triangle)):
            this_level_sum = {}
            for j in xrange(len(triangle[i])):    
                if j == 0:
                     this_level_sum[j] = last_level_sum[0] + triangle[i][j]
                elif j == len(triangle[i])-1:
                     this_level_sum[j] = last_level_sum[j-1] + triangle[i][j]
                else:
                     this_level_sum[j] = min(last_level_sum[j], last_level_sum[j-1]) + triangle[i][j]
        
            last_level_sum = this_level_sum         

        return min(last_level_sum.values())

 

 

Idea

You go from top to bottom. Record the minimum sum until every layer. If you use a bottom-up DP, the solution can be more elegant.

Reference:

https://discuss.leetcode.com/topic/1669/dp-solution-for-triangle/2

Leetcode 116: Populating Next Right Pointers in Each Node

116. Populating Next Right Pointers in Each Node 

  • Total Submissions: 287603
  • Difficulty: Medium
  • Contributors: Admin

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
 

 

Code

# Definition for binary tree with next pointer.
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None

class Solution:
    # @param root, a tree link node
    # @return nothing
    def connect(self, root):
        if root is None: 
            return
        
        pre = root
        while pre.left:
            pre_bakup = pre

            while pre:
                pre.left.next = pre.right
                if pre.next:
                    pre.right.next = pre.next.left
                pre = pre.next

            pre = pre_bakup.left

 

Idea

You traverse nodes in a zigzag-like path. For every node being visited, you set its left child’s next to right child. If the node itself has next node, then its right child should also point to the node’s next node’s left child.

Below is the traversal path of pre:

zigzag

The idea uses O(1) space and O(N) time, where N is the number of nodes in the binary tree.

Reference: https://discuss.leetcode.com/topic/2202/a-simple-accepted-solution

 

Code (Using BFS, space complexity is O(N))

# Definition for binary tree with next pointer.
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None

from collections import *

class Solution:
    # @param root, a tree link node
    # @return nothing
    def connect(self, root):
        if root is None:
            return

        q = deque([(root, 0)])
        while q:
            if len(q) > 1:
                # if two nodes have the same level
                if q[0][1] == q[1][1]:
                    q[0][0].next = q[1][0]
            
            n, lvl = q.popleft()
            
            if n.left and n.right:
                q.append((n.left, lvl+1))
                q.append((n.right, lvl+1))            

 

 

Leetcode 222: Count Complete Tree Nodes

222. Count Complete Tree Nodes 

  • Total Accepted: 45962
  • Total Submissions: 173085
  • Difficulty: Medium
  • Contributors: Admin

Given a complete binary tree, count the number of nodes.

Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.

 

Code

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def countNodes(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root is None:
            return 0        

        height_left, height_right = -1, -1
        
        node = root
        while node:
            height_left += 1 
            node = node.left
       
        node = root
        while node:
            height_right += 1
            node = node.right
       
        if height_left == height_right:
            return 2**(height_left+1) - 1
        else:
            return 1 + self.countNodes(root.left) + self.countNodes(root.right)

 

Idea

height_left is the number of edges between root and its leftmost leaf. height_right is the number of edges between root and its rightmost leaf. If they are the same mean, that means the last level is full. Therefore we can return 2**(height_left+1)-1 by the property of binary tree. If height_left does not equal to height_right, then we have to recursively count the nodes in the left and right subtree.

The time complexity if O((logn)^2). This is because you need O(logn) to calculate height_left/height_right. After that, the worst case is that you need to recursively call self.countNodes(root.left) and self.countNodes(root.right). This happens no more than O(logn) times.

 

Reference:

https://discuss.leetcode.com/topic/15515/easy-short-c-recursive-solution

Leetcode 114: 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

 

Code

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def __init__(self):
        self.prev = None
        
    def flatten(self, root):
        """
        :type root: TreeNode
        :rtype: void Do not return anything, modify root in-place instead.
        """
        if root is None: return
        self.flatten(root.right)
        self.flatten(root.left)
        # self.prev is root's left subtree's root
        root.right = self.prev
        root.left = None
        self.prev = root   

 

Idea

Create a variable self.prev, which records the current node (root)’s left subtree’s root. Overall it utilizes a post-order traversal. The algorithm first traverses right subtree then left subtree and finally adjusts the current root’s left and right subtree.

Reference: https://discuss.leetcode.com/topic/11444/my-short-post-order-traversal-java-solution-for-share/2

 

Code

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def flatten(self, root):
        """
        :type root: TreeNode
        :rtype: void Do not return anything, modify root in-place instead.
        """
        while root:
            ln = root.left
            if ln is not None:
                # find the right-most element of the left subtree 
                while ln.right:
                    ln = ln.right
                ln.right = root.right
                root.right = root.left
                root.left = None
            root = root.right

 

Idea

Iterative way. Time complexity is O(n) since every node can be set as root and ln no more than once.

Reference: https://discuss.leetcode.com/topic/3995/share-my-simple-non-recursive-solution-o-1-space-complexity

 

 

Leetcode 331: Verify Preorder Serialization of a Binary Tree

331. Verify Preorder Serialization of a Binary Tree 

  • Total Accepted: 23475
  • Total Submissions: 68739
  • Difficulty: Medium
  • Contributors: Admin

One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, we record the node’s value. If it is a null node, we record using a sentinel value such as #.

     _9_
    /   \
   3     2
  / \   / \
 4   1  #  6
/ \ / \   / \
# # # #   # #

For example, the above binary tree can be serialized to the string "9,3,4,#,#,1,#,#,2,#,6,#,#", where # represents a null node.

Given a string of comma separated values, verify whether it is a correct preorder traversal serialization of a binary tree. Find an algorithm without reconstructing the tree.

Each comma separated value in the string must be either an integer or a character '#' representing null pointer.

You may assume that the input format is always valid, for example it could never contain two consecutive commas such as "1,,3".

Example 1:
"9,3,4,#,#,1,#,#,2,#,6,#,#"
Return true

Example 2:
"1,#"
Return false

Example 3:
"9,#,#,1"
Return false

 

 

Code

class Solution(object):
    def isValidSerialization(self, preorder):
        """
        :type preorder: str
        :rtype: bool
        """
        if not str: 
            return True

        diff = 1
        for n in preorder.split(','):
            diff -= 1
            if diff < 0:
                return False
            if n != '#':
                diff += 2

        return diff == 0
     

Idea

Calculate the difference between in-degree and out-degree. See https://discuss.leetcode.com/topic/35976/7-lines-easy-java-solution 

 

Code

class Solution(object):
    def isValidSerialization(self, preorder):
        """
        :type preorder: str
        :rtype: bool
        """
        if not preorder: 
            return True
        
        stk = []
        nodes = preorder.split(',')
        for n in nodes:
            while stk and stk[-1] == '#' and n == '#':
                stk.pop()
                if not stk:
                    return False
                stk.pop()
            stk.append(n)
  
        return len(stk) == 1 and stk[0] == '#'

 

Idea

When you see two consecutive “#” characters (one on the top of stack and the other as the current node `n`), that means a subtree with two leaves has been scanned. Pop the subtree’s root as well as the ‘#’ on the stack and replace the topmost element on the stack with “#”.

See https://discuss.leetcode.com/topic/35977/simple-python-solution-using-stack-with-explanation and https://discuss.leetcode.com/topic/35973/java-intuitive-22ms-solution-with-stack

Leetcode 104: Maximum Depth of Binary Tree

104. Maximum Depth of Binary Tree 

  • Total Accepted: 184446
  • Total Submissions: 369369
  • Difficulty: Easy
  • Contributors: Admin

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.

 

Code (BFS)

from collections import *
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root is None:
            return 0

        q = deque([(root, 1)])
        max_lvl = 1

        while q:
            node, lvl = q.popleft()
            max_lvl = max(max_lvl, lvl)
            if node.left is not None: 
                q.append((node.left, lvl+1))
            if node.right is not None:
                q.append((node.right, lvl+1))
            
        return max_lvl

 

Code (DFS)

from collections import *
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        return max(self.maxDepth(root.left), self.maxDepth(root.right))+1 if root is not None else 0