题目:《程序员面试金典 (第5版)》P314
给定一个整数数组,编写一个程序,找出索引m 和 n,只要将 m 和 n 之间的元素排好序,整个数组就是有序的。注意:n-m 越小越好,即找出符合条件的最短序列。
提示:假设数组有序部分按照从小到大的方式排列。比如输入int a[]={1,2,4,7,10,11,7,12,6,7,16,18,19},返回m=3,n=9. 输入 int b[]={1,5,7,8,0,3,1,5,8,19},返回m=0,n=7.
//计算数组下标从start到end中最小的数
int minArray(int *a,int start,int end)
{
int res=a[start];
for(int i=start+1;i<=end;i++)
{
if(a[i]<res)
res=a[i];
}
return res;
}
//计算数组下标从start到end中最大的数
int maxArray(int *a,int start,int end)
{
int res=a[start];
for(int i=start+1;i<=end;i++)
{
if(a[i]>res)
res=a[i];
}
return res;
}
//返回false表示不存在索引m和n可以满足题目要求
//返回false时,给m和n赋值-1
bool FindIndex(int a[],int len,int &m,int &n)
{
if(a==nullptr || len<=1)
{
m=-1;
n=-1;
return false;
}
if(len==2)
{
if(a[0]<=a[1])//整个数组有序
{
m=-1;
n=-1;
return false;
}
else//整个数组无序
{
m=0;
n=1;
return true;
}
}
//len>=3时,初始化left和right
//left为有序数组的结尾,right为有序数组的开始。这点很重要。
int left=0,right=len-1;
while(left<=len-2)
{
if(a[left]>a[left+1])
break;
left++;
}
while(right>=1)
{
if(a[right]<a[right-1])
break;
right--;
}
if(left>=right)//整个数组有序
{
m=-1;
n=-1;
return false;
}
//left+1==right是一种特殊情况
if(left+1==right)
{
if(left>=1)
left--;
if(right<=len-2)
right++;
}
//判断还能不能左右移动
bool lmove=true,rmove=true;
if(left==0)
{
lmove=false;
}
if(right==len-1)
{
rmove=false;
}
int l_max,r_min,m_max,m_min;
do{
if(left>=0)
l_max=a[left];
else
l_max=0x80000000;//int最小值
if(right<=len-1)
r_min=a[right];
else
r_min=0x7fffffff;//int最大值
m_max=maxArray(a,left+1,right-1);
m_min=minArray(a,left+1,right-1);
if(m_min>=l_max && m_max<=r_min)
break;
//正确:m_min>=l_max
if(m_min<l_max)
{
int tmp=left-1;
while(tmp>=0)
{
if(m_min>=a[tmp])
{
left=tmp;
break;
}
else
tmp--;
}
if(tmp<0)
{
left=-1;
lmove=false;
}
}
//正确:m_max<=r_min
if(m_max>r_min)
{
int tmp=right+1;
while(tmp<=len-1)
{
if(m_max<=a[tmp])
{
right=tmp;
break;
}
else
tmp++;
}
if(tmp>len-1)
{
right=len;
rmove=false;
}
}
}while( lmove || rmove );
if(left==-1 && right==len)//整个数组无序
{
m=0;
n=len-1;
return true;
}
m=left+1;
n=right-1;
return true;
}