先求出来这条线,然后统一往上走直到upper,往下走直到lower。这个上下能波动几次,就是最终返回值
其实就是在算这个曲线的高低差是多少
class Solution:
def numberOfArrays(self, differences: List[int], lower: int, upper: int) -> int:
value=0
min_val=0
max_val=0
for i in range(len(differences)):
value=value+differences[i]
min_val=min(min_val,value)
max_val=max(max_val,value)
if upper-lower-(max_val-min_val)+1>0:
return upper-lower-(max_val-min_val)+1
return 0
class Solution(object):
def numberOfArrays(self, differences, lower, upper):
"""
:type differences: List[int]
:type lower: int
:type upper: int
:rtype: int
"""
#前缀和还原差分数组
arr = [0]
for i in range(len(differences)):
arr.append(arr[-1]+differences[i])
max_val = max(arr)
min_val = min(arr)
left = lower - min_val
right = upper - max_val
if right < left:
return 0
return right-left+1
力扣https://leetcode-cn.com/problems/maximum-fruits-harvested-after-at-most-k-steps/solution/qiu-chu-fan-wei-nei-qian-zhui-he-zui-da-tfeoy/
class Solution(object):
def maxTotalFruits(self, fruits, startPos, k):
"""
:type fruits: List[List[int]]
:type startPos: int
:type k: int
:rtype: int
"""
n = len(fruits)
postions = [fruit[0] for fruit in fruits]
amounts = [fruit[1] for fruit in fruits]
# 前缀和便于统计不同区间范围总和
preSum = [0] * (n + 1)
for i in range(1, n + 1):
preSum[i] = preSum[i - 1] + amounts[i - 1]
ret = float('-inf')
for x in range(k + 1):
y = k - 2*x
# 往左 x 步, 往右 y 步
left, right = startPos - x, startPos + y
# 确定区间边界
leftIdx, rightIdx = bisect_left(postions, left), bisect_right(postions, right)
ret = max(ret, preSum[rightIdx] - preSum[leftIdx])
# 往左 y 步, 往右 x 步
left, right = startPos - y, startPos + x
leftIdx, rightIdx = bisect_left(postions, left), bisect_right(postions, right)
ret = max(ret, preSum[rightIdx] - preSum[leftIdx])
return ret
上面那个代码应该有点问题,在确定左边界之后,右边界应该是k-2*左边届。
class Solution:
def platesBetweenCandles(self, s: str, queries: List[List[int]]) -> List[int]:
#双指针找到i到j之间间隔最长的蜡烛[h1,h2],前缀和找到[h1,h2]之间盘子数量
#前缀和
presum=[0 for _ in range(len(s))]
if s[0]=='*':
presum[0]=1
for i in range(1,len(s)):
if s[i]=='*':
presum[i]=presum[i-1]+1
else:
presum[i]=presum[i-1]
#二分找边界
res=[]
A = [i for i,char in enumerate(s) if char=='|']
for i in range(len(queries)):
l=queries[i][0]
r=queries[i][1]
left=bisect_left(A,l)
right=bisect_right(A,r)-1
if left
class Solution:
def platesBetweenCandles(self, s: str, queries):
presum = [0 for _ in range(len(s))]
if s[0] == '*':
presum[0] = 1
for i in range(1, len(s)):
if s[i] == '*':
presum[i] = presum[i - 1] + 1
else:
presum[i] = presum[i - 1]
def find_left(alist,l):
left=0
right=len(alist)-1
while left=l:
right=mid
else:
left=mid+1
return right
def find_right(alist,r):
left = 0
right = len(alist) - 1
while left < right:
mid = (left + right+1) // 2
if alist[mid]<=r:
left = mid
else:
right = mid-1
return right
# 二分找边界
res = []
# 蜡烛的index
alist = [i for i, char in enumerate(s) if char == '|']
print(alist)
for i in range(len(queries)):
# l和r都是index
l = queries[i][0]
r = queries[i][1]
# 找l右边第一个index
pos1 = find_left(alist, l)
pos2 = find_right(alist, r)
if pos1 < pos2:
count = presum[alist[pos2]] - presum[alist[pos1]]
res.append(count)
else:
res.append(0)
return res
# 输入:s = "**|**|***|", queries = [[2,5],[5,9]]
# # 输出:[2,3]
s = "**|**|***|"
queries = [[2,5],[5,9]]
res=Solution().platesBetweenCandles(s,queries)
print(res)
class Solution {
public:
vector platesBetweenCandles(string s, vector>& queries) {
//预处理+二分
//建立一个数组 放满蜡烛的方位
//对于每次查询 二分找到 其对应的下标
//返回 两坐标在s上的之差-1-(在数组上的之差-1)=s上之差减去数组上只差
vector candles;
int len=s.size();
for(int i=0;i ans;
len=queries.size();
for(int i=0;i=right_index) ans.emplace_back(0);
else ans.emplace_back(candles[right_index]-candles[left_index]-(right_index-left_index));
}
return ans;
}
//对于right 找到靠左的
//对于left 找到靠右的
int binary_search(vector& aim,int cur,bool flag){
int left=0,right=aim.size()-1;
while(leftcur){
right=mid-1;
}else{
left=mid+1;
}
}
if(!flag && left>0 && aim[left]>cur) left--;
if(flag && left
class Solution(object):
def platesBetweenCandles(self, s, queries):
"""
:type s: str
:type queries: List[List[int]]
:rtype: List[int]
"""
# 前缀和,二分找边界
presum = [0 for _ in range(len(s))]
if s[0] == "*":
presum[0] = 1
for i in range(1, len(s)):
if s[i] == "*":
presum[i] = presum[i - 1] + 1
else:
presum[i] = presum[i - 1]
#二分查找的数组要有单调性,得是查找index
arr_index = []
for i in range(len(s)):
if s[i] == "|":
arr_index.append(i)
if len(arr_index) == 0:
return [0 for _ in range(len(queries))]
res = []
for i in range(len(queries)):
a1 = queries[i][0]
a2 = queries[i][1]
#找不到蜡烛的情况处理
if a1 > arr_index[-1] or a2 < arr_index[0]:
res.append(0)
continue
# 找a1右边最靠近a1的蜡烛
left = 0
right = len(arr_index) - 1
while left <= right:
mid = (left + right) // 2
if arr_index[mid] >= a1:
right = mid - 1
else:
left = mid + 1
b1 = arr_index[right + 1]
# 找a2左边最靠近的蜡烛
left = 0
right = len(arr_index) - 1
while left <= right:
mid = (left + right) // 2
if arr_index[mid] <= a2:
left = mid + 1
else:
right = mid - 1
b2 = arr_index[left - 1]
if b1 <= b2:
cur = presum[b2] - presum[b1]
else:
cur = 0
res.append(cur)
return res
前缀和+双指针找边界,超时
我是用的前缀和+双指针找边界,超时
class Solution:
def platesBetweenCandles(self, s: str, queries: List[List[int]]) -> List[int]:
#双指针找到i到j之间间隔最长的蜡烛[h1,h2],前缀和找到[h1,h2]之间盘子数量
#前缀和
presum=[0 for _ in range(len(s))]
if s[0]=='*':
presum[0]=1
for i in range(1,len(s)):
if s[i]=='*':
presum[i]=presum[i-1]+1
else:
presum[i]=presum[i-1]
#双指针找
res=[]
for i in range(len(queries)):
left=queries[i][0]
right=queries[i][1]
while s[left]=='*' and left
724. 寻找数组的中心下标
前缀和
前缀和+后缀和
class Solution:
def pivotIndex(self, nums):
presum = [0 for _ in range(len(nums)+1)]
postsum = [0 for _ in range(len(nums)+1)]
for i in range(1,len(presum)):
presum[i] = presum[i-1] + nums[i-1]
for i in range(len(nums)-2,-1,-1):
postsum[i] = postsum[i+1] + nums[i+1]
print(presum)
print(postsum)
for i in range(len(nums)):
if presum[i] == postsum[i]:
return i
return -1
# nums = [1, 7, 3, 6, 5, 6]
# nums = [1, 2,3]
nums = [-1,-1,-1,1,1,1]
res = Solution().pivotIndex(nums)
print(res)
2163 删除元素后和的最小差值
前缀和+后缀和+堆
class Solution:
def minimumDifference(self, nums: List[int]) -> int:
m = len(nums)
n = m // 3
min_pq = nums[m - n:]
heapify(min_pq)
suf_max = [0] * (m - n + 1) # 后缀最大和
suf_max[-1] = s = sum(min_pq)
for i in range(m - n - 1, n - 1, -1):
s += nums[i] - heappushpop(min_pq, nums[i])
suf_max[i] = s
max_pq = [-v for v in nums[:n]] # 所有元素取反当最大堆
heapify(max_pq)
pre_min = -sum(max_pq) # 前缀最小和
ans = pre_min - suf_max[n]
for i in range(n, m - n):
pre_min += nums[i] + heappushpop(max_pq, -nums[i])
ans = min(ans, pre_min - suf_max[i + 1])
return ans
作者:endlesscheng
链接:https://leetcode-cn.com/problems/minimum-difference-in-sums-after-removal-of-elements/solution/qian-zhui-zui-xiao-he-hou-zhui-zui-da-he-yz3d/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public long minimumDifference(int[] nums) {
int n = nums.length / 3;
// min[i] 表示 nums[0] ~ nums[i] 个元素中选择 n 个元素和最小
long[] min = new long[3 * n];
// max[i] 表示 nums[i] ~ nums[3*n-1] 个元素中选择 n 个元素和最大
long[] max = new long[3 * n];
// 升序队列、 降序队列
PriorityQueue asc = new PriorityQueue<>();
PriorityQueue desc = new PriorityQueue<>((a, b) -> b - a);
long sum_first = 0, sum_second = 0;
for (int i = 0; i < 3 * n; i++) {
int l = i, r = 3 * n - 1 - i;
int left = nums[l], right = nums[r];
sum_first += left;
desc.add(left);
sum_second += right;
asc.add(right);
if (i >= n) {
sum_first -= desc.poll();
sum_second -= asc.poll();
}
min[l] = sum_first;
max[r] = sum_second;
}
// 遍历所有情况找到最小差值
long minAns = Long.MAX_VALUE;
for (int i = n - 1; i < 2 * n; i++) {
minAns = Math.min(minAns, min[i] - max[i + 1]);
}
return minAns;
}
}
795. 区间子数组个数
暴力双指针,超时
class Solution:
def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
#从i到j的子数组是否满足条件
#这么写有一个错误:当前index不满足时,还可以往后遍历
cnt=0
index1=0
while index1=left and max_val<=right:
cnt+=1
index2=index2+1
if index2 < len(nums):
max_val = max(max_val, nums[index2])
else:
break
index1+=1
return cnt
前缀和mostk
力扣
class Solution:
def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
#前缀和,拆分成小于right的子数组和小于left的子数组
def mostk(k):
#以右端点为基准
ans=0
pre=0
for i in range(len(nums)):
if nums[i]<=k:
pre=pre+1
else:
pre=0
ans=ans+pre
return ans
return mostk(right)-mostk(left-1)
1109. 航班预订统计
前缀和还原差分数组
对于航班预订系统的理解:
前缀和还原差分数组,比如bookings=[[1,2,10]]
n = 5,有5个航班,在第一个航班上来10个人,,第三个航班-10. 差分数组为[10, 0, -10, 0, 0],最后结果是[10, 10, 0, 0, 0]。
第三个航班-10,说明从第三个航班开始,没有第一个航班上带来的增量了
class Solution(object):
def corpFlightBookings(self, bookings, n):
"""
:type bookings: List[List[int]]
:type n: int
:rtype: List[int]
"""
#转化为上车下车问题
res=[0 for _ in range(n)]
for i in range(len(bookings)):
cur_first=bookings[i][0]
cur_last=bookings[i][1]
res[cur_first-1]+=bookings[i][2]
if cur_last
253. 会议室 II
前缀和还原差分数组
560. 和为 K 的子数组
前缀和+哈希表
力扣
暴力
前缀和
前缀和+哈希表
注意:实现的时候要先判断差值是否在哈希表中 ,然后再把当前值加入哈希表。先都加入哈希表,再判断差值是否在哈希表中,有case无法通过,如:。因为无法判断减去的值是不是当前自身值
class Solution(object):
def subarraySum(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
# 前缀和
presum = [0 for _ in range(len(nums))]
maps={}
presum[0] = nums[0]
maps[presum[0]]=1
for i in range(1, len(nums)):
presum[i] = presum[i - 1] + nums[i]
if presum[i] in maps:
maps[presum[i]]+=1
else:
maps[presum[i]]=1
count = 0
for i in range(len(nums)):
if presum[i]==k:
count+=1
if presum[i]-k in maps:
count+=maps[presum[i]-k]
return count
# count=0
# for i in range(len(nums)):
# for j in range(i+1,len(nums)+1):
# cur=nums[i:j]
# if sum(cur)==k:
# count+=1
return count
1124.表现良好的最长时间段
前缀和+单调栈
6035. 选择建筑的方案数
前缀和+后缀和
20220403周赛的一道题,开始思路想错了,以为是01背包,加了cache之后只能通过一半的case.
背包如下:
class Solution:
def numberOfWays(self, s: str) -> int:
@lru_cache(None)
def dfs(index,count,pre):
if index == len(s) and count!=0:
return 0
elif count == 0:
return 1
#如果选当前的index
a1,a2 = 0,0
if s[index]!=pre and count >= 1:
a1 = dfs(index+1,count-1,s[index])
#如果不选当前的index
a2 = dfs(index+1,count,pre)
return a1+a2
return dfs(0,3,"2")
class Solution(object):
def numberOfWays(self, s):
"""
:type s: str
:rtype: int
"""
#只有101,和010两种情况。
#遍历1次,找当前0前面有多少个1,当前0后面多少个1.前缀和,后缀和,注意下标
#遍历1次,找当前1前面多少个0,当前1后面多少个0.前缀和,后缀和,注意下标
def find_pre_post(value):
presum = [0 for _ in range(len(s))]
postsum = [0 for _ in range(len(s))]
if s[0] == value:
presum[0] = 1
if s[-1] == value:
postsum[-1] = 1
for i in range(1,len(s)):
if s[i] == value:
presum[i] = presum[i-1] + 1
else:
presum[i] = presum[i-1]
for i in range(len(s)-2,-1,-1):
if s[i] == value:
postsum[i] = postsum[i+1] + 1
else:
postsum[i] = postsum[i+1]
return presum,postsum
presum1,postsum1 = find_pre_post("1")
presum0,postsum0 = find_pre_post("0")
count = 0
for i in range(len(s)):
if s[i] == "0":
count += presum1[i]*postsum1[i]
if s[i] == "1":
count += presum0[i]*postsum0[i]
return count
6072. 转角路径的乘积中最多能有几个尾随零
数学+前缀和+后缀和
0417周赛t3,我用的是深搜,走路径。超时
class Solution:
def maxTrailingZeros(self, grid: List[List[int]]) -> int:
def cal_0(num):
count = 0
num_str = str(num)
for h in range(len(num_str)-1,-1,-1):
if num_str[h] == "0":
count += 1
else:
break
return count
#visited存储已经走过的方向,小于等于2时说明转弯最多1次
dires = [(-1,0),(1,0),(0,-1),(0,1)]
def dfs(start_x,start_y,visited):
if start_x < 0 or start_x > len(grid)-1 or start_y < 0 or start_y > len(grid[0])-1 or grid[start_x][start_y] < 0:
return [1]
tmp = grid[start_x][start_y]
grid[start_x][start_y] = -1
res_sum = []
for new_x,new_y in dires:
if len(visited) > 0 and visited[-1] != (new_x,new_y):
visited.append((new_x,new_y))
if len(visited) <= 2:
tmp1 = dfs(start_x + new_x, start_y + new_y, visited)
for t in tmp1:
cur = t * tmp
res_sum.append(cur)
visited.pop()
elif len(visited) > 0 and visited[-1] == (new_x,new_y):
tmp1 = dfs(start_x + new_x, start_y + new_y, visited)
for t in tmp1:
cur = t * tmp
res_sum.append(cur)
elif len(visited) == 0:
visited.append((new_x, new_y))
tmp1 = dfs(start_x + new_x, start_y + new_y, visited)
for t in tmp1:
cur = t * tmp
res_sum.append(cur)
visited.pop()
grid[start_x][start_y] = tmp
return res_sum
res = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
str_num = str(grid[i][j])
if str_num[-1] in ('1','3','7','9'):
continue
cur_ans = dfs(i, j,[])
for c in cur_ans:
cur_ans1 = cal_0(c)
res = max(res,cur_ans1)
return res
力扣
class Solution {
public int maxTrailingZeros(int[][] grid) {
int m = grid.length, n = grid[0].length;
int[][] r2 = new int[m][n]; // r - row
int[][] c2 = new int[m][n]; // c - column
int[][] r5 = new int[m][n];
int[][] c5 = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int num = grid[i][j];
int n2 = getFactorNum(num, 2), n5 = getFactorNum(num, 5);
r2[i][j] = j > 0 ? r2[i][j - 1] + n2 : n2;
c2[i][j] = i > 0 ? c2[i - 1][j] + n2 : n2;
r5[i][j] = j > 0 ? r5[i][j - 1] + n5 : n5;
c5[i][j] = i > 0 ? c5[i - 1][j] + n5 : n5;
}
}
int ans = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 左上
int cnt2 = (j > 0 ? r2[i][j - 1] : 0) + c2[i][j];
int cnt5 = (j > 0 ? r5[i][j - 1] : 0) + c5[i][j];
ans = Math.max(ans, Math.min(cnt2, cnt5));
// 右上
cnt2 = r2[i][n - 1] - r2[i][j] + c2[i][j];
cnt5 = r5[i][n - 1] - r5[i][j] + c5[i][j];
ans = Math.max(ans, Math.min(cnt2, cnt5));
// 左下
cnt2 = r2[i][j] + c2[m - 1][j] - c2[i][j];
cnt5 = r5[i][j] + c5[m - 1][j] - c5[i][j];
ans = Math.max(ans, Math.min(cnt2, cnt5));
// 右下
cnt2 = r2[i][n - 1] - (j > 0 ? r2[i][j - 1] : 0) + c2[m - 1][j] - c2[i][j];
cnt5 = r5[i][n - 1] - (j > 0 ? r5[i][j - 1] : 0) + c5[m - 1][j] - c5[i][j];
ans = Math.max(ans, Math.min(cnt2, cnt5));
}
}
return ans;
}
private int getFactorNum(int n, int factor) {
int cnt = 0;
while (n % factor == 0) {
n /= factor;
cnt++;
}
return cnt;
}
}
作者:inuter
链接:https://leetcode-cn.com/problems/maximum-trailing-zeros-in-a-cornered-path/solution/-by-inuter-q1at/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
304. 二维区域和检索 - 矩阵不可变
一维前缀和
计算每一列的前缀和
class NumMatrix:
def __init__(self, matrix: List[List[int]]):
self.pre_sum_col = [[0 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
#初始化第一行
for j in range(len(matrix[0])):
self.pre_sum_col[0][j] = matrix[0][j]
for i in range(1,len(matrix)):
for j in range(len(matrix[0])):
self.pre_sum_col[i][j] = self.pre_sum_col[i-1][j] + matrix[i][j]
def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
#以列为聚合计算前缀和,一列一列的计算
res = 0
for col in range(col1,col2+1):
if row1 > 0:
res += self.pre_sum_col[row2][col]-self.pre_sum_col[row1-1][col]
else:
res += self.pre_sum_col[row2][col]
return res
二维前缀和
class NumMatrix:
def __init__(self, matrix: List[List[int]]):
self.presum = [[0 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
# 初值
self.presum[0][0] = matrix[0][0]
for i in range(1, len(matrix)):
self.presum[i][0] = self.presum[i - 1][0] + matrix[i][0]
for j in range(1, len(matrix[0])):
self.presum[0][j] = self.presum[0][j - 1] + matrix[0][j]
for i in range(1, len(matrix)):
for j in range(1, len(matrix[0])):
self.presum[i][j] = self.presum[i - 1][j] + self.presum[i][j - 1] - self.presum[i - 1][j - 1] + \
matrix[i][j]
def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
if row1 >= 1 and col1 >= 1:
res = self.presum[row2][col2] - self.presum[row2][col1 - 1] - self.presum[row1 - 1][col2] + \
self.presum[row1 - 1][col1 - 1]
elif row1 >= 1 and col1 == 0:
res = self.presum[row2][col2] - self.presum[row1 - 1][col2]
elif row1 == 0 and col1 >= 1:
res = self.presum[row2][col2] - self.presum[row2][col1 - 1]
else:
res = self.presum[row2][col2]
return res
363. 矩形区域不超过 K 的最大数值和
力扣
class Solution {
public int maxSumSubmatrix(int[][] mat, int k) {
int m = mat.length, n = mat[0].length;
// 预处理前缀和
int[][] sum = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + mat[i - 1][j - 1];
}
}
int ans = Integer.MIN_VALUE;
// 遍历子矩阵的上边界
for (int top = 1; top <= m; top++) {
// 遍历子矩阵的下边界
for (int bot = top; bot <= m; bot++) {
// 使用「有序集合」维护所有遍历到的右边界
TreeSet ts = new TreeSet<>();
ts.add(0);
// 遍历子矩阵的右边界
for (int r = 1; r <= n; r++) {
// 通过前缀和计算 right
int right = sum[bot][r] - sum[top - 1][r];
// 通过二分找 left
Integer left = ts.ceiling(right - k);
if (left != null) {
int cur = right - left;
ans = Math.max(ans, cur);
}
// 将遍历过的 right 加到有序集合
ts.add(right);
}
}
}
return ans;
}
}
作者:AC_OIer
链接:https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/solution/gong-shui-san-xie-you-hua-mei-ju-de-ji-b-dh8s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
你可能感兴趣的:(leetcode,leetcode)