寻找数组中无序的部分,并返回索引。

本文介绍了一种算法,用于在给定的整数数组中找到一个最短的子序列,通过对该子序列进行排序可以使整个数组变为有序。通过定义两个指针left和right来确定有序数组的边界,并逐步调整这两个指针的位置以确定需要排序的最短区间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    题目:《程序员面试金典 (第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;
}


### 使用最大堆和最小堆寻找无序数组中位数 为了高效地找到无序数组中的中位数及其原始下标,可以采用最大堆和最小堆相结合的方法。这种方法能够在O(log n)时间内完成插入操作,保持数据结构平衡以便随时获取当前的中位数值。 具体实现如下: 1. 创建两个优先队列:一个是大根堆用于存储较小的一半元素;另一个是小根堆用来保存较大的一半元素。 2. 当新加入一个元素时,如果这个值小于等于大根堆顶,则将其放入大根堆;反之则进入小根堆。 3. 维护这两个堆之间的大小关系使得它们要么相等,要么大根堆多出一个小于等于小根堆顶部的那个唯一额外项。 4. 如果总数量为奇数,则中位数就是大根堆顶端元素;如果是偶数的话,那么中位数将是两者顶端元素平均值得到的结果[^1]。 然而上述方法不能直接给出原数组里的索引位置。对于这个问题,可以在向堆里添加元素的同时维护一个哈希表来追踪每个值对应的初始索引。这样,在最终确定中位数后就可以通过查表得到其原本所在的位置了。 另外一种更简单但效率稍低的办法是先复制一份输入列表对其进行排序处理,再依据定义从中选出位于中央处的目标数字,最后回到未排序版本的数据集中定位该目标的具体地址[^2]。 下面是基于Python语言的一个简易示例程序展示如何利用快速排序思想配合映射机制获得所需结果: ```python def find_median_index(arr): import copy # 复制数组以防修改原有数据 sorted_arr = copy.deepcopy(arr) # 对副本执行排序 sorted_arr.sort() length = len(sorted_arr) median_value = (sorted_arr[length // 2] + sorted_arr[(length - 1) // 2]) / 2 index_map = {value: idx for idx, value in enumerate(arr)} try: result_idx = index_map[median_value] except KeyError as e: # 若不存在确切匹配的情况(例如浮点型中位数) lower_bound = min(index_map.keys(), key=lambda k: abs(k-median_value)) result_idx = index_map[lower_bound] return result_idx test_array = [7, 9, 3, 5, 1] print(f"The original array is :{test_array}") result = find_median_index(test_array) print(f"Median element's original position was at index:{result}.") ``` 此代码片段展示了如何创建一个新的已排序序列以识别其中心值,借助字典对象建立从值到原来索引间的对应关系,从而能够返回所求中位数最初所在的下标位置[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值