AI刷题之小U的无趣数组 | 豆包MarsCode AI刷题

88 阅读4分钟

“小U的无趣数组”题目要求

一、问题描述

小U有一个长度为 n 的数组。如果数组中存在长度为 3 的子数组,满足 a_i <= a_{i+1} <= a_{i+2},则这个数组被称为“有趣的”。小U可以通过修改数组中的某个元素来打破这种“有趣”的性质。她想知道,最少需要进行多少次操作才能使数组变得不再有趣。

二、测试样例

样例1:

输入:n = 5, a = [6, 2, 4, 5, 1]
输出:1

样例2:

输入:n = 6, a = [1, 2, 3, 4, 5, 6]
输出:2

样例3:

输入:n = 4, a = [5, 3, 1, 7]
输出:0


三、题目解析

3.1代码思路

  1. 遍历数组:我们需要遍历数组,检查每个长度为3的子数组是否满足 a_i <= a_{i+1} <= a_{i+2}
  2. 记录需要修改的元素:对于每个满足条件的子数组,我们需要记录需要修改的元素。
  3. 计算最少修改次数:我们需要计算最少需要修改多少个元素才能打破所有“有趣”的子数组。

3.2详细代码

public class Main {
    public static int solution(int n, int[] a) {
        // 初始化一个变量来记录最少需要修改的次数
        int minOperations = 0;

        // 遍历数组,检查每个长度为3的子数组
        for (int i = 0; i < n - 2; i++) {
            // 检查当前子数组是否满足 a_i <= a_{i+1} <= a_{i+2}
            if (a[i] <= a[i + 1] && a[i + 1] <= a[i + 2]) {
                // 如果满足条件,我们需要记录需要修改的元素
                // 这里你可以选择修改 a[i], a[i+1], 或 a[i+2] 中的一个
                // 选择修改哪个元素取决于后续的子数组情况
                // 这里我们简单地增加修改次数
                minOperations++;

                // 为了避免重复计算,我们可以选择修改 a[i+1]a[i+2]
                // 这里我们选择修改 a[i+1],使其不再满足条件
                a[i + 1] = Math.max(a[i], a[i + 2]) + 1;
            }
        }

        return minOperations;
    }

    public static void main(String[] args) {
        System.out.println(solution(5, new int[]{6, 2, 4, 5, 1}) == 1);
        System.out.println(solution(6, new int[]{1, 2, 3, 4, 5, 6}) == 2);
        System.out.println(solution(4, new int[]{5, 3, 1, 7}) == 0);
    }
}

四、知识总结

在编程中,数组是最常用的数据结构之一,而基于数组的子数组问题也非常常见。这类问题通常包括寻找子数组的某种特性、优化子数组、或调整其内容以满足特定约束。以下是一些解决这类问题的关键技巧和思路总结:

1. 明确问题的核心条件

解决数组相关问题的第一步是准确理解问题中对子数组的要求。例如:

  • 递增/递减约束:如子数组元素需满足递增或递减规则。
  • 值范围限制:如元素不能超过某个范围。
  • 长度或形状要求:如子数组固定长度或满足特定模式。

在本案例中,要求破坏所有满足递增条件 ai≤ai+1≤ai+2的子数组,这是问题的核心。

2. 滑动窗口与区间操作

滑动窗口是一种常用技巧,用于高效处理数组的连续子区间问题:

  • 滑动窗口的基本逻辑

    • 从左到右遍历数组。
    • 维护一个窗口,随着右边界移动动态更新窗口的性质。
  • 适用场景:计算子数组的和、最大值、最小值,或者验证某种条件。

对于子数组问题,如果需要检查固定长度的子数组(如长度为 3 的子数组),可以直接在遍历时进行区间判断,避免重复检查。

3. 优化操作次数

在需要修改数组的问题中,尽量减少修改次数是常见要求。以下是一些优化修改的方法:

  • 局部最优解:每次修改选择当前问题的最佳解,不影响后续操作。例如在本问题中,修改中间元素 a[i+1] 比修改两端元素对后续影响更小。
  • 动态规划:对于复杂问题,可以使用动态规划记录局部修改的最优值,从而构造全局解。
  • 贪心算法:直接在每一步中做出局部最优选择,适用于不需要全局回溯的问题。

五、性能分析

1. 时间复杂度

由于只需遍历一次数组并进行局部修改,时间复杂度为 O(n)。

2. 空间复杂度

代码不使用额外空间,空间复杂度为 O(1)。