from typing import List
classSolution:# 二分查找defbinarySearch2D(self, nums: List[List[int]], target: int) -> bool:ifnot nums or len(nums) == 0ornot nums[0] or len(nums[0]) == 0:
returnFalse
m, n = len(nums), len(nums[0])
i, j = 0, n - 1while (i < m and j >= 0):
if target < nums[i][j]:
j -= 1elif target > nums[i][j]:
i += 1else:
returnTruereturnFalse
4. 找出只出现一次的元素
from functools import reduce
from typing import List
import random
classSolution:defsingleNumber(self, nums: List[int]) -> int:return reduce(lambda x, y: x ^ y, nums)
#测试代码
lst = [i for i in range(101)]
lst.extend(lst);lst.remove(20);random.shuffle(lst)
print(Solution().singleNumber(lst))
5. 找出重复出现的元素
from typing import List
import random
classSolution:# 1.异或法:O(N) O(1) 需要前提条件 # 异或法控制了空间复杂度O(1)# 1-100的数,放在101位数组中,多出的一位是重复元素,找出该元素。A^A^B = B# 此方法全部计算后才能得到结果,而其他方法可以在中途找到直接return# 重要条件:因为所有的B都必须异或一次,所以要求1-100的数字都必须出现deffindRepeatNumber(self,nums: List[int]) -> int:
tmp = nums[0]
for i in enumerate(nums[1:]):
tmp ^= (i[0] ^ i[1])
return tmp
# 2.下标定位之元素交换法:O(N)O(1) # 数组元素交换控制了空间复杂度O(1)# 但是也导致了前提条件:数组中元素的最大值必须小于数组的长度。(MAX<=len-1)# 特别说明(因为用了原地):元素值必须小于列表长deffindRepeatNumber2(self, nums: List[int]) -> int:for i,v in enumerate(nums):
if v != i:
if nums[v] == v:
return v
nums[v] , nums[i] = v , nums[v]
return-1# 3.哈希表中介法:O(N)O(N) deffindRepeatNumber3(self,nums:List[int]) -> int:
_dict = {}
for v in nums:
if v in _dict:
return v
_dict[v] = ''return-1# 4.排序判断法:O(NlogN)O(1) deffindRepeatNumber4(self, nums):
nums.sort()
pre = nums[0]
for index in range(1, len(nums)):
if pre == nums[index]:
return pre
pre = nums[index]
# 测试代码
lst = [i for i in range(101)]
lst.append(10);random.shuffle(lst)
print(Solution().findRepeatNumber(lst))
print(Solution().findRepeatNumber2(lst))
print(Solution().findRepeatNumber3(lst))
print(Solution().findRepeatNumber4(lst))
6. 有序数组中最小数
from typing import List
classSolution:defminArray(self, numbers: List[int]) -> int:
left, right = 0, len(numbers) - 1while left < right:
mid = left + (right-left) // 2if numbers[mid] > numbers[right]:
left = mid + 1elif numbers[mid] < numbers[right]:
right = mid
else:
right -= 1return numbers[left]
print(Solution().minArray([23,40,90,12]))
7. 相邻元素之后最大(最小)的元素序号
import sys
import random
from typing import List
defsearch_near_diff(nums:List[tuple]):
pre, max_diff, max_idx= nums[0][1], 0, 0# 最大# pre, max_diff, max_idx= nums[0][1],sys.maxsize , 0 # 最小for idx,_ in enumerate(nums[1:]):
tmp = abs(_[1] - pre)
if max_diff < tmp:
# if max_diff > tmp: # 最小
max_diff, max_idx = tmp, idx
pre = _[1]
return nums[max_idx][0],nums[max_idx+1][0]
# 测试代码
NUM, MAX = 5, 100
lands = [(i,random.randint(0,MAX)) for i in range(1,NUM+1)]
print(lands)
print(search_near_max_diff(lands))
8. 最长公共前缀
from typing import List
deflongestCommonPrefix(strs: List[str]) -> str:
ans = ''for i in zip(*strs):
# 去重后等于1,说明三个列字符一样if len(set(i)) == 1:
ans += i[0]
else:
breakreturn ans
cmn = longestCommonPrefix(['ab', 'abc', 'abcd'])
print(cmn)
9. 两数之和(数组中两元素和为某数的所有组合)
from typing import List
classSolttion:# O(N) 哈希键存储defsum(self, nums: List[int], target: int) -> List[int]:
hash = {}
for i, num in enumerate(nums):
if target - num in hash:
return (hash[target - num], i)
hash[nums[i]] = i
return ()
# 暴力 O(NN) defsum2(self, nums: List[int], target: int) -> List[int]:for _,i in enumerate(nums):
for __,j in enumerate(nums[_:]):
if i+j == target:
return _,_+__
# O(N)
print(Solttion().sum([1,5,6,8],9))
# O(n*n)
print(Solttion().sum2([1,5,6,8],9))
10. 3数/N数之和(数组中N个元素和为某数的所有组合)
from typing import List
classSolution:defthreeSum(self, nums: List[int]) -> List[List[int]]:# 解决nSum问题if len(nums) <= 2:
return []
nums.sort()
return self.nSum(nums, 3, 0)
defnSum(self, nums, n, target):"""注意,此函数的nums应是排序后的数组,否则每层递归都要对nums排序,效率极低"""if len(nums) < n:
return []
res = []
# twoSumif n == 2:
left, right = 0, len(nums)-1while left < right:
if nums[left] + nums[right] == target:
res.append([nums[left], nums[right]])
while left < right and nums[left] == nums[left+1]:
left += 1while left < right and nums[right] == nums[right-1]:
right -= 1
left += 1
right -= 1elif nums[left] + nums[right] > target:
right -= 1else:
left += 1return res
else:
for first_idx in range(len(nums)):
if first_idx > 0and nums[first_idx] == nums[first_idx-1]:
continue
subres = self.nSum(nums[first_idx+1:], n-1, target-nums[first_idx])
for i in range(len(subres)):
res.append([nums[first_idx]]+subres[i])
return res
defthreeSum2(self, nums: List[int]) -> List[List[int]]:"""三数之和,暴力列举的话,时间复杂度为O(n^3),该解法为O(n^2)"""# 因为是计算三数之和,因此输入数组的长度必须大于等于3,否则返回[]# 因此首先进行长度判断
n = len(nums)
if n < 3: return []
# 特况判定后,对输入数组进行快排,直接使用sort()# 为之后的有序查找奠定基础
nums.sort()
res = []
# 因为最后我们需要得到索引,因此按照索引遍历数组for i in range(n):
# 因为需要找到三数之和为0,又因为数组有序,我们设计的双指针都在i的右侧,即大于nums[i]# 所以一旦nums[i]>0则之后不需要再进行判断,直接返回结果即可if nums[i] > 0: return res
# 因为题目要求,不需要重复答案,因此如果nums[i]与之前相同则跳过# 这里注意不能从第一个开始跳过的,因为[0, 0, 0]都跳过变成[]if(i>0and nums[i]==nums[i-1]):
continue# 好,这些特殊情况处理之后,我们定义双指针# left从当前索引的下一个索引开始
L = i+1# right从最后一个索引开始
R = n-1# 双指针结束条件为L<Rwhile L < R:
# 如果双指针对应的值加上当前遍历值和为0,则满足条件if nums[i] + nums[L] + nums[R] == 0:
# 将结果装入res中
res.append([nums[i], nums[L], nums[R]])
# 一旦出现匹配结果,仍然要保证结果不重复,# 也就是左右指针的下一个值如果和上一个相同需要一直移动# 而且要控制移动后L<R# L指针向右,R指针向左while(L<R and nums[L]==nums[L+1]):
L += 1while(L<R and nums[R]==nums[R-1]):
R -= 1# 当然如果并没有重复,那么指针就按照正常情况进行移动
L += 1
R -= 1# 如果我们发现三数之和大于0,因为数组有序,只需移动R指针即可elif (nums[i]+nums[L]+nums[R] > 0):
R -= 1# 否则移动左指针else:
L += 1return res
# UT
lst = [-1,0,1,2,-1,-4,8,-6,-2]
lst.sort()
print(Solution().nSum(lst,4,0))
11. 组合总数(列表中元素和为某数的所有组合)
from typing import List
classSolution:defcombinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
candidates = sorted(candidates)
ans = []
deffind(s, use, remain):for i in range(s, len(candidates)):
c = candidates[i]
if c == remain:
ans.append(use + [c])
if c < remain:
find(i, use + [c], remain - c)
if c > remain:
return
find(0, [], target)
return ans
defcombinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
dp = [[] for _ in range(target+1)]
for i in sorted(candidates,reverse=True):
for j in range(i,target+1):
if j==i:dp[j] = [[i]];continue
dp[j].extend([x+[i] for x in dp[j-i]])
# print(dp)return dp[-1]
defcombinationSum3(self, candidates: List[int], target: int) -> List[List[int]]:
dict = {}
for i in range(1,target+1):
dict[i]=[]
for i in range(1,target+1):
for j in candidates:
if i==j:
dict[i].append([i])
elif i>j:
for k in dict[i-j]:
x = k[:]
x.append(j)
x.sort() # 升序,便于后续去重if x notin dict[i]:
dict[i].append(x)
return dict[target]
# 测试代码
print(len(Solution().combinationSum([1,2,3,4],5)))
print(len(Solution().combinationSum2([1,2,3,4],5)))
print(len(Solution().combinationSum3([1,2,3,4],5)))
12. 查找TOP-K
from typing import List
import random
# 交换列表索引元素 复杂度O(N)defswap(arr, a, b):
arr[a], arr[b] = arr[b], arr[a]
return arr
deffindKLargest(arr: List[int], k: int) -> int:
l = len(arr)
target = l - k # K大索引# 遍历区间:left、right
left = 0
right = l - 1whileTrue:
index = __partition(arr, left, right)
if index == target:
return arr[index]
elif index < target:
# 下一轮在 [index + 1, right] 里找
left = index + 1else:
# 下一轮在 [left,index - 1] 里找
right = index - 1def__partition(nums, left, right):# randint 是包括左右区间的
random_index = random.randint(left, right)
nums[random_index], nums[left] = nums[left], nums[random_index]
pivot = nums[left] # 中心点位置
lt = left + 1
rt = right
whileTrue:
while lt <= rt and nums[lt] < pivot:
lt += 1while lt <= rt and nums[rt] > pivot:
rt -= 1if lt > rt:
break
swap(nums, lt, rt)
lt += 1
rt -= 1
swap(nums, left, rt)
return rt
# UT
print(findKLargest([1, 5, 7, 8, 3, 9], 4))
13. 字符串蕴含(包含)
defsearchHas(input, target) -> list:
res = []
i = 0while i <= len(input) - len(target):
j = 0while j < len(target):
# print(j,input[i + j],target[j])if input[i + j] == target[j]:
# print(j,target[j])if j == len(target) - 1:
res.append(i)
j += 1else:
break
i += 1return res
# UT
print(search('helloworld', 'llo'))
14. 约瑟夫问题:间隔出列
# 长度n,间隔k,起始startdefjosephus(n,k,start:int = 1):
lista = list(range(1, n+1))
i = start - 1for number in range(n, 0, -1):
i = (i+k-1) % number
person = lista.pop(i)
yield person
# UT
result = [x for x in josephus(5,3)]
res = josephus(5,3)
result = [next(res) for _ in range(5)]
print(result)