例子:数组 1, 2, 4, 7, 10, 11, 7, 12, 6, 7, 16, 18, 19 只要对下标3到9之间的元素排序,就能使整个数组有序
思路是:
// Left: 1, 2, 4, 7, 10, 11
// Middle: 7, 12
// Right: 6, 7, 16, 18, 19
1 找到左边递增序列的最右(最大)的那个元素 11
2 找到右边递增序列最左(最小)的那个元素 6
3 找到中间序列的最小元素 7
4 找到中间序列的最大元素 12
5 找到左边递增序列中比中间序列最小元素(7)还要小或等于的下标(元素7,下标3)
6 找到右边递增序列中比中间序列最大元素(12)还要大或等于的下标的前一个元素(元素7,下标9)
package Moderate;
/**
* 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).
给定了一个整数数组,写一个方法来找到下标m和n使得如果把m到n之间的数排序,
则整个数组也会被排好序。要使得m到n的区间尽量小
*
*/
public class S17_6 {
// 找到左边递增序列的最右(最大)的那个元素 11
public static int findEndOfLeftSubsequence(int[] array) {
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) { // 不再递增了!
return i - 1;
}
}
return array.length - 1;
}
// 找到右边递增序列最左(最小)的那个元素 6
public static int findStartOfRightSubsequence(int[] array) {
for (int i = array.length - 2; i >= 0; i--) {
if (array[i] > array[i + 1]) { // 不再递减了
return i + 1;
}
}
return 0;
}
// 找到左边递增序列中比中间序列最小元素(7)还要小或等于的下标(元素7,下标3)
public static int shrinkLeft(int[] array, int min_index, int start) {
int comp = array[min_index];
for (int i = start - 1; i >= 0; i--) {
if (array[i] <= comp) {
return i + 1;
}
}
return 0;
}
// 找到右边递增序列中比中间序列最大元素(12)还要大或等于的下标的前一个元素(元素7,下标9)
public static int shrinkRight(int[] array, int max_index, int start) {
int comp = array[max_index];
for (int i = start; i < array.length; i++) {
if (array[i] >= comp) {
return i - 1;
}
}
return array.length - 1;
}
public static void findUnsortedSequence(int[] array) {
// find left subsequence
int end_left = findEndOfLeftSubsequence(array);
// find right subsequence
int start_right = findStartOfRightSubsequence(array);
// find min and max element of middle
int min_index = end_left + 1;
if (min_index >= array.length) {
// System.out.println("The array is already sorted.");
return; // Already sorted
}
int max_index = start_right - 1;
for (int i = end_left; i <= start_right; i++) {
if (array[i] < array[min_index]) {
min_index = i;
}
if (array[i] > array[max_index]) {
max_index = i;
}
}
// slide left until less than array[min_index]
int left_index = shrinkLeft(array, min_index, end_left);
// slide right until greater than array[max_index]
int right_index = shrinkRight(array, max_index, start_right);
if (validate(array, left_index, right_index)) {
System.out.println("TRUE: " + left_index + " " + right_index);
} else {
System.out.println("FALSE: " + left_index + " " + right_index);
}
}
/*
* Validate that sorting between these indices will sort the array. Note
* that this is not a complete validation, as it does not check if these are
* the best possible indices.
*/
public static boolean validate(int[] array, int left_index, int right_index) {
int[] middle = new int[right_index - left_index + 1];
for (int i = left_index; i <= right_index; i++) {
middle[i - left_index] = array[i];
}
java.util.Arrays.sort(middle);
for (int i = left_index; i <= right_index; i++) {
array[i] = middle[i - left_index];
}
for (int i = 1; i < array.length; i++) {
if (array[i - 1] > array[i]) {
return false;
}
}
return true;
}
public static void main(String[] args) {
int[] array = { 1, 2, 4, 7, 10, 11, 7, 12, 6, 7, 16, 18, 19 };
// Left: 1, 2, 4, 7, 10, 11
// Middle: 7, 12
// Right: 6, 7, 16, 18, 19
findUnsortedSequence(array);
}
}