前文
继上篇hash table的easy篇,本篇继续分享hash table的medium篇。
3. Longest Substring Without Repeating Characters
class Solution(object):
"""
用传统的dict来完成,不在时加入,在时进行判断:首先判断是否当前的下标差为最大值,接着需要判断下标的起始点更新,
比如'abcdbce',前四个正常录入dict,而到了下标4也就是'b'时,因为'b'在dict里面,所以start从0变成2也就是'c'的位置,
因为接下来不重复的肯定是从c开始计数了,直到又碰到c,此时下标就从2变成6,for也循环结束了,然后返回最大值
Runtime: 80 ms, faster than 37.09% of Python online submissions for Longest Substring Without Repeating Characters.
Memory Usage: 12.3 MB, less than 9.40% of Python online submissions for Longest Substring Without Repeating Characters.
"""
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
dic, res, start, = {}, 0, 0
for i, ch in enumerate(s):
if ch in dic:
# update the res
res = max(res, i-start)
# here should be careful, like "abba"
start = max(start, dic[ch]+1)
dic[ch] = i
# return should consider the last
# non-repeated substring
return max(res, len(s)-start)
18. 4Sum
import collections
import itertools
class Solution(object):
"""
直接沿用3Sum的解法,多添加一层罢了,所以效率也是低的不行,不过这种方法算是最容易想出的。
Runtime: 808 ms, faster than 22.63% of Python online submissions for 4Sum.
Memory Usage: 10.7 MB, less than 100.00% of Python online submissions for 4Sum.
"""
def fourSum(self, nums, target):
nums.sort()
ans = []
for a in range(len(nums)-3):
if a > 0 and nums[a] == nums[a-1]:
continue
for b in range(a+1,len(nums)-2):
if b > a+1 and nums[b] == nums[b-1]:
continue
c, d = b+1, len(nums)-1
while c < d:
tot = nums[a]+nums[b]+nums[c]+nums[d]
if tot == target:
ans.append([nums[a],nums[b],nums[c],nums[d]])
if tot <= target:
c += 1
while nums[c] == nums[c-1] and c < d:
c += 1
if tot >= target:
d -= 1
while nums[d] == nums[d+1] and c < d:
d -= 1
return ans
class Solution2(object):
"""
这里采用python的高级解法,这些用法看的我眼花缭乱,感觉自己学了一个假python;
通过defaultdict建立字典,可以在key不存在时不报错,而是默认value为list即空列表;
用combinations找出所有的index、value能构成的二元元祖;
接着遍历two_sum的key,也就是nums任意两个数的和,因为value是set,所以接下来都是围绕set的操作;
set.isdisjoint是求交集,即两个set没有相同的部分返回真,所以完美规避了两个pair相同;
pair1|pair2则是求并集,即两个set的所有元素,;
这里的sorted也是必备的,需要把不同的索引但是重复的数字给删除了;
关于del two_sum[t],也可以不删除,因为去掉这句代码照常运行,不过速度会慢点,这点还不清楚原因。
Runtime: 168 ms, faster than 70.47% of Python online submissions for 4Sum.
Memory Usage: 23.5 MB, less than 100.00% of Python online submissions for 4Sum.
"""
def fourSum(self, nums, target):
two_sum = collections.defaultdict(list)
res = set()
for (n1, i1), (n2, i2) in itertools.combinations(enumerate(nums), 2):
two_sum[i1+i2].append({n1, n2})
for t in list(two_sum.keys()):
if not two_sum[target-t]:
continue
for pair1 in two_sum[t]:
for pair2 in two_sum[target-t]:
if pair1.isdisjoint(pair2):
res.add(tuple(sorted(nums[i] for i in pair1 | pair2)))
del two_sum[t]
return [list(r) for r in res]
36. Valid Sudoku
class Solution(object):
"""
直接按题目大意,从横、竖、9宫格三方面来比较
比较有意思的是9宫格的取得方式(每次取一个小九宫格),另外比较的话直接定义字典(或集合)来存储,存在的话则说明有重复值
Runtime: 84 ms, faster than 34.44% of Python online submissions for Valid Sudoku.
Memory Usage: 11.7 MB, less than 5.11% of Python online submissions for Valid Sudoku.
"""
def isValidSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: bool
"""
for i in range(9):
if not self.isValidNine(board[i]):
return False
col = [c[i] for c in board]
if not self.isValidNine(col):
return False
for i in [0, 3, 6]:
for j in [0, 3, 6]:
block = [board[s][t] for s in [i, i+1, i+2] for t in [j, j+1, j+2]]
if not self.isValidNine(block):
return False
return True
def isValidNine(self, row):
map = {}
for c in row:
if c != '.':
if c in map:
return False
else:
map[c] = True
return True
class Solution2(object):
"""
可以说是上面的简化版,不过相对没那么好理解
Runtime: 76 ms, faster than 42.37% of Python online submissions for Valid Sudoku.
Memory Usage: 11.8 MB, less than 5.11% of Python online submissions for Valid Sudoku.
"""
def isValidSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: bool
"""
seen = set()
return not any(x in seen or seen.add(x)
for i, row in enumerate(board)
for j, c in enumerate(row)
if c != '.'
for x in ((c, i), (j, c), (i/3, j/3, c)))
class Solution3(object):
"""
相对上面一种简化版,这个版本更好理解
Runtime: 80 ms, faster than 40.20% of Python online submissions for Valid Sudoku.
Memory Usage: 11.9 MB, less than 5.11% of Python online submissions for Valid Sudoku.
"""
def isValidSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: bool
"""
seen = []
for i, row in enumerate(board):
for j, c in enumerate(row):
if c != '.':
seen += [(c,j),(i,c),(i/3,j/3,c)]
return len(seen) == len(set(seen))
49. Group Anagrams
class Solution(object):
"""
建立有序字典,比对每一个排序后的值,如果数值相同,则加入到dict的value里,
最后再对dict.value进行排序,返回列表即可
Runtime: 96 ms, faster than 92.77% of Python online submissions for Group Anagrams.
Memory Usage: 17.5 MB, less than 5.13% of Python online submissions for Group Anagrams
"""
def groupAnagrams(self, strs):
"""
:type strs: List[str]
:rtype: List[List[str]]
"""
groups = collections.defaultdict(list)
for s in strs:
groups[tuple(sorted(s))].append(s)
return list(map(sorted, groups.values()))
94. Binary Tree Inorder Traversal
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution1(object):
"""
中序遍历,即先获取左子树的结果,再根节点,再右子树,思路还是很清晰
Runtime: 12 ms, faster than 99.66% of Python online submissions for Binary Tree Inorder Traversal.
Memory Usage: 11.8 MB, less than 5.78% of Python online submissions for Binary Tree Inorder Traversal.
"""
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
res = []
self.helper(root, res)
return res
def helper(self, root, res):
if root:
self.helper(root.left, res)
res.append(root.val)
self.helper(root.right, res)
class Solution2(object):
"""
iteratively,即用迭代的思路来完成该题,整体和上述差别不大
Runtime: 16 ms, faster than 98.85% of Python online submissions for Binary Tree Inorder Traversal.
Memory Usage: 11.8 MB, less than 5.78% of Python online submissions for Binary Tree Inorder Traversal.
"""
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
res,stack = [],[]
while True:
while root:
stack.append(root)
root = root.left
if not stack:
return res
node = stack.pop()
res.append(node.val)
root = node.right
138. Copy List with Random Pointer
# Definition for a Node.
class Node(object):
def __init__(self, val, next, random):
self.val = val
self.next = next
self.random = random
class Solution(object):
"""
先构造字典,将老链表和新链表一一对应,这样就构造了一个纯next的链表,然后再循环即可
Runtime: 392 ms, faster than 33.67% of Python online submissions for Copy List with Random Pointer.
Memory Usage: 14.6 MB, less than 100.00% of Python online submissions for Copy List with Random Pointer.
"""
def copyRandomList(self, head):
"""
:type head: Node
:rtype: Node
"""
nodeDict = dict()
dummy = Node(0, None, None)
nodeDict[head] = dummy
newHead, pointer = dummy, head
while pointer:
node = Node(pointer.val, pointer.next, None)
nodeDict[pointer] = node
newHead.next = node
newHead, pointer = newHead.next, pointer.next
pointer = head
while pointer:
if pointer.random:
nodeDict[pointer].random = nodeDict[pointer.random]
pointer = pointer.next
return dummy.next
166. Fraction to Recurring Decimal
class Solution(object):
"""
Runtime: 36 ms, faster than 7.30% of Python online submissions for Fraction to Recurring Decimal.
Memory Usage: 11.9 MB, less than 5.55% of Python online submissions for Fraction to Recurring Decimal.
"""
def fractionToDecimal(self, numerator, denominator):
"""
:type numerator: int
:type denominator: int
:rtype: str
"""
# divmod获取整除后的整数和余数
n, remainder = divmod(abs(numerator), abs(denominator))
# sign判断是否有负数,作为符号展示
sign = '-' if numerator*denominator < 0 else ''
result = [sign+str(n), '.']
stack = []
# 循环判断余数是否开始循环
while remainder not in stack:
stack.append(remainder)
n, remainder = divmod(remainder*10, abs(denominator))
result.append(str(n))
idx = stack.index(remainder)
result.insert(idx+2, '(')
result.append(')')
return ''.join(result).replace('(0)', '').rstrip('.')
187. Repeated DNA Sequences
class Solution(object):
"""
直接依次遍历取值,判断是否存在定义的dict里,存在就val+1,不存在就为1,最后遍历取值val>1的
Runtime: 72 ms, faster than 58.05% of Python online submissions for Repeated DNA Sequences.
Memory Usage: 30.4 MB, less than 52.31% of Python online submissions for Repeated DNA Sequences.
"""
def findRepeatedDnaSequences(self, s):
"""
:type s: str
:rtype: List[str]
"""
dict1 = {}
for i,v in enumerate(s[:-9]):
dict1[s[i:i+10]] = dict1.get(s[i:i+10],0) + 1
return [k for k,v in dict1.iteritems() if v>1]
class Solution2(object):
"""
用Counter来简化第一步行程dict的操作,并且效率也变高了
Runtime: 68 ms, faster than 63.86% of Python online submissions for Repeated DNA Sequences.
Memory Usage: 35 MB, less than 15.66% of Python online submissions for Repeated DNA Sequences
"""
def findRepeatedDnaSequences(self, s):
"""
:type s: str
:rtype: List[str]
"""
from collections import Counter
return [k for k,v in Counter([s[x:x+10] for x in range(len(s)-9)]).iteritems() if v > 1]
274. H-Index
class Solution(object):
"""
先排序再计算
Runtime: 24 ms, faster than 65.02% of Python online submissions for H-Index.
Memory Usage: 11.9 MB, less than 47.22% of Python online submissions for H-Index.
"""
def hIndex(self, citations):
"""
:type citations: List[int]
:rtype: int
"""
N = len(citations)
citations.sort()
h = 0
for i, c in enumerate(citations):
h = max(h, min(N - i, c))
return h
299. Bulls and Cows
class Solution(object):
"""
先逐一匹配看是否相等,然后算出两个列表的长度最小值,最后获取bull和cow的个数
Runtime: 24 ms, faster than 99.74% of Python online submissions for Bulls and Cows.
Memory Usage: 11.7 MB, less than 85.37% of Python online submissions for Bulls and Cows.
"""
def getHint(self, secret, guess):
"""
:type secret: str
:type guess: str
:rtype: str
"""
bulls = sum(map(operator.eq, secret, guess))
both = sum(min(secret.count(x), guess.count(x)) for x in set(guess))
return '%dA%dB' % (bulls, both - bulls)
总结
感觉hash table的medium题后面的题意比较难理解,整体相对easy要难一些。