leetcode
leetcode 2801 ~ 2850
部分排序

部分排序

难度:

标签:

题目描述

Given an array of integers, write a method to find indices m and n such that if you sorted elements m through n, the entire array would be sorted. Minimize n - m (that is, find the smallest such sequence).

Return [m,n]. If there are no such m and n (e.g. the array is already sorted), return [-1, -1].

Example:

Input:  [1,2,4,7,10,11,7,12,6,7,16,18,19]
Output:  [3,9]

Note:

  • 0 <= len(array) <= 1000000

代码结果

运行时间: 42 ms, 内存: 35.1 MB


/*
 * Problem: Given an integer array, write a function to find the indices m and n such that if you sort the elements from index m to n, the entire array becomes sorted. The function should return [m, n], and if no such m and n exist (i.e., the array is already sorted), return [-1, -1].
 * Example: Input: [1, 2, 4, 7, 10, 11, 7, 12, 6, 7, 16, 18, 19]
 *          Output: [3, 9]
 */
import java.util.*;
import java.util.stream.*;

public class SolutionStream {
    public int[] findUnsortedSubarray(int[] nums) {
        if (nums == null || nums.length <= 1) return new int[]{-1, -1};
        int n = nums.length;

        int[] sorted = Arrays.stream(nums).sorted().toArray();
        int start = IntStream.range(0, n).filter(i -> nums[i] != sorted[i]).findFirst().orElse(-1);
        if (start == -1) return new int[]{-1, -1}; // Array is already sorted
        int end = IntStream.range(0, n).map(i -> n - 1 - i).filter(i -> nums[i] != sorted[i]).findFirst().orElse(-1);

        return new int[]{start, end};
    }
}

解释

方法:

题解采用了一种扫描数组的方式,首先从左到右扫描,记录最大值,如果当前元素小于已记录的最大值,则更新结束位置end。这样可以找到右侧第一个需要排序的位置。然后从右到左扫描,记录最小值,如果当前元素大于已记录的最小值,则更新开始位置start。这样可以找到左侧第一个需要排序的位置。这两次扫描共同确定了最短需要排序的子数组。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在算法中,为什么选择使用连续扫描数组两次(先从左到右再从右到左)的方式来确定m和n的位置?
此算法的目的是找到最小的子数组,当对其进行排序后,整个数组都将是有序的。从左到右扫描时,通过更新最大值并检查当前元素是否小于此最大值,可以确定右边界。如果元素小于最大值,意味着它应该位于更前面的位置。相反,从右到左扫描通过更新最小值,如果当前元素大于此最小值,则意味着它应该位于更后面的位置,从而确定左边界。这两次扫描确保找到的子数组是最短的,使其排序后整个数组变为有序。
🦆
这种方法中,当数组已完全排序时,返回值为`[-1,-1]`的逻辑是如何通过代码实现的?
在代码中,初始设置了`start`和`end`索引为`-1`。在从左到右的扫描中,如果所有元素都是递增的,则`max_val`将逐步更新而不会触发`end`的更新(即不会有任何元素小于`max_val`)。类似地,在从右到左的扫描中,如果所有元素都是递减的,则`min_val`也将逐步更新而不会触发`start`的更新(即不会有任何元素大于`min_val`)。因此,如果数组已经完全排序,`start`和`end`将保持为初始值`-1`,最终返回`[-1, -1]`。
🦆
算法在更新`end`索引时使用了`if array[i] < max_val`条件,请问这里的比较逻辑是基于什么考虑?
此条件用于检查当前元素是否处于正确的位置。在从左到右扫描过程中,`max_val`记录了扫描到当前位置时的最大值。如果某个元素`array[i]`小于`max_val`,这说明`array[i]`位于比它大的元素之后,这是无序的,因此需要对其进行排序。由此,`end`索引会被更新为当前元素的位置,标记这是目前找到的最右侧的无序位置。这个逻辑确保了能够找到需要排序的最小子数组的右边界。

相关问题