算法基础例三小和问题和逆序对问题

小和问题

在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
举个简单的例子:给一个数组1 3 4 2 6
1左边比1小的数,没有;
3左边比3小的数,1;
4左边比4小的数,1、3;
2左边比2小的数,1;
6左边比6小的数,1 、3、 4、 2;
所以小和为1+1+3+1+1+3+4+2 = 16;
解题思路:一种可以用暴力排序的方法,从第一个元素开始,轮流找前面小于该元素的值,再从第二个元素开始,轮流找前面小于该元素的值,,,一直到最后一个元素,累加这些小于当前元素的值即可。
还有一种方法就是利用归并排序。将数组分为左半部分和右半部分,小和一共分为三部分,第一部分为左半部分的小和,第二部分为右半部分的小和,第三部分为左半部分和右半部分合并时产生的小和。如果左半部分元素N,小于右半部分元素M,那么从右半部分右指针P到右半部分最后R就有(R-P+1)*N小和。
实现代码如下:

# include <stdio.h>
int megerSortArr(int arr[], int left, int middle, int right)
{
	int SortArr[right - left +1]; //用来排序 
	int p1 = left;  //指向数组最左边的数 
	int p2 = middle + 1; //指向数组最右边的数
	int sum = 0; 
	int i = 0;
	while(p1 <= middle && p2 <= right)   
	{
		sum += arr[p1] < arr[p2] ? (right - p2 +1) * arr[p1] : 0;  //小和思想,第三部分—归并产生的小和 
		
		SortArr[i ++] = arr[p1] <arr[p2] ? arr[p1 ++]:arr[p2 ++]; //归并排序 ,谁小放谁 
	} 
	while(p1 < middle) //归并排序,右边越界 
	{
		SortArr[i ++] = arr[p1 ++];  //左边部分全部复制 
	}
	while(p2 < right) //归并排序,左边越界 
	{
		SortArr[i ++] = arr[p2 ++]; //右边部分全部复制 
	} 
	
	return sum;
}
int megerSort(int arr[], int left, int right)
{
	if(left == right)  //递归的结束条件 
	{
		return 0;
	}
	int middle  =  left + ((right - left) >> 1);  //(left + right) / 2; 
	//左半部分小和 + 右半部分小和 + 数组归并排序产生的小和 
	return megerSort(arr,left,middle) + megerSort(arr,middle+1,right) + megerSortArr(arr,left,middle,right);
}
int megerSortSum(int arr[],int n) 
{
	return megerSort(arr,0,n-1); 
}
int main(void)
{
   // int a[] = {500, 22, 53, -158, 4, 86, 32, 33, 26, -70, 135, -34, 32, 543, 2500};
    int a[] = {1,3,4,2,5,6};
    int n;  //存放数组a中元素的个数
	int sum2 =0; 
    n = sizeof(a) / sizeof(a[0]);  /*a[0]是int型, 占4字节*/
    sum2 =  megerSortSum(a,n);

    printf("%d\t",sum2);

    printf("\r\n");
    return 0;
} 
逆序对问题

在一个数组中,左边的数如果比右边的数大,则两个数构成一个逆序对,请打印逆序对的数目。
解题思路和求解小和问题一样,这里只要把上面的第11行代码换成sum += arr[p1] > arr[p2] ? (middle - p1 + 1) : 0; 即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

经纬的无疆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值