前言
本文为个人学习的算法学习笔记,学习笔记,学习笔记,不是经验分享与教学,不是经验分享与教学,不是经验分享与教学,若有错误各位大佬轻喷(T^T)。主要使用编程语言为Python3,各类资料题目源于网络,主要自学途径为蓝桥云课,侵权即删。
算法思想
前缀和:对于一个长度为n的列表a,其前缀和sum[i] = a[0] + a[1] + ...+ a[i],得到一个新的列表sum称为前缀和。
性质:
1.迭代性:sum[i] = sum[i-1] + a[i]
def get_persum(a):
sum0 = [0] * len(a)
sum0[0] = a[0]
for i in range(len(a)):
sum0[i] = sum0[i-1] + a[i]
2.区间求法:a[r] + ... + a[l] = sum[l] - sum[r-1]
def get_sum(sum0, l, r):
ans = 0
if(l == 0):
ans = sum0[r]
else:
ans = sum[r] - sum[l - 1]
return ans
题目实战1
以下题目均来自蓝桥云课题库,链接如下
1.区间次方和
问题描述
给定一个长度为 nn 的整数数组 aa 以及 mm 个查询。
每个查询包含三个整数 l,r,kl,r,k 表示询问 l∼rl∼r 之间所有元素的 kk 次方和。
请对每个查询输出一个答案,答案对 10^9+7取模。
输入格式
第一行输入两个整数 n,mn,m 其含义如上所述。
第二行输入 nn 个整数 a[1],a[2],...,a[n]a[1],a[2],...,a[n]。
接下来 mm 行,每行输入三个整数 l,r,kl,r,k 表示一个查询。
输出格式
输出 mm 行,每行一个整数,表示查询的答案对 10^9+7 取模的结果。
错误实录
import os
import sys
# 请在此输入您的代码
#求前缀和列表函数
def get_persum(a, n):
sum0 = []
sum0[0] = a[0]
for i in range(1,n):
sum0[i] = sum0[i-1] + a[i]
return sum0
#求前缀和区间函数
def get_sum(sum0, l, r):
if l == 0:
return sum0[r]
else:
return sum0[r] - sum0[l-1]
#列表读入函数
def input_list():
return list(map(int, input().split()))
#输入
n, m = input_list()
a_origin = input_list()
while m != 0:
l, r, k = input_list()
a = []
i = 0
for i in range(len(a_origin)-1):
a[i] = a_origin[i]**k
sum0 = []
sum0 = get_persum(a, n)
ans = get_sum(sum0, l, r)
print(ans)
print()
m -= 1
错误点
a = [] # 创建空列表
a[0] = 1 # 报错!空列表没有索引0
正确的列表初始化方法
a = [] # 初始化空列表
for i in range(len(a_origin)):
a.append(a_origin[i] ** k) # 正确:使用append添加元素
解答
import os
import sys
# 求前缀和列表函数
def get_persum(a, n):
sum0 = [0] * n
sum0[0] = a[0]
for i in range(1, n):
sum0[i] = sum0[i-1] + a[i]
return sum0
# 求前缀和区间函数(修改:调整索引)
def get_sum(sum0, l, r):
# 输入的l,r从1开始,转换为从0开始的索引
l -= 1
r -= 1
if l == 0:
return sum0[r]
else:
return sum0[r] - sum0[l-1]
# 列表读入函数
def input_list():
return list(map(int, input().split()))
# 输入
n, m = input_list()
a_origin = input_list()
while m != 0:
l, r, k = input_list()
a = []
for i in range(len(a_origin)):
a.append(a_origin[i] ** k)
sum0 = get_persum(a, n)
ans = get_sum(sum0, l, r)
ans = ans % (10**9 + 7)
print(ans)
m -= 1
2.小郑的平衡串
问题描述
平衡串指的是一个字符串,其中包含两种不同字符,并且这两种字符的数量相等。
例如,abababababab 和 aababbaababb 都是平衡串,因为每种字符各有三个,而 abaababaab 和 aaaabaaaab 都不是平衡串,因为它们的字符数量不相等。
平衡串在密码学和计算机科学中具有重要应用,比如可以用于构造哈希函数或者解决一些数学问题。
小郑拿到一个只包含 LL、QQ 的字符串,他的任务就是找到最长平衡串,且满足平衡串的要求,即保证子串中 LL、QQ 的数量相等。
输入格式
输入一行字符串,保证字符串中只包含字符 LL、QQ。
输出格式
输出一个整数,为输入字符串中最长平衡串的长度。
解答
import os
import sys
# 请在此输入您的代码
def get_persum(a):
sum0 = [0] * len(a)
sum0[0] = a[0]
for i in range(1, len(a)):
sum0[i] = sum0[i-1] + a[i]
return sum0
def get_sum(sum0, l, r):
if l == 0:
ans = sum0[r]
else:
ans = sum0[r] - sum0[l-1]
return ans
a = ""
a = input()
code = []
maxstr = 0
for i in range(len(a)):
if(a[i] == 'L'):
code.append(1)
else:
code.append(-1)
sum0 = get_persum(code)
for l in range(len(code)):
for r in range(l, len(code)):
if(get_sum(sum0, l, r) == 0):
maxstr = max(maxstr,r - l + 1)
print(maxstr)
体悟:问题提及区间,大多数情况就会用到前缀和
算法拓展——二维前缀和
tips:对于二维列表,编程过程中建议下标都从1开始
区间和求法
#打印矩阵函数
def output(a, n):
for i in range(1, n+1):
print(''.join(map(str, a[i][1:])))
#输入二维矩阵行列数
n, m = list(map(int, input().split()))
#读入二维矩阵
a = [[0] * (m+1) for _ in range(n+1)]
sum = [[0] * (m+1) for _ in range(n+1)]
for i in range(1,n+1):
a[i] = [0] + list(map(int, input().split()))
output(a, n)
#构造二位前缀和
for i in range(1, n+1):
for j in range(1, m+1):
sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + a[i][j]
#二维前缀和区间和函数
def get_sum(sum, x1, y1, x2, y2):
return sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1]
题目实战2
1.统计子矩阵
问题描述
给定一个 N×MN×M 的矩阵 AA, 请你统计有多少个子矩阵 (最小 1×11×1, 最大 N×M)N×M) 满足子矩阵中所有数的和不超过给定的整数 KK ?
输入格式
第一行包含三个整数 N,MN,M 和 KK.
之后 NN 行每行包含 MM 个整数, 代表矩阵 AA.
输出格式
一个整数代表答案。
import os
import sys
# 请在此输入您的代码
#初始化准备
n, m, k = map(int, input().split())
ans = 0
#读入二维矩阵
a = [[0] * (m+1) for _ in range(n+1)]
sum0 = [[0] * (m+1) for _ in range(n+1)]
for i in range(1,n+1):
a[i] = [0] + list(map(int, input().split()))
#二维前缀和区间和函数
def get_sum(sum0, x1, y1, x2, y2):
return (sum0[x2][y2] - sum0[x1-1][y2] - sum0[x2][y1-1] + sum0[x1-1][y1-1])
for i in range(1, n+1):
for j in range(1, m+1):
sum0[i][j] = sum0[i][j-1] + sum0[i-1][j] -sum0[i-1][j-1] + a[i][j]
for x1 in range(1,n+1):
for y1 in range(1,m+1):
for x2 in range(x1, n+1):
for y2 in range(y1, m+1):
if(get_sum(sum0, x1, y1, x2, y2) <= k):
ans += 1
print(ans)