Our problem is given a matrix costs in which costs[i][j] is the traveling cost going from node i to node j, we are asked to return the minimum cost for traveling from node 0 and visit every other node exactly once and return back to node 0.
We use g(x, S) to denote the minimum cost for a travel which starts from node x, visits every node in S exactly once and returns to node 0. The detailed DP process can be illustrated in the following example.
Let’s say we have a 5×5 costs matrix, which means we have 5 node.
In the first round, we calculate:
g(1, ∅) = costs(1,0) # minimum cost of travel from node 1 and ends at node 0 without visiting any other node
g(2, ∅) = costs(2,0)
g(3, ∅) = costs(3,0)
g(4, ∅) = costs(4,0)
In the second round, we calculate:
# minimum cost of travel from node 1 and ends at node 0 with visiting only one other node
g(1, {2}) = costs(1,2) + g(2, ∅)
g(1, {3}) = costs(1,3) + g(3, ∅)
g(1, {4}) = costs(1,4) + g(4, ∅)
# minimum cost of travel from node 2 and ends at node 0 with visiting only one other node
...
In the third round, we calculate:
# minimum cost of travel from node 1 and ends at node 0 with visiting two other nodes
g(1, {2,3}) = min(costs(1,2)+g(2,{3}), costs(1,3)+g(3,{2})) # either you choose to go from 1 to 2 first, or go from 1 to 3 first
g(1, {3,4}) = min(costs(1,3)+g(3,{4}), costs(1,4)+g(4,{3}))
g(1, {2,4}) = min(costs(1,2)+g(2,{4}), costs(1,4)+g(4,{2}))
# minimum cost of travel from node 2 and ends at node 0 with visiting two other nodes
...
In the fourth round, we calculate:
# minimum cost of travel from node 1 and ends at node 0 with visiting three other nodes
# either you choose to go from 1 to 2 first, or go from 1 to 3 first or go from 1 to 4 first
g(1, {2,3,4}) = min(costs(1,2)+g(2,{3,4}), costs(1,3)+g(3,{2,4}), costs(1,4)+g(4,{2,3}))
# minimum cost of travel from node 2 and ends at node 0 with visiting three other nodes
...
After the four rounds above, we can calculate our ultimate goal, g(0, {1,2,3,4}):
from itertools import *
class Solution:
def shortest(self, costs):
'''
costs: List[List[n]]
'''
def to_str(l):
return '-'.join([str(ll) for ll in l])
# nodes excluding the starting node
nodes = set([i for i,v in enumerate(costs) if i])
g = {}
for x in xrange(1, len(costs)):
g[x] = {}
g[x][''] = costs[x][0]
for k in xrange(1, len(costs)-1):
for x in xrange(1, len(costs)):
for c in combinations(node-set([x]), k):
g[x][to_str(c)] = min([costs[x][e] + g[e][to_str(c-set([e]))] for e in c])
return min([costs[0][e] +g[e][to_str(nodes-set([e]))] for e in nodes])
In the code `g` is a dictionary. Its value its another dictionary. For example, if we want to refer to g(1, {2,3,4}), we can access it by `g[1][‘2-3-4’]`.
Let’s analyze the time complexity and the space complexity for this DP algorithm.
Space complexity: before calculating g(0, {1,2,3,4}), we need to store:
Therefore, for each row here, we need to store g(.) values of number $latex \sum\limits_{k=1}^{n-2} C_{n-1}^k = O(2^n) $ (n is total number of nodes: 0, 1, .., n-1). We have n-1 rows here. So in total space complexity is $latex O(n2^n)$.
Time complexity: we know we have $latex O(n2^n)$ g(.) values to store. We get each of these values by taking min function over O(n) possible candidates(See Python code line 20). Therefore, the total time complexity is $latex O(n^2 2^n)$.
Total Accepted: 4861Total Submissions: 13934Difficulty: Medium
Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left node that shares the same parent node) or empty, flip it upside down and turn it into a tree where the original right nodes turned into left leaf nodes. Return the new root.
For example: Given a binary tree {1,2,3,4,5},
1
/ \
2 3
/ \
4 5
return the root of the binary tree [4,5,2,#,#,3,1].
The serialization of a binary tree follows a level order traversal, where ‘#’ signifies a path terminator where no node exists below.
Here’s an example:
1
/ \
2 3
/
4
\
5
The above binary tree is serialized as "{1,2,3,#,#,4,#,#,5}".
Code
class Solution:
# @param root, a tree node
# @return root of the upside down tree
def upsideDownBinaryTree(self, root):
# take care of the empty case
if not root:
return root
# take care of the root
l = root.left
r = root.right
root.left = None
root.right = None
# update the left and the right children, form the new tree, update root
while l:
newL = l.left
newR = l.right
l.left = r
l.right = root
root = l
l = newL
r = newR
return root
Idea
First, let’s walk through what is called “upside down”. I draw an example plot. The original tree roots at 7. To turn it upside down, you first mirror it along a horizontal line. Then, for any branch stretching towards right top (marked as red), you make it as left leaf.
Now, the basic idea is to go though from the original root (7), make root’s left child (1) as new parent whose left child will be the original root’s right left (6) and right child will be the original root (7). After that, you set new root to root.left (1), and process it in the same way. As pointed out by (https://leetcode.com/discuss/18410/easy-o-n-iteration-solution-java), the core idea is to “Just think about how you can save the tree information you need before changing the tree structure“.
Total Accepted: 76404Total Submissions: 229965Difficulty: Hard
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?
Idea:
This problem is similar to a previous post. However, it can be done using a property regarding preorder and postorder: postorder traverse = reverse of {preorder traverse with right node visited earlier than left node}.
The detailed implementation: modify the previous post code. You still do a preorder traverse but with the order: [root], [right], [left]. To do so, when you push to the stack, you push node.left first then push node.right. So when you pop the stack, you will visit the right node first then sometimes later the left node. At last, when you return the `res` list, you return its reverse.
In practice you have two choices, either always append values to `res` left, or use normal append but return `res[::-1]`.
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):
# An alternative: append left to res
# def postorderTraversal(self, root):
# st = [root]
# res = []
# while st:
# root = st.pop()
# if root:
# res.insert(0,root.val)
# st.append(root.left)
# st.append(root.right)
# return res
def postorderTraversal(self, root):
st = [root]
res = []
while st:
root = st.pop()
if root:
res.append(root.val)
st.append(root.left)
st.append(root.right)
return res[::-1]
Total Accepted: 89130Total Submissions: 240451Difficulty: Medium
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?
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 preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
stack = [root]
res = []
while stack:
node = stack.pop()
if node:
res += [node.val]
stack.append(node.right)
stack.append(node.left)
return res
Idea
Preorder: [root], [left], [right]
So we use a stack to add right first then left. so whenever we pop an element out, the left element will always be popped out before the right element. Since we want to return preorder result, whenever an element is popped out, we add it to `res` immediately.
Total Accepted: 30832Total Submissions: 81197Difficulty: Easy
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”
For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
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 lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
if p.val > q.val:
p, q = q, p
if p.val < root.val and q.val > root.val:
return root
if p.val == root.val or q.val == root.val:
return root
if p.val < root.val and q.val < root.val:
return self.lowestCommonAncestor(root.left, p, q)
else:
return self.lowestCommonAncestor(root.right, p, q)
Idea
Since it is already a BST, it should be easy. Please go to another post to see how to find lowest common ancestor for normal binary tree.
Total Accepted: 1824Total Submissions: 4282Difficulty: Medium
This is a follow up of Shortest Word Distance. The only difference is now word1 could be the same as word2.
Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list.
word1 and word2 may be the same and they represent two individual words in the list.
For example, Assume that words = ["practice", "makes", "perfect", "coding", "makes"].
Given word1 = “makes”, word2 = “coding”, return 1. Given word1 = "makes", word2 = "makes", return 3.
Note: You may assume word1 and word2 are both in the list.
Code
import sys
class Solution(object):
def shortestWordDistance(self, words, word1, word2):
"""
:type words: List[str]
:type word1: str
:type word2: str
:rtype: int
"""
min_dis = sys.maxint
p1, p2 = min_dis, -min_dis
for i in xrange(len(words)):
w = words[i]
if w not in set([word1, word2]):
continue
if word1 == word2:
p1 = p2
p2 = i
else:
if w == word1:
p1 = i
if w == word2:
p2 = i
min_dis = min(min_dis, abs(p1 - p2))
return min_dis
Idea
A little similar to the previous post. The only difference is that, if word1==word2, then we need to set `p1` to previous `p2`, and set `p2` to current `i`. We keep unchanged how `min_dis` is determined: min(min_dis, abs(p1 – p2))
Total Accepted: 1811Total Submissions: 5300Difficulty: Medium
This is a follow up of Shortest Word Distance. The only difference is now you are given the list of words and your method will be called repeatedly many times with different parameters. How would you optimize it?
Design a class which receives a list of words in the constructor, and implements a method that takes two words word1 and word2 and return the shortest distance between these two words in the list.
For example, Assume that words = ["practice", "makes", "perfect", "coding", "makes"].
Given word1 = “coding”, word2 = “practice”, return 3. Given word1 = "makes", word2 = "coding", return 1.
Note: You may assume that word1does not equal toword2, and word1 and word2 are both in the list.
Code
class WordDistance(object):
def __init__(self, words):
"""
initialize your data structure here.
:type words: List[str]
"""
word_dic = dict()
for i in xrange(len(words)):
w = words[i]
if word_dic.get(w, None):
word_dic[w].append(i)
else:
word_dic[w] = [i]
self.word_dic = word_dic
def shortest(self, word1, word2):
"""
Adds a word into the data structure.
:type word1: str
:type word2: str
:rtype: int
"""
l1 = self.word_dic[word1]
l2 = self.word_dic[word2]
min_dis = sys.maxint
p1 = 0
p2 = 0
while p1 < len(l1) and p2 < len(l2):
min_dis = min(min_dis, abs(l1[p1]-l2[p2]))
if min_dis == 1:
return 1
if l1[p1] > l2[p2]:
p2 += 1
else:
p1 += 1
return min_dis
# Your WordDistance object will be instantiated and called as such:
# wordDistance = WordDistance(words)
# wordDistance.shortest("word1", "word2")
# wordDistance.shortest("anotherWord1", "anotherWord2")
Idea
Since the function `shortest` will be called repeatedly, we need to use more space in trade of less time. We know from the previous post that if we don’t use any space we can have an O(N) algorithm. Therefore, in this problem, we want to achieve shorter time than O(N) by using more space.
What we do is just using a dictionary to store positions for words. (key: word, value: a list of positions in `words` where the word appears). Since we traverse from words[0] to words[-1], we guarantee every position list stores positions in an ascending order. Then, when we call `shortest(words, word1, word2)`. we extract `word1`’s and `word2`’s position lists.
The crux of the algorithm is that if p1 (a position from word1’s position list) is already larger than p2 (a position from word2’s position list), then every position after p1 in the word1’s position list will have larger distance with p2. Therefore, you don’t need to compare those positions after p1 anymore. Instead, you increase p2 in order to let it be closer to p1.
The time complexity is O(m+n) where m and n are the lengths of l1 and l2.
Total Accepted: 2492Total Submissions: 5946Difficulty: Easy
Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list.
For example, Assume that words = ["practice", "makes", "perfect", "coding", "makes"].
Given word1 = “coding”, word2 = “practice”, return 3. Given word1 = "makes", word2 = "coding", return 1.
Note: You may assume that word1does not equal toword2, and word1 and word2 are both in the list.
Code
import sys
class Solution(object):
def shortestDistance(self, words, word1, word2):
"""
:type words: List[str]
:type word1: str
:type word2: str
:rtype: int
"""
p1 = p2 = -1
min_dis = sys.maxint
for i in xrange(len(words)):
w = words[i]
if w not in [word1, word2]:
continue
if w == word1:
p1 = i
if w == word2:
p2 = i
if p1 != -1 and p2 != -1:
min_dis = min(min_dis, abs(p1 - p2))
return min_dis
Idea
Just need O(N) time to traverse the `word` list once. `p1` and `p2` are the last index of seeing word1 and word2. If the current visit word is either word1 or word2, you can update the min distance just by `abs(p1-p2)`.
Total Accepted: 9627Total Submissions: 34073Difficulty: Medium
Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +,- and *.
class Solution(object):
def diffWaysToCompute(self, input):
if input.isdigit():
return [int(input)]
res = []
for i in xrange(len(input)):
if input[i] in "-+*":
res1 = self.diffWaysToCompute(input[:i])
res2 = self.diffWaysToCompute(input[i+1:])
res += [eval(str(k)+input[i]+str(j)) for k in res1 for j in res2]
return res
Idea
Deal it with recursion. Whenever you see an operator (`-`, `+` or `*`), you get results from the operator’s left side (line 8) and right side (line 9) and concatenate results from both sides with the operator (line 10) . Remember that to judge if a string represents a pure number you can use `string.isdigit()`. (line 3)