程序员面试金典——解题总结: 9.17中等难题 17.6给定一个整数数组,编写一个函数,找出索引m和n,只要将m和n之间的元素排好序,整个数组就是有序的。注意:n - m越小越好,也就是说,找出

来源:互联网 发布:photogragh是什么软件 编辑:程序博客网 时间:2024/04/27 23:49
#include <iostream>#include <stdio.h>#include <vector>using namespace std;/*问题:给定一个整数数组,编写一个函数,找出索引m和n,只要将m和n之间的元素排好序,整个数组就是有序的。注意:n - m越小越好,也就是说,找出      符合条件的最短序列。分析:我们将数组分成3个部分,A[0... m-1],A[m ... n],A[n+1...A.length-1]      那么必定要符合如下条件:前面数组的最大值要<=中间数组的最小值,中间数组的最大值要<=后面数组的最小值  如果数组已经有序,那么m,n都设置为-1  如果数组无序,可以遍历m和n,需要不断从中间数组中取出最小值和最大值并比较,符合条件就可以  时间复杂度= 不断尝试m和n的时间O(n^2) + 从中间数组选择最小值和最大值的的时间O(n)【可以采用线性时间选择算法,具体的算法我记得好像是数组不断划分为5的等分来做】  而且需要前面数组和后面数组都要有序  输入:9(数组元素个数,接下来一行是n个元素)1 3 5 9 8 7 4 6 13131 2 4 7 10 11 7 12 6 7 16 18 19输出:2(m) 7(n)3 9书上解法:1 从左到右遍历,如果当前元素比后面元素大,记录当前元素位置low【牛逼,确定了左边有序序列】  从右到左遍历,如果当前元素比其前面元素小,记录该元素位置high  中间数组在下标low+1~high-1  寻找中间数组中最小值min,最大值max,  从low位置向前遍历,如果有元素的值 < min,记录其位置pos,则m = pos + 1,  从high位置向后遍历,如果有元素的值 > max,记录位置pos,则n= pos - 1;表明该元素前面部分都是<=max的,这是不符合题目要求的,所以设定n=pos-1  【这个解法是错误的】  例如:1 3 5 9 8 7 4 6 13,  寻找中间数组得到:[1 3 5 9] [8 7] [4 6 13]  对中间数组,确定左边中小于中间数组最小值,确定右边大于中间数组最大值,得:[1 2 5] [9 8 7 4 6] [13]  发现尽管对中间排好序,但是 5 大于 4,仍然不是有序的  如果继续对数组:                           [1 2 5] [9 8 7 4 6] [13]重复上述处理,找到[9 8 7 4 6]中最小值为4,最大值为9, 发现修改左边下标为2,把5包含进来,得到最终 [1 2] [5 9 8 7 4 6] [13]    结束处理的必要条件必须满足:  A[beginIndex - 1] <= min ,并且A[endIndex + 1] >= max2//书上解法错误,这里必须要判断找到的下标是否真的还符合题目要求;如果不符合,需要继续寻找下标int flag = isCanFinish(datas , beginIndex , endIndex);while( 1 !=  flag){//如果左边大于中间数组最小值,左边寻找到的下标减1,并继续判断if( 2 == flag){beginIndex--;flag = isCanFinish(datas , beginIndex , endIndex);}else if( 3 == flag){endIndex++;flag = isCanFinish(datas , beginIndex , endIndex);}}3寻找数组 datas[low ... high]中的最小值和最大值,这里用分治法来做分治法原理:将规模为n的子问题划分为k个规模较小的子问题,子问题独立,对子问题求解,并将答案合并分治法本质是一种特殊地递归,一般可以通过二分法进行处理分治法处理步骤:1)划分 , 2)处理 ,3)归并答案如果low = high,表明只有一个元素,则最大值和最小值都是它否则,令min = datas[low],max=datas[max];        令middle = low + (high - low)/2;得到 result1 = findMinAndMax(datas , low , middle);     result2 = findMinAndMax(datas , middle+1 , high); min = result1.min < result2.min ? result1.min : result2.min; max = result1.max > result2.max ? result1.max : result2.max;*/bool isOrder(vector<int>& datas){if(datas.empty()){return true;}int size = datas.size();for(int i = 1 ; i < size ; i++){if(datas.at(i) < datas.at(i-1)){return false;}}return true;}//寻找左边递增序列的截止位置int findLeftIndex(vector<int>& datas){if(datas.empty()){return -1;}int size = datas.size();int i;for(i = 0 ; i < size - 1 ; i++){if(datas.at(i) > datas.at(i+1)){return i;}}return i;}//寻找右边递增序列的截止位置int findRightIndex(vector<int>& datas){if(datas.empty()){return -1;}int size = datas.size();int i;for(i = size - 1 ; i >= 1 ; i--){if(datas.at(i) < datas.at(i-1)){return i;}}return i;}//寻找大于或小于value的下标int findIndex(vector<int>& datas , int index , int value , bool isFindLeft){//如果是寻找左边数组中,第一个比value小的下标int i;int size = datas.size();if(isFindLeft){for(i = index ; i >= 0 ; i--){if(datas.at(i) <= value){return (i + 1);}}}else{for(i = index ; i < size ; i++ ){if(datas.at(i) >= value){return (i - 1);}}}return -1;}/*寻找数组 datas[low ... high]中的最小值和最大值,这里用分治法来做分治法原理:将规模为n的子问题划分为k个规模较小的子问题,子问题独立,对子问题求解,并将答案合并分治法本质是一种特殊地递归,一般可以通过二分法进行处理分治法处理步骤:1)划分 , 2)处理 ,3)归并答案如果low = high,表明只有一个元素,则最大值和最小值都是它否则,令min = datas[low],max=datas[max];        令middle = low + (high - low)/2;得到 result1 = findMinAndMax(datas , low , middle);     result2 = findMinAndMax(datas , middle+1 , high); min = result1.min < result2.min ? result1.min : result2.min; max = result1.max > result2.max ? result1.max : result2.max;*/pair<int , int> findMinAndMax(vector<int>& datas , int low , int high){int size = datas.size();if(datas.empty() || low > high || high >= size){pair<int, int> result(-1,-1);return result;}//如果只有一个元素if(low == high){pair<int , int> result(datas.at(low) , datas.at(low));return result;}//如果有两个元素,注意是等于号else if( high == low + 1){int min = datas.at(low) < datas.at(high) ? datas.at(low) : datas.at(high);int max = datas.at(low) > datas.at(high) ? datas.at(low) : datas.at(high);pair<int , int> result(min ,max);return result;}//多个元素,二分后递归处理{int realMin = INT_MAX;int realMax = INT_MIN;int middle = low + (high - low) / 2;pair<int , int> result1 = findMinAndMax(datas , low , middle);pair<int , int> result2 = findMinAndMax(datas , middle + 1 , high);//比较realMin = result1.first < result2.first ? result1.first : result2.first;realMax = result1.second > result2.second ? result1.second : result2.second;pair<int , int> result(realMin , realMax);return result;}}//判断当前数组是否可以结束处理,即已经找到正确的下标,返回1:表示可以正确,返回2:表示左边不正确,返回3:表示右边不正确int isCanFinish(vector<int>& datas , int beginIndex , int endIndex){if(datas.empty() || beginIndex < 0 || endIndex >= datas.size() || beginIndex >= endIndex){return 1;}pair<int , int> result = findMinAndMax(datas , beginIndex , endIndex);int min = result.first;int max = result.second;//如果左边大于中间数组最小值if(datas.at(beginIndex - 1) > min ){return 2;}//如果右边小于中间数组最大值else if(datas.at(endIndex + 1) < max){return 3;}else{return 1;}}pair<int, int> getIndexs(vector<int>& datas){pair<int , int> invalidResult(-1 , -1);if(datas.empty()){return invalidResult;}//检查数组是否有序,如果有序,直接返回if(isOrder(datas)){return invalidResult;}int leftIndex = findLeftIndex(datas);int rightIndex = findRightIndex(datas);pair<int , int> result = findMinAndMax(datas , leftIndex + 1 , rightIndex - 1);int min = result.first;int max = result.second;int beginIndex = findIndex(datas , leftIndex , min , true) ;int endIndex = findIndex(datas , rightIndex , max , false);//书上解法错误,这里必须要判断找到的下标是否真的还符合题目要求;如果不符合,需要继续寻找下标int flag = isCanFinish(datas , beginIndex , endIndex);while( 1 !=  flag){//如果左边大于中间数组最小值,左边寻找到的下标减1,并继续判断if( 2 == flag){beginIndex--;flag = isCanFinish(datas , beginIndex , endIndex);}else if( 3 == flag){endIndex++;flag = isCanFinish(datas , beginIndex , endIndex);}}pair<int, int> realResult(beginIndex , endIndex);return realResult;}void process(){int num;vector<int> datas;int value;pair<int, int> result;while(cin >> num){datas.clear();//复用之前容器,数据要清空for(int i = 0 ; i < num ; i++){cin >> value;datas.push_back(value);}result = getIndexs(datas);cout << result.first << " " << result.second << endl;}}int main(int argc , char* argv[]){process();getchar();return 0;}

0 0
原创粉丝点击