Минимальное окно для сортировки

Минимальное окно для сортировки


Условие задачи

Дан массив. Найдите длину наименьшего подмассива, сортировка которого приведёт в порядок весь массив.

Пример 1:

1
2
3
Вход: [1, 2, 5, 3, 7, 10, 9, 12]
Выход: 5
Пояснение: достаточно отсортировать [5, 3, 7, 10, 9].

Пример 2:

1
2
3
Вход: [1, 3, 2, 0, -1, 7, 10]
Выход: 5
Пояснение: достаточно отсортировать [1, 3, 2, 0, -1].

Пример 3:

1
2
3
Вход: [1, 2, 3]
Выход: 0
Пояснение: массив уже отсортирован.

Пример 4:

1
2
3
Вход: [3, 2, 1]
Выход: 3
Пояснение: нужно отсортировать весь массив.

Решение

Сначала найдём слева и справа первые нарушения порядка. Они задают начальные границы кандидата на сортировку. Однако просто отсортировать этот участок недостаточно: его минимум может быть меньше элементов слева, а максимум — больше элементов справа.

Алгоритм:

  1. Найти первую неупорядоченную пару слева и первую — справа.
  2. Определить минимум и максимум внутри полученного участка.
  3. Расширять левую границу, пока слева есть элементы больше минимума участка.
  4. Расширять правую границу, пока справа есть элементы меньше максимума участка.

Код

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package main

import "fmt"

func minimumWindowSort(arr []int) int {
	if len(arr) < 2 {
		return 0
	}

	low, high := 0, len(arr)-1
	for low < len(arr)-1 && arr[low] <= arr[low+1] {
		low++
	}
	if low == len(arr)-1 {
		return 0
	}

	for high > 0 && arr[high] >= arr[high-1] {
		high--
	}

	subarrayMin, subarrayMax := arr[low], arr[low]
	for i := low + 1; i <= high; i++ {
		if arr[i] < subarrayMin {
			subarrayMin = arr[i]
		}
		if arr[i] > subarrayMax {
			subarrayMax = arr[i]
		}
	}

	for low > 0 && arr[low-1] > subarrayMin {
		low--
	}
	for high < len(arr)-1 && arr[high+1] < subarrayMax {
		high++
	}

	return high - low + 1
}

func main() {
	fmt.Println(minimumWindowSort([]int{1, 2, 5, 3, 7, 10, 9, 12}))
	fmt.Println(minimumWindowSort([]int{1, 3, 2, 0, -1, 7, 10}))
	fmt.Println(minimumWindowSort([]int{1, 2, 3}))
	fmt.Println(minimumWindowSort([]int{3, 2, 1}))
}

Вывод:

1
2
3
4
5
5
0
3

Временная сложность

Несколько последовательных проходов по массиву занимают \(O(N)\) времени.

Пространственная сложность

Алгоритм использует постоянный объём дополнительной памяти, поэтому пространственная сложность равна \(O(1)\).