LC
P21. Course Schedule
topo sort的经典题型。不过这道题的corner case感觉有点不太make sense.
import collections
class Solution(object):
def canFinish(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
if not prerequisites: return True
pre = collections.defaultdict(set)
nex = collections.defaultdict(set)
for p in prerequisites:
pre[p[0]].add(p[1])
nex[p[1]].add(p[0])
start = [k for k in nex if k not in pre]
l = len(set([k for k in nex] + [k for k in pre]))
res = []
while start:
tmp = start.pop()
res.append(tmp)
for c in nex[tmp]:
pre[c].remove(tmp)
if not pre[c]:
del pre[c]
if c not in pre:
start.append(c)
return len(res) == l
s = Solution()
ans = s.canFinish(2, [[1,0]])
print ans
P22. Search in Rotated Sorted Array
这道题还是写得有一点点挣扎。不过最后意识到了应该怎么写。就是先找到有序的那一段,然后判断target在不在里面,不过不在那么就一定在另外一段里面。我觉得这一段对于考验corner case特别强调。 2分查找的精髓在于,每一次循环都在缩小范围,而每一次解都应该在缩小的范围之内。
l和r是两个互相逼近的关系,因为这里用的//整除,所以,永远l永远都不可能通过+1到达r,极限的情况是比r小1。而光靠//, r就能够逼近l。所以这里r需要取len(nums)而不是len(nums)-1
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
if not nums: return -1
l, r = 0, len(nums)
while l < r:
mid = (l + r)//2
if nums[mid] == target:
return mid
if nums[0] <= nums[mid]: # left in order
if nums[0] <= target < nums[mid]:
r = mid
else:
l = mid + 1
else: # right in order
if nums[mid] < target <= nums[-1]:
l = mid + 1
else:
r = mid
return -1
s = Solution()
ans = s.search([4, 5, 6, 7, 0, 1, 2], 2)
print ans
P23. One Edit Distance
这道题,主要是能分析三种情况,一种是insert, 一种是replacement, 还有一种delete。遇到不一样的话,就可以通过长度来判断是哪一种。
class Solution(object):
def isOneEditDistance(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
ls, lt = len(s), len(t)
for i in range(min(ls, lt)):
if s[i] != t[i]:
if ls == lt:
return s[i+1:] == t[i+1:] # replacement
elif ls < lt:
return s[i:] == t[i+1:] # insert
elif ls > lt:
return s[i+1:] == t[i:] # delete
return abs(ls - lt) == 1 and (s in t or t in s) # the difference have to be the last char
s = Solution()
ans = s.isOneEditDistance('ac', 'acc')
print ans
P24. Find K Pairs with Smallest Sums
这道题是一道经典的heap的题目,不过总感觉用tuple写起来可读性不高。到时候还是要看看那天那个大神怎么用一个class然后重新定义build in equal method的。
import heapq
class Solution(object):
def kSmallestPairs(self, nums1, nums2, k):
"""
:type nums1: List[int]
:type nums2: List[int]
:type k: int
:rtype: List[List[int]]
"""
pairs = [(-(i+j), i, j) for i in nums1 for j in nums2]
heap = []
for p in pairs:
if len(heap) == k:
if -p[0] < -heap[0][0]:
heapq.heappop(heap)
heapq.heappush(heap, p)
else:
heapq.heappush(heap, p)
return [[p[1], p[2]] for p in heap]
s = Solution()
ans = s.kSmallestPairs([1,1,2], [1,2,3], 2)
print ans
P25. Word Break
很喜欢这道题。
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
return self.helper(s, set(wordDict))
def helper(self, s, dic):
# base case
if not s:
return True
for i in range(1, len(s)+1):
if s[:i] in dic:
if self.helper(s[i:], dic):
return True
return False
s = Solution()
ans = s.wordBreak("leetcode", ["leet", "code"])
print ans
然后time limit exceed了。应该上面这种做法会重复计算很多路径,所以我们用memo来优化一下。
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
self.memo = {'': True}
return self.helper(s, set(wordDict))
def helper(self, s, dic):
# base case
if s in self.memo:
return self.memo[s]
for i in range(len(s), 0, -1):
if s[:i] in dic:
if self.helper(s[i:], dic):
self.memo[s] = True
return self.memo[s]
self.memo[s] = False
return self.memo[s]
word = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
dic = ["a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"]
s = Solution()
ans = s.wordBreak(word, dic)
print ans
稍微再简化一下代码
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
return self.helper(s, set(wordDict), {'': True})
def helper(self, s, dic, memo):
if s not in memo:
for i in range(len(s), 0, -1):
if s[:i] in dic:
if self.helper(s[i:], dic, memo): # if any one of path works return True
memo[s] = True
return memo[s]
memo[s] = False # tried all the path, return False
return memo[s]
s = Solution()
ans = s.wordBreak("a", ["a"])
print ans
P26. Implement Trie (Prefix Tree)
这种题目,写熟了真的是毫无难度!
class Node(object):
def __init__(self):
self.dic = {}
self.isWord = False
def __repr__(self):
return repr(self.dic)
class Trie(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.root = Node()
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: void
"""
cur = self.root
for s in word:
if s not in cur.dic:
cur.dic[s] = Node()
cur = cur.dic[s]
cur.isWord = True
def search(self, word):
"""
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
cur = self.root
for s in word:
if s not in cur.dic:
return False
cur = cur.dic[s]
return cur.isWord
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
:type prefix: str
:rtype: bool
"""
cur = self.root
for s in prefix:
if s not in cur.dic:
return False
cur = cur.dic[s]
return True
s = Trie()
s.insert('abc')
s.insert('abb')
print s.search('abd')
print s.root
P27. Reverse Words in a String II
这种string处理的题目遇到python, 真的是找死。
class Solution(object):
def reverseWords(self, str):
"""
:type str: List[str]
:rtype: void Do not return anything, modify str in-place instead.
"""
str[:] = list(' '.join(''.join(str).strip().split()[::-1]))
抄一个正常的放这里。
class Solution(object):
def reverseWords(self, s):
"""
:type s: a list of 1 length strings (List[str])
:rtype: nothing
"""
s.reverse()
index = 0
for i in range(len(s)):
if s[i] == " ":
s[index: i] = reversed(s[index: i])
index = i + 1
s[index: ] = reversed(s[index: ])
P28. Spiral Matrix
这道题,有点恶心,不过我们一层一层剥开他的心。
class Solution(object):
def spiralOrder(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[int]
"""
if not matrix or not matrix[0]:
return []
res = []
while matrix:
# upper
res += matrix[0]
matrix = matrix[1:]
# right
if matrix and matrix[0]:
for row in matrix:
res.append(row.pop())
# buttom
if matrix and matrix[0]:
res += matrix[-1][::-1]
matrix = matrix[:-1]
# left
if matrix and matrix[0]:
for row in reversed(matrix):
res.append(row.pop(0))
return res
s = Solution()
ans = s.spiralOrder([
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
])
print ans
P29. Copy List with Random Pointer
这道题就是我去年去uber面试的那道题呀。有几个corner case没有特别处理好。
class RandomListNode(object):
def __init__(self, x):
self.label = x
self.next = None
self.random = None
class Solution(object):
def copyRandomList(self, head):
"""
:type head: RandomListNode
:rtype: RandomListNode
"""
dic = {}
if not head:
return head
cur = head
while cur:
dic[cur] = RandomListNode(cur.label)
cur = cur.next
cur = head
while cur:
dic[cur].next = dic[cur.next] if cur.next else None
dic[cur].random = dic[cur.random] if cur.random else None
cur = cur.next
return dic[head]
P30. Clone Graph
我先写一个两遍过的解法。
# Definition for a undirected graph node
class UndirectedGraphNode:
def __init__(self, x):
self.label = x
self.neighbors = []
class Solution:
# @param node, a undirected graph node
# @return a undirected graph node
def cloneGraph(self, node):
if not node:
return node
dic = {}
stack = [node]
visited = set()
# deep copy node
while stack:
tmp = stack.pop()
visited.add(tmp)
dic[tmp.label] = UndirectedGraphNode(tmp.label)
for c in tmp.neighbors:
if c not in visited:
stack.append(c)
# copy neighbors
for n in visited:
for c in n.neighbors:
dic[n.label].neighbors.append(dic[c.label])
return dic[node.label]
a = UndirectedGraphNode(-1)
b = UndirectedGraphNode(1)
a.neighbors.append(b)
s = Solution()
ans = s.cloneGraph(a)
print ans.label
然后我再写一个一遍过的解法。
# Definition for a undirected graph node
class UndirectedGraphNode:
def __init__(self, x):
self.label = x
self.neighbors = []
def __repr__(self):
return repr(self.label)
class Solution:
# @param node, a undirected graph node
# @return a undirected graph node
def cloneGraph(self, node):
if not node:
return node
root = UndirectedGraphNode(node.label)
visited = {node.label: root}
stack = [node]
while stack:
cur = stack.pop()
for c in cur.neighbors:
if c.label not in visited:
stack.append(c)
visited[c.label] = UndirectedGraphNode(c.label)
visited[cur.label].neighbors.append(visited[c.label])
return root