小和问题

在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和。

例子:
[1,3,4,2,5]
1左边比1小的数, 没有;
3左边比3小的数, 1;
4左边比4小的数, 1、 3;
2左边比2小的数, 1;
5左边比5小的数, 1、 3、 4、 2;
所以小和为1+1+3+1+1+3+4+2=16

其实小和问题就是归并排序的应用。不了解归并排序的,可以看一下这篇文章归并排序

废话不多说,直接上代码

package com.chenli.sort;

/**
 * 归并排序的应用:小和问题
 * @author chenli
 *
 */
public class SmallSum {
	
	public static int smallSum(int[]arr){
		
		if(arr==null||arr.length<2){
			return 0;
		}
		
		return mergeSort(arr,0,arr.length-1);
		
	}

	private static int mergeSort(int[] arr, int left, int right) {
		
		//递归结束条件
		if(left == right){
			return 0;
		}
		//相当于mid =(left+right)/2 即 mid=left+(right-left)/2
		//使用这种形式是为了防止溢出。为什么使用位运算?因为位运算在电脑里比算术运算快
		int mid = left + ((right-left)>>1);
		return mergeSort(arr, left, mid)
				+mergeSort(arr, mid+1, right)
				+merge(arr,left,mid,right);		
	}

	private static int merge(int[] arr, int left, int mid, int right) {
		
		//定义一个辅助数组
		int[]help = new int[right-left+1];
		//定义一个指向左边有序数组的第一个数的下标的指针
		int p1 = left;
		//定义一个指向右边有序数组的第一个数的下标的指针
		int p2 = mid +1;
		//记录小和数的结果
		int result = 0;
		//辅助数组开始的下标
		int i = 0;
		
		while(p1<=mid&&p2<=right){
			/*
			 if(arr[p1]<arr[p2]){
			 	result = result + (p2-mid+1)*arr[p1];
			 	}
			 如果arr[p2]>arr[p1],说明arr[p2]后面的值都大于arr[p1]。
			 所以直接记录有几个大于arr[p1]的值
			 */
			result += arr[p1]<arr[p2]?(right-p2+1)*arr[p1]:0;
			help[i++] = arr[p1]<arr[p2]?arr[p1++]:arr[p2++];			
		}
		while(p1<=mid){
			help[i++]=arr[p1++];
		}
		while(p2<=right){
			help[i++]=arr[p2++];
		}
		for(int k=0;k<help.length;k++){
			arr[left+k]=help[k];
		}
		return result;
	}

	public static void main(String[] args) {
		
		int[]arr = {1,3,4,2,5};
		int smallsum = smallSum(arr);
		System.out.println("小和的值为:"+smallsum);

	}

}

运行结果在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值