Hash Tables: Ransom Note
一道简易的题目,由于碰到了我经常用到的库 Counter,所以在此还是记录一下
from collections import Counter
def checkMagazine(magazine, note):
magazineList = Counter(magazine)
magazineDict = {v:magazineList[v] for v in magazineList}
noteList = Counter(note)
noteDict = {v:noteList[v] for v in noteList}
for v in noteDict:
if v not in magazineDict or magazineDict[v] < noteDict[v]:
print("No")
return
print("Yes")
return
对比一下其他人使用相同的库的代码,感觉别人写的实在是太骚了呀,深深感觉到自己的掌握还远远不够
python def checkMagazine(magazine, note): if not (Counter(note) - Counter(magazine)): # or Counter(note) - Counter(magazine) == {} print("Yes") else: print("No")
Sherlock and Anagrams
一道中等难度的题目,最初采用将字符串都拆解成他们的不同字串的方法,结果超时了,想想也是,如果是100个字母长度的字符串,那么结果就是2100,不超时才怪。
from collections import Counter
def checkAnag(a,b):
if Counter(a) == Counter(b):
return True
def sherlockAndAnagrams(s):
count = 0
s1 = "".join(reversed(s))
sub1 =[s1[i:i+x+1] for i in range(len(s1)) for x in range(len(s1)-i)]
if s1 in sub1:
sub1.remove(s1)
for i in range(len(sub1)):
for j in range(i+1,len(sub1)):
if checkAnag(sub1[i],sub1[j]):
count += 1
return count
与其对其中的每一个字母进行计数,还不如将所有的字母都按顺序排列一遍,然后再比较最后的两个序列是否相同,此思路的实现代码如下
python def sherlockAndAnagrams(s): count=0 dict={} n=len(s) for i in range(n): for j in range(n-i): sub=''.join(sorted(s[j:j+i+1])) try: dict[sub]+=1 except: dict[sub]=1 for i in dict: count+=dict[i]*(dict[i]-1)//2 return count
Count Triplets
对三个数进行r倍组合,1为特殊情况,我直接用了组合计算,不过代码出现了超时,再研究研究哪里出了问题
from collections import Counter
from itertools import combinations
# Complete the countTriplets function below.
def combinationResult(num):
i = 0
for combination in combinations(range(num),3):
i += 1
return i
def countTriplets(arr, r):
sum = 0
square = r**2
countNum = Counter(arr)
if r == 1:
for v in countNum:
if(countNum[v]>2):
sum += combinationResult(countNum[v])
return sum
sortSet = list(sorted(set(arr)))
firstLimit = sortSet[len(sortSet)-1]/square
for x in sortSet:
if x > firstLimit:
break
if x*r in sortSet and x*square in sortSet:
sum += countNum[x]*countNum[x*r]*countNum[x*square]
return sum
关于组合数的计算,参见python计算组合数的两种实现方法
经过对两种方法(直接进行组合与笛卡尔乘积)的比对,得出直接利用combinations来计算更加迅速一些,以下为比较代码:
import math
import itertools
import time
from itertools import combinations
unique = [1, 2, 3, 4, 5, 56, 78, 23]
time1 = time.time()
for j in range(1000000):
i = 0
for combination in combinations(unique, 2):
i += 1
time2 = time.time()
for j in range(1000000):
d = 0
uniques = [unique, unique]
for combination in itertools.product(*uniques):
d += 1
time3 = time.time()
print("time 2-1 = "+str(time2-time1), "time 3-1 = "+str(time3-time2))
#time 2-1 = 3.7130393981933594 time 3-1 = 7.952743053436279
为了将这道题解决,我看了一下出题者的解释,在出题者的hint中提到本题是能够达到O(n)的复杂度的,反观一下自己,虽然自己并没有写什么循环,不过的话在循环里的if语句中用到了两个in,基本算是O(n3)的复杂度了。
按照作者的意思,作者进行个对arr的遍历,建立两个字典,假设三元组为(A,B,C),两个字典分别是指对于B来说A已经存在了,以及对于C来说(A,B)的组合已经准备好了。
每个字典里面放的并不是实值,而是对于未来三元组的一个可能性的预测,在遍历每个A的同时让B与C的线性空间不断减小,是一个非常有意思的解决思路。以下是它的python代码。
def countTriplets(arr, r):
r2 = Counter()
r3 = Counter()
count = 0
for v in arr:
if v in r3:
count += r3[v]
if v in r2:
r3[v*r] += r2[v]
r2[v*r] += 1
return count