解决leetcode第3510题移除最小数对使数组有序II
3510.移除最小数对使数组有序II
难度:困难
问题描述:
给你一个数组nums,你可以执行以下操作任意次数:
选择相邻元素对中和最小的一对。如果存在多个这样的对,选择最左边的一个。
用它们的和替换这对元素。
返回将数组变为非递减所需的最小操作次数。
如果一个数组中每个元素都大于或等于它前一个元素(如果存在的话),则称该数组为非递减。
示例1:
输入:nums=[5,2,3,1]
输出:2
解释:
元素对(3,1)的和最小,为4。替换后nums=[5,2,4]。
元素对(2,4)的和为6。替换后nums=[5,6]。
数组nums在两次操作后变为非递减。
示例2:
输入:nums=[1,2,2]
输出:0
解释:
数组nums已经是非递减的。
提示:
1<=nums.length<=105
-109<=nums[i]<=109
问题分析:
这个问题按照题目给定的处理方法处理,其实就可以解决问题。
处理步骤如下
第一是将nums数组中所有相邻元素的和s求出,将相邻元素中第一个元素的索引值i与和s构成一个列表,将所有这种列表组成一个新的列表,然后按和与索引值为关键字排序,找出其中和最小且索引值最小的那一对元素的[i,s]返回。
第二是对找到的那一对元素,用其和s进行替换,生成新的整数列表。
第三是检查新生成的整数列表,判断其是否为非递减的列表,如果是,返回替换的次数,否则重复上面的步骤。
程序如下:
# 检查两个列表是否相等,以方便后面判断一个数组是否已经是有序数组
def check_is_decreasing(a, b):
return True if a == b else False
# 将一个数字列表中相邻元素和求出,并返回和最小的数对索引,如果有多个和最小,则返回最左的那一个,返回格式是[i,s],其中i为数对索引,s为相邻元素的和
def get_min_sum_and_index(a):
b = []
n = len(a)
for i in range(n - 1):
s = a[i] + a[i + 1]
b.append([i, s])
c = sorted(b, key=lambda x: (x[1], x[0]))
return c[0]
# 将相邻元素和最小的两个元素用其和替换,返回替换之后的列表
def replace_min_sum(a):
b = get_min_sum_and_index(a)
print(f'{a}中索引值为{b[0]}的连续两个元素的和{b[1]}最小')
del a[b[0]]
del a[b[0]]
a.insert(b[0], b[1])
print(f'替换最小和之后的数组为{a}')
return a
#主程序
x = eval(input('pls input x='))
#替换次数用c统计
c = 0
n = len(x)
#长度为n的列表,最多替换n-1次
for i in range(n-1):
if check_is_decreasing(x, sorted(x)):
print(f'{x}已经是非递减有序数组')
break
c = c + 1
print(f'第{c}次替换最小和')
x = replace_min_sum(x)
print(f'最少操作次数为:{c}次')
运行实例一
pls input x=[3,4,5]
[3, 4, 5]已经是非递减有序数组
最少操作次数为:0次
运行实例二
pls input x=[3,2,5,1,4]
第1次替换最小和
[3, 2, 5, 1, 4]中索引值为0的连续两个元素的和5最小
替换最小和之后的数组为[5, 5, 1, 4]
第2次替换最小和
[5, 5, 1, 4]中索引值为2的连续两个元素的和5最小
替换最小和之后的数组为[5, 5, 5]
[5, 5, 5]已经是非递减有序数组
最少操作次数为:2次
运行实例三
pls input x=[3,1,5,2,4]
第1次替换最小和
[3, 1, 5, 2, 4]中索引值为0的连续两个元素的和4最小
替换最小和之后的数组为[4, 5, 2, 4]
第2次替换最小和
[4, 5, 2, 4]中索引值为2的连续两个元素的和6最小
替换最小和之后的数组为[4, 5, 6]
[4, 5, 6]已经是非递减有序数组
最少操作次数为:2次
很多问题,其实已经通过题目的描述,把算法说得清楚明白,只要按照其描述,转换成相应的处理程序,就可以解决问题,所以慢慢审题,读懂题目,是一种很重要的能力。