4017.数组中的峰值II
难度:困难
问题描述:
给你一个长度为n的整数数组nums和一个二维整数数组queries。
如果满足以下条件,子数组numsi..j被称为峰值子数组:
其长度至少为3。
存在一个下标k使得i<k<j且:
numsk>numsk-1
numsk>numsk+1
你需要处理以下两种类型的查询:
1,li,ri:计算完全包含在numsli..ri中的峰值子数组的数量。
2,indexi,vali:将numsindexi更新为vali。此更新适用于所有后续查询。
返回一个数组answer,其中answeri是按出现顺序排列的第i个类型1查询的答案。
子数组是数组中连续的非空元素序列。
示例1:
输入:nums=1,3,2,4,queries=\[1,0,3,2,1,1,1,0,3]
输出:2,0
解释:
查询1,0,3:
1,3,2:选择k=1。则numsk=3,numsk-1=1,且numsk+1=2。因为3>1且3>2,这是一个峰值子数组。
1,3,2,4:选择k=1。则numsk=3,numsk-1=1,且numsk+1=2。因为3>1且3>2,这是一个峰值子数组。
查询2,1,1:将nums1更新为1。数组变为1,1,2,4。
查询1,0,3:现在没有峰值子数组。
因此,answer=2,0。
示例2:
输入:nums=9,8,9,8,queries=\[1,1,3,2,2,1,1,0,2]
输出:1,0
解释:
查询1,1,3:
nums1..3=8,9,8:选择k=2。则numsk=9,numsk-1=8,且numsk+1=8。因为9>8且9>8,这是一个峰值子数组。
查询2,2,1:将nums2更新为1。数组变为9,8,1,8。
查询1,0,2:没有峰值子数组。
因此,answer=1,0。
示例3:
输入:nums=3,6,2,7,1,queries=\[1,1,3,2,3,0,1,0,4]
输出:0,3
解释:
查询1,1,3:唯一长度至少为3的子数组是6,2,7。其唯一可能的峰值下标是k=2,但nums2=2小于nums1=6和nums3=7,因此它不是一个峰值子数组。
查询2,3,0:将nums3更新为0。数组变为3,6,2,0,1。
查询1,0,4:
3,6,2:选择k=1。则numsk=6,numsk-1=3,且numsk+1=2。因为6>3且6>2,这是一个峰值子数组。
3,6,2,0:选择k=1。则numsk=6,numsk-1=3,且numsk+1=2。因为6>3且6>2,这是一个峰值子数组。
3,6,2,0,1:选择k=1。则numsk=6,numsk-1=3,且numsk+1=2。因为6>3且6>2,这是一个峰值子数组。
因此,answer=0,3。
提示:
3<=n==nums.length<=10**5
0<=numsi<=10**5
1<=queries.length<=10**5
queriesi=1,li,ri或queriesi=2,indexi,vali
0<=li<ri<=n-1
0<=indexi<=n-1
0<=vali<=10**5
分析问题:
解决下面几个小问题,这道题也就迎刃而解了。
一是对于一个数组,先找出其中有多少个峰值,把索引号0和峰值对应的索引号以及最后一个元素的索引号n-1以列表的形式返回,如果中间没有峰值,则返回空列表,函数get_list_of_peak_index(nums1)实现这一功能;
二是对于只有一个峰值的数组nums2,k=start,peak,end,描述了一个查询,如何把这个查询中的不同峰值子数组数量统计出来呢?函数get_numbers_of_peak_sub_array(k,nums2)实现这一功能,最后返回统计出来的峰值子数组数量t和不同的子数组列表temp;
三是处理第一种查询1,li,ri,先根据查询,取出对应的子数组,然后查出子数组中的峰值列表,把这个峰值对应的索引号列表比如0,i1,i2,i3,......,in,n-1,分解成多个小部分,0,i1,i2、i1,i2,i3、i2,i3,i4、......,每一个部分只有一个峰值,然后调用函数get_numbers_of_peak_sub_array(k,nums2)依次统计每个小部分中峰值子数组的数量,最后将所有峰值子数组数量加起来,就是这个查询对应的峰值子数组的总数量,返回总数量和对应的峰值子数组列表temp;
四是处理第二种查询2,indexi,vali],函数get_changed_nums(query2,nums)实现了这一功能,返回新的nums;
主程序根据查询序列queries,依次取出查询,调用相应的查询处理函数,输出每次查询结果,问题得到解决。
程序如下:
python
#统计一个数组nums中峰值子数组的峰值索引号列表t并返回
def get_list_of_peak_index(nums1):
t=[0]
n=len(nums1)
for i in range(n-1):
if nums1[i] > nums1[i - 1] and nums1[i] > nums1[i + 1]:
t.append(i)
t.append(n-1)
if len(t)<3:
return []
else:
return t
# 统计一个最大的峰值数组nums中峰值子数组的数量并返回
def get_numbers_of_peak_sub_array(k,nums2):
n=len(nums2)
start=k[0]
peak=k[1]
end=k[2]
t=(peak-start)*(end-peak-1)
temp=[]
for i in range(start,peak):
for j in range(peak+1,end):
sub_array=nums2[i:j+1]
temp.append(sub_array)
return t,temp
#对查询[2,indexi,vali]的处理,返回处理之后的nums
def get_changed_nums(query2,nums):
nums[query2[1]]=query2[2]
return nums
#对查询[1,li,ri]的处理,返回处理之后得到的完全包含其中的峰值子数组数量
def get_numbers_of_peak_subarray_by_query(query1,nums3):
nums4=nums3[query1[1]:query1[2]+1]
t = get_list_of_peak_index(nums4)
if not t:
return 0,[]
else:
n = 0
r = len(t)
temp=[]
for i in range(r - 2):
a = t[i]
b = t[i + 1]
c = t[i + 2] + 1
k = [a, b, c]
m, e = get_numbers_of_peak_sub_array(k, nums4)
temp.extend(e)
n += m
return n,temp
#主程序
nums=eval(input('pls input nums='))
queries= eval(input('pls input queries='))
t=[]
for query in queries:
if query[0]==1:
n,a=get_numbers_of_peak_subarray_by_query(query,nums)
s='有以下峰值子数组:' if n!=0 else '没有峰值子数组'
print(f'对于查询{query},{s}')
if a:
print(a)
t.append(n)
else:
k=nums[::]
nums=get_changed_nums(query,nums)
print(f'对于查询{query},使得原数组{k}变为{nums}')
print('answer =',t)
运行实例一
pls input nums=1,3,2,4
pls input queries=\[1,0,3,2,1,1,1,0,3]
对于查询1, 0, 3,有以下峰值子数组:
\[1, 3, 2\], \[1, 3, 2, 4\]
对于查询2, 1, 1,使得原数组1, 3, 2, 4变为1, 1, 2, 4
对于查询1, 0, 3,没有峰值子数组
answer = 2, 0
运行实例二
pls input nums=9,7,9,7,9,2
pls input queries=\[1,0,3,2,1,10,1,0,5]
对于查询1, 0, 3,有以下峰值子数组:
\[9, 7, 9, 7\], \[7, 9, 7\]
对于查询2, 1, 10,使得原数组9, 7, 9, 7, 9, 2变为9, 10, 9, 7, 9, 2
对于查询1, 0, 5,有以下峰值子数组:
\[9, 10, 9\], \[9, 10, 9, 7\], \[9, 10, 9, 7, 9\], \[10, 9, 7, 9, 2\], \[9, 7, 9, 2\], \[7, 9, 2\]
answer = 2, 6
运行实例三
pls input nums=3,6,2,7,1
pls input queries=\[1,1,3,2,3,0,1,0,4]
对于查询1, 1, 3,没有峰值子数组
对于查询2, 3, 0,使得原数组3, 6, 2, 7, 1变为3, 6, 2, 0, 1
对于查询1, 0, 4,有以下峰值子数组:
\[3, 6, 2\], \[3, 6, 2, 0\], \[3, 6, 2, 0, 1\]
answer = 0, 3