[CTCI] 最小调整有序
题目描述
有一个整数数组,请编写一个函数,找出索引m和n,只要将m和n之间的元素排好序,整个数组就是有序的。注意:n-m应该越小越好,也就是说,找出符合条件的最短序列。
给定一个int数组A和数组的大小n,请返回一个二元组,代表所求序列的起点和终点。(原序列位置从0开始标号,若原序列有序,返回[0,0])。保证A中元素均为正整数。
测试样例:
[1,4,6,5,9,10],6
返回:[2,3]
先分别找到左边第一对逆序对与右边第一对逆序对,然后找出两个逆序对之间的最大值与最小值,然后分别向两边扩展边界到最小值与最大值。
1 class Rearrange { 2 public: 3 int findEndOfLeft(vector<int> &A) { 4 for (int i = 0; i < A.size(); ++i) { 5 if (A[i] < A[i-1]) return i - 1; 6 } 7 return A.size() - 1; 8 } 9 int findStartOfRight(vector<int> &A) { 10 for (int i = A.size() - 2; i >= 0; --i) { 11 if (A[i] > A[i+1]) return i + 1; 12 } 13 return 0; 14 } 15 int shrinkLeft(vector<int> &A, int min_idx, int start) { 16 int comp = A[min_idx]; 17 for (int i = start - 1; i >= 0; --i) { 18 if (A[i] <= comp) return i + 1; 19 } 20 return 0; 21 } 22 int shrinkRight(vector<int> &A, int max_idx, int start) { 23 int comp = A[max_idx]; 24 for (int i = start; i < A.size(); ++i) { 25 if (A[i] >= comp) return i - 1; 26 } 27 return A.size() - 1; 28 } 29 vector<int> findSegment(vector<int> A, int n) { 30 // write code here 31 int end_left = findEndOfLeft(A); 32 int start_right = findStartOfRight(A); 33 int min_idx = end_left + 1; 34 if (min_idx >= A.size()) return {0, 0}; 35 int max_idx = start_right - 1; 36 for (int i = end_left; i <= start_right; ++i) { 37 if (A[i] < A[min_idx]) min_idx = i; 38 if (A[i] > A[max_idx]) max_idx = i; 39 } 40 int left_idx = shrinkLeft(A, min_idx, end_left); 41 int right_idx = shrinkRight(A, max_idx, start_right); 42 return {left_idx, right_idx}; 43 } 44 };