【LeetCode 每日一题】3507. 移除最小数对使数组有序 I

Problem: 3507. 移除最小数对使数组有序 I

文章目录

  • 整体思路
      • [1. 核心问题与功能](#1. 核心问题与功能)
      • [2. 算法逻辑](#2. 算法逻辑)
  • 完整代码
  • 时空复杂度
      • [1. 时间复杂度: O ( N 2 ) O(N^2) O(N2)](#1. 时间复杂度: O ( N 2 ) O(N^2) O(N2))
      • [2. 空间复杂度: O ( N ) O(N) O(N)](#2. 空间复杂度: O ( N ) O(N) O(N))

整体思路

1. 核心问题与功能

代码试图解决的问题是:给定一个整数数组 nums,通过不断的"合并相邻对 "操作,使得数组最终变为非递减(升序或相等)序列。

  • 操作定义 :找到数组中和最小的一对相邻元素,将它们合并(即用它们的和替换这两个元素)。
  • 目标 :求最少需要进行多少次合并操作(每次合并计为一次移除,虽然代码命名是 removal,实际是减少了数组长度)。

2. 算法逻辑

这是一个贪心 + 模拟的过程:

  1. 数据转换 :首先将输入的 int[] 数组转换为 ArrayList,以便于动态删除和修改元素。
  2. 主循环 :只要当前数组不是 非递减的(即存在 arr[i] > arr[i+1]),就继续执行合并操作。
  3. 贪心策略
    • 在每一轮中,遍历当前数组,寻找所有相邻对 (arr[i], arr[i+1])
    • 找出这些相邻对中和最小的那一对。如果有多对和相同,取最靠左的一对(代码逻辑如此)。
    • 合并:将这两个数合并为一个数(它们的和)。具体做法是修改左边位置的值,并移除右边位置的元素。
    • 计数器 ans 加 1。
  4. 终止:当数组满足非递减条件时退出循环,返回合并次数。

完整代码

java 复制代码
import java.util.ArrayList;
import java.util.List;

class Solution {
    public int minimumPairRemoval(int[] nums) {
        // 1. 将数组转换为 ArrayList 以支持动态修改
        List<Integer> arr = new ArrayList<>();
        for (int num : nums) {
            arr.add(num);
        }

        int ans = 0; // 记录合并(移除)操作的次数
        
        // 2. 主循环:只要数组还不是非递减的,就继续合并
        // isNonDecreasing 检查是否 arr[i] <= arr[i+1] 对所有 i 成立
        while (!isNonDecreasing(arr)) {
            
            // 3. 寻找相邻和最小的一对元素
            int minPairLoc = 0; // 记录最小和对的起始索引
            
            // 初始化最小和为前两个元素的和(注意:循环前应确保 size >= 2)
            // 如果 isNonDecreasing 返回 false,说明至少有逆序对,size 必然 >= 2
            int sum = arr.get(0) + arr.get(1);
            
            // 遍历数组,寻找更小的相邻和
            for (int i = 1; i < arr.size() - 1; i++) {
                int temp = arr.get(i) + arr.get(i + 1);
                // 贪心选择:找到更小的和,更新索引和最小值
                if (sum > temp) {
                    sum = temp;
                    minPairLoc = i;
                }
            }
            
            // 4. 执行合并操作
            // 将左边元素 (minPairLoc) 更新为两数之和
            arr.set(minPairLoc, sum);
            // 移除右边元素 (minPairLoc + 1)
            arr.remove(minPairLoc + 1);
            
            // 记录操作次数
            ans++;
        }
        return ans;
    }

    // 辅助方法:检查数组是否为非递减序列
    private boolean isNonDecreasing(List<Integer> arr) {
        for (int i = 0; i < arr.size() - 1; i++) {
            if (arr.get(i) > arr.get(i + 1)) {
                return false; // 发现逆序,返回 false
            }
        }
        return true; // 所有元素都有序
    }
}

时空复杂度

假设数组初始长度为 N N N。最坏情况下,数组可能需要合并成只剩 1 个元素(例如输入是完全逆序且数值递减剧烈),即执行 N − 1 N-1 N−1 次操作。

1. 时间复杂度: O ( N 2 ) O(N^2) O(N2)

  • 外层 while 循环 :最坏情况下执行 O ( N ) O(N) O(N) 次(每次数组长度减 1)。
  • 循环内部操作
    • isNonDecreasing:遍历当前数组,耗时 O ( K ) O(K) O(K),其中 K K K 是当前长度。
    • 寻找最小对 :遍历当前数组,耗时 O ( K ) O(K) O(K)。
    • ArrayList.remove :这是主要开销。移除元素会导致后续元素前移,耗时 O ( K ) O(K) O(K)。
  • 综合 :第 1 轮长度 N N N,第 2 轮长度 N − 1 N-1 N−1 ...
    • 总复杂度 ≈ ∑ k = N 2 ( k + k + k ) ≈ O ( N 2 ) \approx \sum_{k=N}^{2} (k + k + k) \approx O(N^2) ≈∑k=N2(k+k+k)≈O(N2)。
    • 因此,最坏时间复杂度是 O ( N 2 ) O(N^2) O(N2)。

2. 空间复杂度: O ( N ) O(N) O(N)

  • 计算依据
    • 创建了一个 ArrayList 存储 N N N 个元素。
  • 结论 : O ( N ) O(N) O(N)。
相关推荐
LYS_06182 小时前
RM赛事C型板九轴IMU解算(3)(姿态融合算法)
c语言·算法·imu·姿态解算·四元数到欧拉角
LDG_AGI2 小时前
【机器学习】深度学习推荐系统(三十一):X For You Feed 全新推荐系统技术架构深度解析
人工智能·深度学习·算法·机器学习·架构·推荐算法
tobias.b2 小时前
408真题解析-2010-5-数据结构-树的结点数量计算
数据结构·算法·408真题解析
chilavert3182 小时前
技术演进中的开发沉思-329 JVM:垃圾回收(中)
java·jvm·算法
啊阿狸不会拉杆2 小时前
《机器学习》 第 9 章 - 深度强化学习
人工智能·算法·机器学习·计算机视觉·ai·ml
仰泳的熊猫2 小时前
题目 1429: 蓝桥杯2014年第五届真题-兰顿蚂蚁
数据结构·c++·算法·蓝桥杯
苦藤新鸡2 小时前
35.LRU缓存(最久未访问)问题
算法·链表·缓存
Yupureki2 小时前
《算法竞赛从入门到国奖》算法基础:入门篇-分治
c语言·开发语言·数据结构·c++·算法·贪心算法
充值修改昵称3 小时前
数据结构基础:B*树B+树的极致优化
数据结构·b树·python·算法