算法:定义一个数组的的陡峭值为:相邻两个元素之差的绝对值之和。

定义一个数组的的陡峭值为:相邻两个元素之差的绝对值之和。现在小红拿到了一个数组,她有多次询问,每次查询一段连续子数组的陡峭值。你能帮帮她吗?
连续子数组为从原数组中,连续的选择一段元素(可以全选、可以不选)得到的新数组。
输入描述
第一行输入一个正整数n,代表数组长度。
第二行输入n个正整数ai,代表小红拿到的数组。
第三行输入一个正整数q,代表询问次数。
接下来的q行,每行输入两个正整数l,r代表一次询问.
1 ≤ n,q≤ 10^5,1 ≤ ai ≤ 10^9
1≤l≤r≤n
输出描述
输出q行,每行输出一个正整数,代表查询的结果
以上是一道算法题,请使用java代码实现,标准输入输出

以下是使用 Scanner 输入的 Java 代码实现:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();
        }
        
        // 计算差值数组d
        int[] d = new int[n - 1];
        for (int i = 0; i < n - 1; i++) {
            d[i] = Math.abs(a[i + 1] - a[i]);
        }
        
        // 计算前缀和数组sum
        int[] sum = new int[n];
        for (int i = 1; i < n; i++) {
            sum[i] = sum[i - 1] + d[i - 1];
        }
        
        // 处理查询
        int q = scanner.nextInt();
        for (int i = 0; i < q; i++) {
            int l = scanner.nextInt();
            int r = scanner.nextInt();
            if (l == r) {
                System.out.println(0);
            } else {
                // 转换为0-based索引
                System.out.println(sum[r - 1] - sum[l - 1]);
            }
        }
        scanner.close();
    }
}

修改说明:

  1. 输入方式替换
    BufferedReader 替换为 Scanner,通过 scanner.nextInt() 直接读取整数。

  2. 数组读取
    使用循环逐个读取数组元素,避免 split 的字符串处理。

  3. 查询处理
    直接通过 scanner.nextInt() 读取 lr,无需额外处理字符串分割。


代码逻辑保持不变:

  1. 预处理差值数组:计算相邻元素的绝对差值。
  2. 前缀和数组:通过前缀和快速计算任意区间的陡峭值。
  3. 查询优化:每个查询的时间复杂度为 O(1),总时间复杂度为 O(n + q)。

输入输出示例:

输入

3
1 3 5
2
1 2
1 3

输出

2
4

解释:

  • 区间 [1,2] 的差值为 |3-1|=2
  • 区间 [1,3] 的差值为 |3-1| + |5-3| = 2 + 2 = 4

优化复杂度(建议将int全部换成long避免数据溢出)

以下是优化后的代码,通过减少数组的使用和避免溢出,同时保持内存效率:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();
        }

        // 直接计算前缀和,省去差值数组d
        long[] sum = new long[n]; // 使用long防止溢出
        for (int i = 1; i < n; i++) {
            sum[i] = sum[i - 1] + Math.abs(a[i] - a[i - 1]);
        }

        int q = scanner.nextInt();
        for (int i = 0; i < q; i++) {
            int l = scanner.nextInt();
            int r = scanner.nextInt();
            if (l == r) {
                System.out.println(0);
            } else {
                // 转换为0-based索引
                System.out.println(sum[r - 1] - sum[l - 1]);
            }
        }
        scanner.close();
    }
}

优化说明:

  1. 省去差值数组 d

    • 直接在计算前缀和数组 sum 时,边计算差值边累加,不再需要单独的 d 数组,节省了 O(n) 的空间。
  2. 使用 long 类型的前缀和数组

    • 原差值可能达到 2e9,当 n=1e5 时,总和可能超过 int 的范围(最大值为 2^31-1≈2e9),因此必须使用 long 类型以避免溢出。
  3. 内存优化效果

    • 原方案需要存储 dint[n-1])和 sumint[n]),总空间为 4n(以字节计算)。
    • 新方案仅用 long[n]sum,空间为 8n,但通过省去 d 数组,总内存与原方案相近,同时避免了溢出问题。

复杂度分析:

  • 时间复杂度:预处理为 O(n),每个查询为 O(1),总时间复杂度仍为 O(n + q)
  • 空间复杂度O(n),仅需存储原始数组 a 和前缀和数组 sum

输入输出示例:

输入

3
1 3 5
2
1 2
1 3

输出

2
4

关键点总结:

  • 避免溢出:差值总和可能超过 int 的范围,必须使用 long
  • 减少数组:直接计算前缀和,无需额外存储差值数组,节省内存。
  • 高效查询:通过前缀和实现 O(1) 时间的区间查询。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海青橘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值