sc onsite 21-30
P21 regular和wildcard match准备一波 regular expression 这两道题真的是把本宝宝写哭了。就是各种corner case! 其实基本思想就是dp.
遇到.和相同的时候,应该选左上角进行dp,如果是星星,那么可以继承上面和上上面的结果,作用分别是消除掉前面那个char和相做不存在。然后还可以不停地copy前一个,这里就需要当前一个与s中的字母相同时,可以dp s前的前一个char的结果,总之很绕。
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
dp = [[False]*(len(s)+1) for _ in range(len(p)+1)]
dp[0][0] = True
for i in range(1, len(p)):
dp[i + 1][0] = dp[i - 1][0] and p[i] == '*'
for i in range(len(p)):
for j in range(len(s)):
if p[i]=='.':
dp[i+1][j+1] = dp[i][j]
elif p[i]==s[j]:
dp[i+1][j+1] = dp[i][j]
elif p[i]=='*':
dp[i+1][j+1] = dp[i][j+1] or dp[i-1][j+1]
if i>0 and p[i-1]=='.' or p[i-1]==s[j]:
dp[i+1][j+1] = dp[i+1][j+1] or dp[i+1][j]
print i+1, dp[i+1]
return dp[-1][-1]
wildcard matching https://leetcode.com/problems/wildcard-matching/ 我还是觉得2D dp要好理解得多,面试如果要我优化成1D的DP。那我可是要跪地求饶给他看!
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
dp = [[False]*(len(s)+1) for _ in range(len(p)+1)]
dp[0][0] = True
for i in range(len(p)):
for j in range(len(s)):
if p[i]=='?':
dp[i+1][j+1] = dp[i][j]
elif p[i]==s[j]:
dp[i+1][j+1] = dp[i][j]
elif p[i]=='*':
dp[i+1][j+1] = dp[i][j+1] or dp[i][j] or dp[i+1][j]
print dp[i+1]
return dp[-1][-1]
s = 'aaa'
p = 'aa'
so = Solution()
ans = so.isMatch(s, p)
print(ans)
P22 1. 1. find all amicable numbers.输入一个正整数,找出所有小于这个数的amicable pairs。 看之前的面经有时间复杂度O(nlogn),空间复杂度O(n)的算法。 感觉对于每一个数字求解是sqrt(n). 总的复杂度是n * log(n)。求解答怎么得到nlogn的算法 下面有大神回答:跟count prime类似的思想,通过n log n的复杂度求因子和
我没太听懂,不过还是写一遍count prime好了。aicable number之前写过一次就不写了
class Solution(object):
def countPrimes(self, n):
"""
:type n: int
:rtype: int
"""
if n<2:
return 0
p = [True]*n
p[0], p[1]=False, False
for i in range(2, (int(n**0.5)+1)):
if not p[i]:
pass
else:
for j in range(i*i, n, i):
p[j]=False
return sum(p)
P23 第一轮题目是给一堆会议时间,选出从早7点到晚7点的free时间,比如给了 8-11, 12:30-17:00, 15:00-17:30,就输出7-8, 11-12:30, 5:30-19:00,我想了好一阵,然后说用stack一个一个处理,结果面试官说为啥要用stack,我才意识到用一个结束时间就可以,一开始设置成7:00,处理一个时间就更新一些结束时间,然后输出就行了,不过写完了有一个bug,然后面试小哥说这是一个serious bug,我当时感觉他就有点不满意,囧,加了if else判断处理掉bug
整体不难吧。主要是corner case处理比较麻烦?
class Solution(object):
def findFreeTime(self, d, ms):
"""
:type d: str
:type m: List[str]
:rtype: list[str]
"""
# split times
meetings = []
for m in ms:
s,e = m.split('-')
meetings.append([s,e])
# merge times
mergedMeetings = [meetings[0]]
for i in range(1,len(meetings)):
if mergedMeetings[-1][1]>meetings[i][0]:
mergedMeetings[-1][1]=meetings[i][1]
else:
mergedMeetings.append(meetings[i])
# build result
s, e = d.split('-')
res = []
for m in mergedMeetings:
if m[0]>s:
res.append([s, m[0]])
s = m[1]
if s<e:
res.append([s, e])
return res
day = '7:00-19:00'
meetings = ['8:00-11:00', '12:30-17:00', '15:30-17:30']
so = Solution()
ans = so.findFreeTime(day, meetings)
print ans
P24 中国小哥 + shadow, 聊天, 问project, 问的问题是longest incresing subsequence, 似乎是lintcode上的题?还有一题是大数乘法。
大数乘法如下 https://qiuzhihui.gitbooks.io/r-book/content/big_integer.html LIS如下https://leetcode.com/problems/longest-increasing-subsequence/ 中国大哥就是给力!
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums:
return 0
dp = [1]*len(nums)
for i in range(len(nums)):
for j in range(i):
if nums[i]>nums[j]:
dp[i] = max(dp[i],dp[j]+1)
return max(dp)
nums = [10, 9, 2, 5, 3, 7, 101, 18]
so = Solution()
ans = so.lengthOfLIS(nums)
print ans
P25 第四轮,国人小哥。我也不知道他后来有没有放水,反正是挂了。但过程中他给了很多的提示。题目是这样的:一棵树,代表上司和员工的关系,然后每个节点都有一个对应的权值。然后公司开了一个party,为了让员工们更好的交流,有个规定,如果上司去参加party,那么他的直接下属(直接孩子节点)就不去(同理,如果下属去了,直接上司,父节点就不去)。然后设计一个算法,参加party的人的权值总和最高。这是一道动态规划题,思路是每次计算一个员工去的权值之和与不去的权值之和,从叶子开始。 这不就是house robber 3么? https://leetcode.com/problems/house-robber-iii/
思路:这道题很像dp。就是一直返回最优。根据取不去root的值可以分成2类情况来讨论,因为要返回两个情况的最优,所以需要新建一个helper function。这里提一句,什么时候需要helper function呢? 一般是我们想到这道题需要递归,原来的fuction不能满足这种递归的结构。 dfs也是其中的一种原方程不能满足结构的情况。
Top to bot with memo
class Solution(object):
def rob(self, root):
"""
:type root: TreeNode
:rtype: int
"""
self.memo = {}
return self.helper(root)
def helper(self, root):
if not root: # if not root
return 0
if root not in self.memo: # if it is not in memo
val = 0
if root.left: # we calculate not have left
val += self.helper(root.left.left) + self.helper(root.left.right)
if root.right: # we calculate not have right
val += self.helper(root.right.left) + self.helper(root.right.right)
f = root.val+val # max include root
s = self.helper(root.left) + self.helper(root.right) # max not include root
self.memo[root] = max(f, s)
return self.memo[root]
bot to top solution
class Solution(object):
def rob(self, root):
"""
:type root: TreeNode
:rtype: int
"""
return max(self.helper(root))
def helper(self, root):
if not root:
return [0, 0]
l = self.helper(root.left)
r = self.helper(root.right)
f = root.val + l[1] + r[1]
s = max(l[0]+r[1], l[1]+r[0], l[0]+r[0], l[1]+r[1])
return [f, s]
P26 第一轮是一个大胡子白人,扎着马尾辫。看起来还是挺严肃的。先聊简历,聊了很多。他问到有个我做过的项目,如果想再做一遍的话,问我想怎样改进。编程题是给定一个有向关系图,在给定2个名字,求出这两个人的共同朋友(即2个点能达到的共同节点,类似树的共同祖先)
思路:就是dfs然后求一个交集?
import collections
class Solution(object):
def commonFriends(self, relation, a, b):
if not relation:
return []
dic = collections.defaultdict(set)
for r in relation:
a, b = r
dic[a].add(b)
s, af = [a], set([a])
while s:
tmp = s.pop()
children = dic[tmp]
for c in children:
if c not in af:
s.append(c)
af.add(c)
s, bf = [b], set([b])
while s:
tmp = s.pop()
children = dic[tmp]
for c in children:
if c not in bf:
s.append(c)
bf.add(c)
return list(af&bf)
relation = [[1,2],[2,3],[3,4],[6,5],[5,4]]
a, b = 1, 6
so = Solution()
ans = so.commonFriends(relation, a, b)
print ans
P27 第二轮是一个白人小哥,人很nice。简单的聊了一下简历后就开始编程。题目是如果通讯录里从某一个名字开始翻转了,请把这个名字找出来。类似leetcode这道题:。这题我二分搜索算法犯了个低级错误,大概被扣分不少。 这道题就是find min in rotated array啊。 https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/
class Solution(object):
def findR(self, names):
if not names:
return
l, r = 0, len(names)-1
while l<r:
mid = (l+r)//2
if names[mid]<names[r]:
r = mid
else:
l = mid+1
return names[l]
names = ['case', 'doug', 'aron', 'bob']
so = Solution()
ans = so.findR(names)
print ans
P28 我觉得吧game of life得再写一遍
正常的
class Solution(object):
def gameOfLife(self, board):
"""
:type board: List[List[int]]
:rtype: void Do not return anything, modify board in-place instead.
"""
if not board or not board[0]:
return
for i in range(len(board)):
for j in range(len(board[0])):
cnt = 0
for dp in [(1,0),(-1,0),(0,1),(0,-1),(1,1),(1,-1),(-1,1),(-1,-1)]:
m, n = i+dp[0], j+dp[1]
if 0<=m<len(board) and 0<=n<len(board[0]):
if board[m][n]&1==1:
cnt += 1
if board[i][j]==1 and 2<=cnt<=3:
board[i][j] = board[i][j]^2
if board[i][j]==0 and cnt==3:
board[i][j] = board[i][j]^2
for i in range(len(board)):
for j in range(len(board[0])):
board[i][j] = board[i][j]>>1
print board
board = [[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0]]
so = Solution()
so.gameOfLife(board)
用hash直接来存坐标 输入和输出都不变,为了好验证
class Solution(object):
def gameOfLife(self, board):
"""
:type board: List[List[int]]
:rtype: void Do not return anything, modify board in-place instead.
"""
if not board or not board[0]:
return
dic = {}
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j]==1:
dic[(i,j)] = [1,0]
keys = dic.keys()
for k in keys:
tmp = dic[k]
for dp in [(1,0),(-1,0),(0,1),(0,-1),(1,1),(1,-1),(-1,1),(-1,-1)]:
i, j = k[0] + dp[0], k[1]+dp[1]
if (i,j) in dic:
dic[(i,j)][1] += 1
else:
dic[(i,j)] = [0,1]
keys = dic.keys()
for k in keys:
if dic[k][0]==1:
if 2<=dic[k][1]<=3:
dic[k] = [1,0]
else:
del dic[k]
else:
if dic[k][1]==3:
dic[k] = [1,0]
else:
del dic[k]
for i in range(len(board)):
for j in range(len(board[0])):
if (i,j) in dic:
board[i][j]==1
else:
board[i][j]==0
print board
board = [[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0]]
so = Solution()
so.gameOfLife(board)
P29 Reconstruct Itinerary
backtracking的经典题型,找一个path试,可以就返回,不可以就试下一个。
import collections
class Solution(object):
def findItinerary(self, tickets):
"""
:type tickets: List[List[str]]
:rtype: List[str]
"""
maxL = len(tickets)+1
dic = collections.defaultdict(list)
for f,t in tickets:
dic[f].append(t)
for k in dic:
dic[k].sort()
self.res = None
print self.dfs(dic, 'JFK', ['JFK'], maxL)
print self.res
def dfs(self, dic, cur, path, maxL):
if len(path)==maxL:
self.res = path
return True
for i in range(len(dic[cur])):
c = dic[cur].pop(0)
if self.dfs(dic, c, path+[c], maxL):
return True
dic[cur].append(c)
tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
so = Solution()
so.findItinerary(tickets)
感觉自己不是很熟悉backtracking,那我们就把N-Queen II写一遍好了。
class Solution(object):
def totalNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
"""
board = [['.']*n for _ in range(n)]
dic = set()
res = []
self.bt(0, 0, board, dic, [], n, res)
return res
def bt(self, m, n, board, dic, path, l, res):
if len(path)==l:
return True
for i in range(m, len(board)):
for j in range(len(board[0])):
if (0,i-j) not in dic and (1,i+j) not in dic and\
(2,i) not in dic and (3,j) not in dic:
dic.add((0,i-j))
dic.add((1,i+j))
dic.add((2,i))
dic.add((3,j))
board[i][j]= 'Q'
if self.bt(i, j, board, dic, path+[(i,j)], l, res):
res.append(map(''.join, [k for k in board]))
dic.remove((0,i-j))
dic.remove((1,i+j))
dic.remove((2,i))
dic.remove((3,j))
board[i][j]= '.'
so = Solution()
ans = so.totalNQueens(4)
print ans
P30 然后就做一道类似knight move的题目,给了一个函数list nextMoves(),返回所有下一个有效的move,棋盘无穷大,输出到目的地的最短路径。bfs就可以做好,另开一个hash表记录上一步。follow-up是输出所有的最短路径。用hash表记录上一步所有可能的位置,然后dfs返回所有路径。这道题是在电脑上编译通过的。讲完follow-up时已经没时间了,问了个小问题国人小哥就走了。
感觉这道题目跟P14 很像,那就用bfs写吧。最短路径我总感觉只有唯一解啊。实在不行,我就用level order traversal的办法好了。具体代码就不写了。