用C++实现两个元素相同但顺序不同的等长数组的正确匹配

7 篇文章 0 订阅

《程序员面试宝典》第五版第96页题目如下:

有两等长数组A,B,所含元素相同,但顺序不同,只能取得A数组某值和B数组某值进行比较,比较结果为大于,小于,等于,但是不能取得同一数组A或者B中两个数进行比较,也不能取得某数组中的某个值。写一个算法实现正确匹配(即A数组中某值与B数组中某值等值)。

最简单的方法:
循环加判断,复杂度O(n^2)
代码如下:

#include <iostream>
 
using namespace std;
 
void matching(int a[],int b[],int k)
{
int i = 0;
while(i <= k)
{
int j = 0;
while(j <= k)
{
if(a[i] == b[j])
{
cout << "(" << i <<"," << j <<")	";
break;
}
j++;
}
i++;
}
cout << endl;
}
 
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int b[10] = {10,6,4,5,1,8,7,9,3,2};
int k = sizeof(a)/sizeof(int);
matching(a,b,k);	
return 0;
}

一种优化方法:
利用二分法的思想,先取A0,与B0Bn-1比较,比较结果计入一个结构数组C,结构为:{某数在B中的位置,标记,某数在A中的位置}。其中“标记”可为:大于,小于,等于。“某数在A/B中的位置”:0n-1,为相应位置。注:第一次比较后,C中元素都为{某数在B中的位置,标记,A0}格式。
取A1,由C可知B中与A0大小相同的数,与其比较。若A2大,则与B中比A0大的值比较。将比较结果替换计入结构数组C。若A2小亦同理。
执行至完毕。
代码如下:

#define N 10

typedef struct {
	int loc_b;
	int flag;//-1,0,1分别表示b[loc_b]<,=,>a[loc_a]
	int loc_a;
}C;

C c[N];
int a[N];
int b[N];
//利用快排的思想和二分查找的思想对数组进行比较。利用a[0]初始化数组c,其中数组前半部分表示b[j]<a[0],后面部分表示b[j]>a[0].同时记录k,使得b[k]==a[0],以后对a数组进行比较时均与b[k]进行比较,(因为不让同数组之间进行比较).

void _match() {
	int head = 0;
	int tail = N - 1;
	int i, j, k;
	i = rand() % N;
	//初始化赋值
	for (j = 0;j<N;j++) {//类似与按照a[i]的值对b进行快排

		if (b[j]>a[i]) {//从后向前插入到c
			c[tail].flag = 1;
			c[tail].loc_a = i;
			c[tail].loc_b = j;
			tail--;
			continue;
		}
		if (b[j]<a[i]) {//从前向后插入到c
			c[head].flag = -1;
			c[head].loc_a = i;
			c[head].loc_b = j;
			head++;
			continue;
		}
		if (b[j] == a[i]) {
			k = j;//记录相等时候的位置
		}
	}
	c[head].flag = 0;
	c[head].loc_a = i;
	c[head].loc_b = k;
	//endfor
	for (i = 0;i<N;i++) {
		if (a[i]<b[k]) {//a[i]小于b[k]时候,从c的前面进行比较
			for (j = 0;j<head;j++) {
				if (b[c[j].loc_b] == a[i]) {
					c[j].flag = 0;
					c[j].loc_a = i;
					break;
				}
			}
		}
		else if (a[i]>b[k]) {//从c的后面比较
			for (j = head + 1;j<N;j++) {
				if (b[c[j].loc_b] == a[i]) {
					c[j].flag = 0;
					c[j].loc_a = i;
					break;
				}
			}
		}

	}
}


int main() {
	int i = 0;
	for (i = 0;i<N;i++) {
		a[i] = i;
		b[i] = N - i - 1;
	}
	for (i = 0;i<sizeof(a) / sizeof(a[0]);i++)
		printf("%d  ", a[i]);
	printf("\n");
	for (i = 0;i<sizeof(b) / sizeof(b[0]);i++)
		printf("%d  ", b[i]);
	printf("\n");
	_match();
	for (i = 0;i<N;i++) {
		cout << "b[" << c[i].loc_b << "] match a[" << c[i].loc_a << "]" << endl;
	}
	system("pause");
	return 0;
}

进一步优化:
利用快速排序和二分法的思想。
1)在A数组中随机选取一个数,(根据题意,我们并不知道这个值的确定值是多少)比如说 A[i] ,然后和B 数组中进行比较,根据你的数据结构,将B数组每个数与A[i]进行比较,若比 A[i] 大的按照从后向前存储,比 A[i] 小的从前向后存储,要是等于A[i] ,就记录下来 这个值在B的位置 j,继续比较,直到B中数组全部比较完成,然后再把这个相等的b[j] 插入空余的那个中间位置上。
2) 然后再从A 数组中取出数A[k]{k=0~n}与B[j](这个B[j] 就是A [i],因为同一数组中不能比较大小,只能采用这种方式)比较,若比B[j]大,那么从结构C中 A[i] 后面的比较,若比B[j]小,就从结构C中 A[i] 前面的比较,直到找到相等,然后更新结构数组C 中与这个相等相应值。(注意,在这里,只更新相等的那个数值的 “标记”,“某数在A中的位置”,其它与A[k]不相同,或大,或小的情况下,不更新,即还保持A[i] 的比较结果,以利于继续比较)
3)重复步骤 2,继续取A数组 剩下的值,仍然与那个 B[j]比较,这样逐步更新结构数组C ,直到A数组全部取出比较完,那么这个程序也就完成了相应的功能。
随机选择A[i],要是选择好,可以大大降低比较次数。

参考:《程序员面试宝典》
https://blog.csdn.net/mba16c35/article/details/42172653

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值