Find35.搜索插入位置给定一个排序数组和一个目标值,在数组中找到目标值并返回其索引。如果数组中不存在目标值,则返回将按顺序插入的位置。您可以假设数组中没有重复元素。示例1:输入:[1,3,5,6],5输出:2示例2:输入:[1,3,5,6],2输出:1示例3:输入:[1,3,5,6],7Output:4Example4:Input:[1,3,5,6],0Output:0首先,让我们回顾一下二进制搜索代码defsearch(nums->list[int],target->int)->int:"""Params:nums(list):sortedarraytarget(int):int"""#如果数组为空ifnotnums:return-1defhelper(left->int,right->int):#循环结束条件:left=right+1whileleft<=right:#避免因值太大而溢出mid=left+(right-left)//2#Shrinkleftifnums[mid]target:left=mid+1#找到,直接returnelifnums[mid]==target:returnmidn=len(nums)idx=helper(0,n-1)返回idx如果idxelse-1defsearchInsert(nums->list[int],target->int)->int:如果不是nums:返回0defhelper(left,right):whileleft<=right:mid=(left+right)//2ifnums[mid]target:right=mid-1elifnums[mid]==target:right=right-1returnleftreturnhelper(0,len(nums)-1)202.快乐数写一个算法判断一个数n是否是快乐数"happynumber》定义为:对于一个正整数,每次用它每个位置的数的平方和代替这个数,然后重复这个过程,直到这个数变成1,也可能是无限循环但是它永远不会变成1。如果能变成1,那么这个数就是一个快乐的数。如果n是一个快乐的数字,则返回True;如果不是,则为假。示例:输入:19输出:true解释:12+92=8282+22=6862+82=10012+02+02=1这道题的关键是当数字n不是happy时如何跳出循环数字。一个简单的思路就是用字典来保存每次转换的结果defisHappy(n):ifn==1:returnTruedicts={}whilen!=1:#如果转换的结果已经存在于字典,直接返回Falseifnindicts:returnFalseans=0whilen>0:ans+=(n%10)*(n%10)n//=10n=ans#如果可以跳出循环返回True复杂度分析内层Complexity$log(n)$,idea2快慢指针,开头的题中隐含了一个链表,我们需要做的是判断是否有环在链表中defisHappy(n):ifn==1:returnTruedefhelper(num):ans=0whilen>0:ans+=(n%10)*(n%10)n//=10returnans#慢指针slow=n#快指针fast=helper(n)#如果快指针和慢指针不相等,直到它们相等whileslow!=fast:slow=helper(slow)fast=helper(helper(fast))returnslow==1205.同构字符串给定两个字符串s和t,判断判断它们是否同构。如果s中的字符可以替换为t,则两个字符串是同构的。所有出现的字符都必须替换为另一个字符,同时保留字符的顺序。两个字符不能映射到同一个字符,但一个字符可以映射自己。示例1:输入:s="egg",t="add"输出:true示例2:输入:s="foo",t="bar"输出:false示例3:输入:s="paper",t="title"output:truedefisIsomorphic(s->str,t->str):如果不是s而不是s:返回False如果不是s或者不是t或len(s)!=len(t):返回Truedicts={}fori,cinenumerate(s):ifcindicts:ifdicts[c]!=t[i]:returnFalsedicts[c]=t[i]returnlen(dicts)==len(set(dicts.values()))的时间复杂度为$O(n)$,空间复杂度为$O(1)$,因为字典最多包含128个元素242.给出两个有效的字谜给定字符串s和t,写一个函数判断t是否是s的变位词。示例1:输入:s="anagram",t="nagaram"输出:true示例2:输入:s="rat",t="car"输出:false解释:你可以假设字符串只包含小写字母.进阶:如果输入字符串包含unicode字符怎么办?你能调整你的解决方案来处理这个问题吗?思路1排序,如果两个字符串是anagrams,则排序后的字符串相同defisAnagram(s:str,t:str)->bool:ifnotsandnott:returnTrueifnotsornottorlen(s)!=len(t):returnFalse#排序s=sorted(s)t=sorted(t)#如果两个字符串是anagramsreturns==t时间复杂度是$O(nlogn)$,并且空间复杂度为$O(1)$。思路2哈希表记录每个字母出现的次数。由于只包含小写字母,我们可以使用固定大小的数组来实现哈希表defisAnagram(s:str,t:str)->bool:ifnotsandnott:returnTrueifnotsornottorlen(s)!=len(t):returnFalse#记录每个字母出现的次数arr=[0]*26fori,cinenumerate(s):arr[ord(c)-ord('a')]+=1arr[ord(t[i])-ord('a')]-=1#如果某个位置的元素小于0,可以直接returnFalseforiinrange(26):ifarr[i]<0:returnFalse#returnsum(arr)==0时间复杂度是$O(n)$,空间复杂度是$O(1)$。如果包含Unicode字符,则需要用字典来记录每个字符出现的次数。思路同290。单词规则给定一个pattern和一个Stringstr,判断str是否遵循相同的规律。Followhere指的是完全匹配,例如pattern中的每个字母与stringstr中的每个非空词之间存在双向连接。示例1:输入:pattern="abba",str="dogcatcatdog"输出:true示例2:输入:pattern="abba",str="dogcatcatfish"输出:false示例3:输入:pattern="aaaa",str="dogcatcatdog"输出:false示例4:输入:pattern="abba",str="dogdogdogdog"输出:false解释:你可以假设pattern只包含小写字母,str包含由一个空格分隔的小写字母。这道题的思路和205题一样,也是用字典defwordPattern(pattern:str,str:str)->bool:ifnotpatternornotstr:returnFalsesplit_str=str.split()iflen(pattern)!=len(split_str):returnFalsedicts={}fori,cinenumerate(pattern):ifcindicts:ifdicts[c]!=split_str[i]:returnFalsedicts[c]=split_str[i]returnlen(dicts)==len(set(dicts.values()))349.两个数组的交集给定两个数组,编写一个函数来计算它们的交集。示例1:输入:nums1=[1,2,2,1],nums2=[2,2]输出:[2]示例2:输入:nums1=[4,9,5],nums2=[9,4,9,8,4]输出:[9,4]解释:输出中的每个元素都必须是唯一的。我们可以忽略输出结果的顺序。去重+搜索defintersection(nums1:List[int],nums2:List[int])->List[int]:ifnotnums1ornotnums2:return[]#去重nums1=set(nums1)nums2=set(nums2)m=len(nums1)#求res=[iforiinnums1ifiinnums2]returnres时间复杂度为$O(m+n)$,set运算时间复杂度为$O(n)$,in/包含。空间复杂度为$O(1)$350。两个数组的交集II给定两个数组,编写一个函数来计算它们的交集。示例1:输入:nums1=[1,2,2,1],nums2=[2,2]输出:[2,2]示例2:输入:nums1=[4,9,5],nums2=[9,4,9,8,4]输出:[4,9]解释:输出结果中每个元素出现的次数应与两个数组中元素出现次数的最小值一致。我们可以忽略输出结果的顺序。高级:如果给定的数组已经排序怎么办?你会如何优化你的算法?如果nums1的大小比nums2小很多,哪种方法更好?如果nums2的元素存储在磁盘上,内存有限,无法一次将所有元素加载到内存中怎么办?defintersect(nums1:List[int],nums2:List[int])->List[int]:如果不是nums1或不是nums2:return[]m,n=len(nums1),len(nums2)res=[]dicts={}#使用字典记录每个数字出现的次数foriinnums1:dicts[i]=dicts.get(i,0)+1foriinnums2:#如果i在字典中其值大于0ifiindictsanddicts[i]>0:res.append(i)dicts[i]-=1returnres时间复杂度为$O(n+m)$,空间复杂度为$O(m)$or$O(n)$如果nums2的元素存放在磁盘上,内存是有限的,不能一次把所有元素加载到内存中,可以并行读取。410.拆分数组最大值给定一个非负整数数组和一个整数m,你需要将这个数组拆分为m个非空的连续子数组。设计一种算法,使m个子数组各自的和的最大值最小。注:数组的长度n满足以下条件:1≤n≤10001≤m≤min(50,n)例子:输入:nums=[7,2,5,10,8]m=2输出:18解释:一共有四种方法可以将nums拆分成2个子数组。其中最好的办法就是分成[7,2,5]和[10,8],因为此时这两个子数组各自和的最大值为18,是所有子数组中最小的个案。BinarySearch+Greedy“使...的最大值尽可能小”是二分查找题的常见问题。在这个问题中,我们注意到当我们选择一个值xx时,我们可以线性验证是否存在满足其最大分区子数组和不超过xx的分区方案。策略如下:defsplitArray(nums:List[int],m:int)->int:defcheck(x:int)->bool:total,cnt=0,1fornuminnums:iftotal+num>x:cnt+=1total=numelse:total+=numreturncnt<=mleft=max(nums)right=sum(nums)whileleftstr:ifnotsorlen(s)<2:returnsdicts={}res=''#统计每个字符在s中出现的次数forc:dicts[c]=dicts.get(c,0)+1#按字符出现次数排序dicts=sorted(dicts.items(),lambdax:x[1],reverse=True)fork,vindicts.items():res+=k*v返回res时间复杂度为$O(nlogn)$,空间复杂度为$O(n)$更简洁的方法deffrequencySort(s:str)->str:ifnotsorlen(s)<2:returnsfromcollectionsimportCounter#Counter(s):返回一个元素统计字典#most_common():根据元素出现的次数降序排列return''.join(k*vfork,v在Counter(s).most_common())540中。有序数组中的单个元素给定一个仅包含整数的有序数组,每个元素将出现两次,而只有一个数字将只出现一次。找到这个号码。示例1:输入:[1,1,2,3,3,4,4,8,8]输出:2示例2:输入:[3,3,7,7,10,11,11]输出:10注意:您的方案应该以O(logn)时间复杂度和O(1)空间复杂度运行。思路1暴力算法遍历整个数组defsingleNonDuplicate(nums:List[int])->int:n=len(nums)i=0whileiint:res=nums[0]foriinnums[1:]:res=res&ireturnres时间复杂度$O(n)$,空间复杂度$O(1)$思路3二分查找defsingleNonDuplicate(nums:List[int])->int:n=len(nums)left,right=0,n-1whileleft<=right:mid=(left+right)//2ifmid+1