枚举算法(Enumeration Algorithm):也称为穷举算法,指的是按照问题本身的性质,一一列举出该问题所有可能的解,并在逐一列举的过程中,将它们逐一与目标状态进行比较以得出满足问题要求的解。在列举的过程中,既不能遗漏也不能重复。
注:在枚举算法中,当问题规模很大时,效率一般比较低
例1:两数之和https://leetcode.cn/problems/two-sum/
class Ques1:
def twoSum(self,nums,target):
answer=[]
for i in range(len(nums)-1):
for j in range(i+1,len(nums)):
if nums[i]+nums[j] == target:
answer=[i,j]
return answer
时间复杂度为:O(n**2)
例二:计算质数https://leetcode.cn/problems/count-primes/
class Solution(object):
def isprime(self,x):
if x<=1:
return False # x<=1的情况单独判断,质数的范围是大于1
for i in range(2, int(math.sqrt(x))+1):
if x % i == 0:
return False
return True
def countPrimes(self,n):
count = 0
for i in range(1,n):
if self.isprime(i):
count+=1
return count
结果是超时,我们选择更有效率的方法:
对于一个合数,它一定有除了1和本身的质因子,使得它本身一定是这个质因子的倍数;所以我们找到一个质数时,可以筛掉它的倍数。
朴素筛法:
import math
class Ques:
def naive_sieve(self,n):
if n<2:
return []
is_prime = [True]*(n)
is_prime[0] = is_prime[1]=False
primes = []
for i in range(2,n):
if is_prime[i]:
primes.append(i)
# 把所以i的倍数标记为合数
for j in range(i**2,n,i): #步长为i
is_prime[j] = False
return primes
埃氏筛:
class Solution(object):
def countPrimes(self,n):
if n<2:
return 0
is_prime = [True]*(n) # 判断小于n的所有素数,不包括n本身
is_prime[1]=False
for i in range(2,int(math.sqrt(n))+1):
if is_prime[i]:
for j in range(i**2,n,i):
is_prime[j] = False
primes = [i for i in range(1,n) if is_prime[i]] //开辟列表需要更多的时间,可以直接if判断
return len(primes)
例三:公因子数目https://leetcode.cn/problems/number-of-common-factors/
class Solution(object):
def commonFactors(self,a,b):
count = 0
for i in range(1,min(a,b)+1): # 直接用min()找出最小值
if a % i == 0 and b % i == 0:
count+=1
return count
例四:和为s的连续正数序列https://leetcode.cn/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/
解法1:数学计算
class Solution(object):
def fileCombination(self, target):
i,j,res = 1,2,[]
while i<j:
j = (-1 + (1 + 4 * (2 * target + i * i - i)) ** 0.5) / 2
if i<j and j == int(j):
res.append(list(range(i,int(j)+1)))
i+=1
return res
该解法:
解法2:滑动窗口
class Solution(object):
def fileCombination(self, target):
i,j,s,end = 1,2,3,[]
while i<j:
if s == target:
end.append(list(range(i,j+1)))
if s>= target:
s -= i
i+=1
else:
j+=1
s+=j
return end
上面两张图中,第一张图的结果正确!!!【先削减s的值,再递增i的值】
例五:统计圆内格点数目https://leetcode.cn/problems/count-lattice-points-inside-a-circle/
class Solution(object):
def countLatticePoints(self, circles):
min_x, min_y, max_x, max_y = 200, 200, 0, 0
for circle in circles:
if min_x > circle[0] - circle[2]:
min_x = circle[0] - circle[2]
if min_y > circle[1] - circle[2]:
min_y = circle[1] - circle[2]
if max_x < circle[0] + circle[2]:
max_x = circle[0] + circle[2]
if max_y < circle[1] + circle[2]:
max_y = circle[1] + circle[2]
count = 0
for x in range(min_x,max_x+1):
for y in range(min_y,max_y+1):
for x1,y1,r1 in circles:
if (x-x1)**2+(y1-y)**2 <= r1**2:
count+=1
break
return count
例六:网络信号最好的坐标https://leetcode.cn/problems/coordinate-with-maximum-network-quality/
class Solution(object):
def bestCoordinate(self, towers, radius):
max_tuples = [0,0]
val_max = 0
max_x=max(t[0] for t in towers ) # t[0]代表towers每个元素(是一个列表)的第一个值
max_y = max(t[1] for t in towers) # t[1]则是代表每个元素第二个值,以此类推
for x in range(max_x+1):
for y in range(max_y+1):
val0 = 0
for a,b,r in towers:
d = (x-a)**2+(y-b)**2
if radius**2 >= d:
val0 += int(r/(1+d**0.5))
if val0 > val_max:
val_max = val0
max_tuples = [x,y]
return max_tuples
例七:和为k的子数组https://leetcode.cn/problems/subarray-sum-equals-k/
求一个数组的连续子数组:
n = len(nums)
subnums = []
for i in range(n):
for j in range(n):
subnums.append(nums[i,j+1])
那么求解该题:
class Solution(object):
def subarraySum(self, nums, k):
count = 0
length = len(nums)
for i in range(length):
sums = 0
for j in range(i,length):
sums +=nums[j] #
if sums == k:
count+=1
return count
💡
注:相比于:
for i in range(n):
for j in range(i,n):
if nums[i:j+1] == k:
count += 1
但是依旧会超时:前缀和
前缀和:前缀和指一个数组的某下标之前的所有数组元素的和(包括自身)
通常会在前缀和首位放一个0,如:数组[1,2,3],前缀和:[0,1,3,6]
前缀和的作用:
如:
class Solution(object):
def subarraySum(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
count = 0
n = len(nums)
**preSum = [0]
tmp = 0
for i in range(n):
tmp+=nums[i]
preSum.append(tmp) # 求前缀和
for i in range(1,n+1):
for j in range(i,n+1):
if preSum[j]-preSum[i-1]==k:
count+=1
return count