標籤:style blog io ar color os sp for div
17.6 給定一個整數數組,編寫一個函數,找出索引m和n,只要將m和n之間的元素排好序,整個數組就是有序的。注意:n越小越好,也就是說,找出合格最短序列。
解法:
開始解題之前,讓我們先確認一下答案會是什麼樣的。如果要找的是兩個索引,這表明數組中間有一段有待排序,其中數組開頭和末尾部分是排好序的。
現在,我們借用下面的例子來解決此題:
1,2,4,7,10,11,7,12,6,7,16,18,19
首先映入腦海的想法可能是,直接找出位於開頭的最長遞增子序列,以及位於末尾的最長遞增子序列。
左邊:1,2,4,7,10,11
中間:7,12
右邊:6,7,16,18,19
很容易就能找出這些子序列,只需從數組最左邊和最右邊開始,向中間尋找遞增子序列。一旦發現元素大小順序不對,那就是找到了遞增/遞減子序列的兩頭。
但是,為瞭解決這個問題,還需要對數組中間部分進行排序,只要將中間部分排好序,數組所有元素便是有序的。具體來說,就是一下判斷條件必須為真:
//左邊所有元素都要小於中間所有元素
min(middle)>end(left)
//中間所有元素都要小於右邊的所有元素
max(middle)<start(right)
或者,換句話說,對於所有元素:
left<middle<right
實際上,上例的這個條件絕對不可能成立。根據定義,中間部分的元素是無序的。而在上面的例子中,left.end>middle.start且middle.end>right.start一定成立。這樣一來,只排序中間部分並不能讓整個數組有序。
不過,我們還可以縮減左邊和右邊的子序列,直到先前的條件成立為止。
令min等於min(middle),max等於max(middle).
對左邊部分,我們先從這個子序列的末尾開始,並向左移動,直到找到元素索引i使得array[i]<min;找到後只需排序中間部分,就能讓數組的那部分有序。
然後,對右邊部分進行類似操作。
C++實現代碼:
#include<iostream>using namespace std;int findEndOfLeftSubsequence(int array[],int n){ int i; for(i=1;i<n;i++) { if(array[i]<array[i-1]) return i-1; } return n-1;}int findEndOfRightSubsequence(int array[],int n){ int i; for(i=n-2;i>=0;i--) { if(array[i]>array[i+1]) return i+1; } return 0;}int shrinkLeft(int array[],int n,int min_index,int start){ int comp=array[min_index]; cout<<comp<<endl; int i; for(i=start-1;i>=0;i--) { if(comp>=array[i]) return i+1; } return 0;}int shrinkRight(int array[],int n,int max_index,int start){ int comp=array[max_index]; cout<<comp<<endl; for(int i=start;i<n;i++) { if(comp<=array[i]) return i-1; } return n-1;}void findUnsortedSequence(int array[],int n){ int end_left=findEndOfLeftSubsequence(array,n); cout<<end_left<<endl; int start_right=findEndOfRightSubsequence(array,n); cout<<start_right<<endl; int min_index=end_left+1; if(min_index>=n) return; 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; } cout<<array[min_index]<<" "<<array[max_index]<<endl; int right_index=shrinkRight(array,n,max_index,start_right); int left_index=shrinkLeft(array,n,min_index,end_left); cout<<left_index<<" "<<right_index<<endl;}int main(){ int arr[12]={1,2,4,7,10,7,12,6,7,16,18,19}; findUnsortedSequence(arr,12);}
careercup-中等難度 17.6