左神小和问题逆序对问题面试

归并排序的扩展问题

——先了解数据结构之归并排序,更容易理解以下的问题。

  • 小和问题和逆序对问题。
    在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。在一个数组中,左边的数如果比右边的数大,则这两个数构成一个逆序对。(据说,小和问题面试必考)
  1. 小和问题可以反向思维,从左往右找比这个数大的数有几个。

  2. 用归并的方法。

  3. 逆序对问题与小和问题时相同的。只需要将相加改成打印逆序对。

    例如,该数组为 a[6]={1,3,4,2,5,4};

    如下给出完整的计算小和的示意过程:
    在这里插入图片描述
    (1)在(1~1)范围上比较
    在这里插入图片描述
    (2)在(2~2)范围上比较
    在这里插入图片描述
    (3)在(4~4)范围上比较
    在这里插入图片描述
    (4)在(5~5)范围上比较
    在这里插入图片描述
    (5)在(3~5)范围上比较
    在这里插入图片描述
    将所有荧光笔标记的数值相加即最终的答案。

如下是计算小和的完整代码:(与归并排序只有两行不同)

#include <iostream>

int merge(int a[], int l, int m, int r)
{
	int *help = new int[6];
	int i = 0;
	int p1 = l;
	int p2 = m + 1;
	int res = 0;
	while (p1 <= m && p2 <= r)
	{
		//小和问题的条件 左边的数小于右边的数
		res += a[p1] < a[p2] ? (a[p1] * (r - p2 + 1)) : 0;
		//当左边严格小于右边时,才将左边的数字拷贝到help[]
		//不能是小于等于,因为这样才不会少统计   
		help[i++] = a[p1] < a[p2] ? a[p1++] : a[p2++];
	}
	while (p1 <= m)
	{
		help[i++] = a[p1++];
	}
	while (p2 <= r)
	{
		help[i++] = a[p2++];
	}
	for (int j = 0; j < i; j++)
	{
		a[l + j] = help[j];
	}
	return res;
}

int MergeSort(int  a[], int l, int r)
{
	if (l < r) {
		    
		int mid = l + ((r - l) >> 1);
		     
			//左侧范围上排序求小和
		return MergeSort(a, l, mid)
			  //右侧范围上求小和
			+MergeSort(a, mid + 1, r)
			  //左组和右组合并的情况下求小和
			+merge(a, l, mid, r);
	}	
	return 0;
}

int main()
{
	int a[] = { 1,3,4,2,5,4 };
	int i = 0, n = 6;
	int ans = MergeSort(a, i, n-1);
	std::cout << ans;
}

下面是逆序对问题的完整代码:

#include <iostream>

void merge(int a[], int l, int m, int r)
{
	int *help = new int[6];
	int i = 0;
	int p1 = l;
	int p2 = m + 1;
	int res = 0;
	while (p1 <= m && p2 <= r)
	{
		//逆序对的条件 左边的数大于右边的数
		if (a[p1] > a[p2])
		{
			std::cout << a[p1] << " " << a[p2] << std::endl;
		}
		//当左边严格大于右边时,才将左边的数字拷贝到help[]
		//不能是大于等于,因为这样才不会少统计   
		help[i++] = a[p1] > a[p2] ? a[p1++] : a[p2++];
	}
	while (p1 <= m)
	{
		help[i++] = a[p1++];
	}
	while (p2 <= r)
	{
		help[i++] = a[p2++];
	}
	for (int j = 0; j < i; j++)
	{
		a[l + j] = help[j];
	}
}

void MergeSort(int  a[], int l, int r)
{
	if (l < r) {
		    
		int mid = l + ((r - l) >> 1);
		     
			//左侧范围上排序求逆序对
		MergeSort(a, l, mid);
			  //右侧范围上求逆序对
		MergeSort(a, mid + 1, r);
			  //左组和右组合并的情况下求逆序对
		merge(a, l, mid, r);
	}	
}

int main()
{
	int a[] = { 1,3,4,2,5,4 };
	int i = 0, n = 6;
	 MergeSort(a, i, n-1);
	 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值