笔试练习1分享(弱鸡版)

区间删除

有一个长度为 𝑛的数组 𝑎,要使得数组 𝑎 有序(单调不降)。 选择一段区间 [𝑙,𝑟],(1≤𝑙≤𝑟≤𝑛)[l,r],(1≤l≤r≤n),将数组的这一段删除,其他的部分(如果存在的话)就按顺序拼在一起。

现在想知道有多少种不同的选择区间的方案。

注:空数组也满足有序,即你可以选择 [1,𝑛][1,n] 这个区间。

个人第一版代码(超时)总体时间复杂度:O(n³):

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

    int count = 0;

    // 枚举所有可能的删除区间 [l, r]
    for (int l = 1; l <= n; l++) {
        for (int r = l; r <= n; r++) {
            // 构建删除 [l, r] 后的新数组
            int[] b = new int[n - (r - l + 1)];
            int idx = 0;
            for (int i = 0; i < n; i++) {
                if (i + 1 >= l && i + 1 <= r) continue;
                b[idx++] = a[i];
            }

            // 判断新数组是否单调不降
            boolean ok = true;
            for (int i = 0; i < b.length - 1; i++) {
                if (b[i] > b[i + 1]) {
                    ok = false;
                    break;
                }
            }

            if (ok) count++;
        }
    }

    System.out.println(count);
}

}

枚举区间:O(n²)

每次构造数组并判断有序:O(n)

总体时间复杂度:O(n³)

AI提示办法:解决每次构造需要判断有序。如何优化判断?把判断拿出去,枚举 [𝑙,𝑟]区间O(n²),在外部进行1-l和r-n的有序判断,只要让l与r两端满足升序即可。

import java.util.Scanner;
public class Main {
	static int res=0;
	static int n=0;
	public static void main(String[] args) {
    	Scanner in = new Scanner(System.in);
   	n=in.nextInt();
   int[] arr=new int[n];
   for(int i=0;i<n;i++){
       arr[i]=in.nextInt();
   }
   int start=0;
   while(start<n-1&&arr[start]<arr[start+1]){
       start++;
   }
   int end=n-1;
   while(end>0&&arr[end]<arr[end-1]){
       end++;
   }
    for (int l = 0; l <= start; l++) {
        for (int r = end; r <= n; r++) {//r=Math.max(start+1.end)保证覆盖到start到end之间的非有序
            if (l == 0 || r == n || arr[l - 1] <= arr[r]) {
                res++;
            }
        }
    }
    System.out.println(res);
}

}

依旧超时解决(纯AI,本彩笔改破防了,比较搞笑的是某通AI给的代码只是对最小r找的判断条件和计数修改了一下,把题目喂给它也是过不了的代码,我的代码卡住了AI让AI过不了,男泵):

问题分析

我们需要计算有多少种不同的区间删除方案,使得删除后的数组剩余部分是非递减的。具体来说,我们需要找到所有满足以下条件的区间 [l,r](1≤l≤r≤n):

删除区间 [l,r] 后,剩余部分的数组是非递减的。

关键观察

​​非递减条件​​:剩余部分必须满足 a[1]≤a[2]≤⋯≤a[l−1]≤a[r+1]≤⋯≤a[n]。 ​​预处理​​:

预处理两个数组 p 和 s:

p[i]:从 a[1] 到 a[i] 的最长连续非递减前缀长度。

s[i]:从 a[i] 到 a[n] 的最长连续非递减后缀长度。

​​合法区间的条件​​:

对于区间 [l,r],必须满足:

a[l−1]≤a[r+1](如果 l>1 且 r<n)。

p[l−1]=l−1(即 a[1..l−1] 是非递减的)。

s[r+1]=n−r(即 a[r+1..n] 是非递减的)。

解决步骤

​​预处理 p 和 s 数组​​:

p[i]:如果 a[i]≥a[i−1],则 p[i]=p[i−1]+1;否则 p[i]=1。

s[i]:如果 a[i]≤a[i+1],则 s[i]=s[i+1]+1;否则 s[i]=1。

​​枚举左端点 l​​:

如果 p[l−1]=l−1,说明 a[1..l−1] 不是非递减的,跳过。

否则,二分查找最小的 r 使得 a[l−1]≤a[r+1] 且 s[r+1]=n−r。

​​统计方案数​​: 对于每个合法的 l,所有 r≥找到的最小 r 都是合法的,因此方案数为 n−r+1。

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 + 2]; // 1-based indexing
    for (int i = 1; i <= n; i++) {
        a[i] = scanner.nextInt();
    }
    a[0] = Integer.MIN_VALUE;
    a[n + 1] = Integer.MAX_VALUE;

    int[] p = new int[n + 2]; // p[i]: length of longest non-decreasing prefix ending at i
    int[] s = new int[n + 2]; // s[i]: length of longest non-decreasing suffix starting at i

    p[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (a[i] >= a[i - 1]) {
            p[i] = p[i - 1] + 1;
        } else {
            p[i] = 1;
        }
    }

    s[n] = 1;
    for (int i = n - 1; i >= 1; i--) {
        if (a[i] <= a[i + 1]) {
            s[i] = s[i + 1] + 1;
        } else {
            s[i] = 1;
        }
    }

    long ans = 0;
    for (int l = 1; l <= n; l++) {
        if (p[l - 1] != l - 1) {
            continue; // a[1..l-1] is not non-decreasing
        }
        int low = l, high = n;
        int best = n + 1; // smallest r such that a[l-1] <= a[r+1] and s[r+1] = n - r
        while (low <= high) {
            int mid = (low + high) / 2;
            if (a[l - 1] <= a[mid + 1] && s[mid + 1] == (n - mid)) {
                best = mid;
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        ans += (n - best + 1);
    }
    System.out.println(ans);
}

}

复杂度分析

​​时间复杂度​​:O(nlogn),预处理 p 和 s 数组是 O(n),枚举左端点 l 并二分查找 r 是 O(nlogn)。

​​空间复杂度​​:O(n),用于存储 p 和 s 数组。

#刷题##区间删除#
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务