赞
踩
在一个数组中,每一个数组左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
例子:
[1,3,4,2,5]左边比1小的数,没有。3左边比1小的数,1;4左边比4小的数,1,3;2左边比2小的数,1;5左边比5小的数,1,3,4,2;所以小和为1+1+3+1+1+3+4+2=16。
第一种思路就是暴力递归
第二种思路就是通过归并排序在进行排序的同时拿到他的小和。
1*4+3*2+4*1+2*1
=16package com.zhao; /** * @version v1.0 * @ProjectName: 数据结构 * @ClassName: SmallSum * @Description: 小核问题 * @Author: 赵先生 * @Date: 2022/2/10 10:27 *求小和的意思是将数组中每一个数左边比它小的数累积起来,称为小和。 */ public class SmallSum { public static int small(int[] arr) { //如果数组为空,或者数组的个数为0或者1,就证明小和个数为0。 if (arr == null || arr.length < 2){ return 0; } return process(arr, 0, arr.length-1); } /** * 既要排序也要求小和 * @param arr * @param l * @param r * @return */ private static int process(int[] arr, int l, int r) { if (l == r) { return 0; } //计算中间值 int mid = l + ((r - 1) >> 1); //小和最后的数量=左侧排序小和的数量+右侧排序加小和的数量+最后一次合并小和的数量 return process(arr, mid + 1, r) + process(arr, l, mid) + merge(arr, l, mid, r); } /** * 求小和 * @param arr 数组 * @param l 左边位置 * @param mid 中间位置 * @param r 右边位置 * @return 小和值 */ private static int merge(int[] arr, int l, int mid, int r) { /** * arr1 新建数组,用于排序 * p1 为左指针 * p2 为右指针 * res 为存放小和的值 */ int[] arr1 = new int[r-l+1]; int i = 0; int p1 = l; int p2 = mid+1; int res = 0; //如果左右指针没有越界 while(p1 < mid && p2 <= r) { /** * 如果左指针的数字小与右指针的数字,那么就去计算右指针及其后面的长度(假设为n),那么小和的值为n*左指针的值 * (r - p2 +1)计算出个数 */ res += arr[p1] < arr[p2] ? (r - p2 +1) * arr[p1] : 0; //进行排序(如果相等必须要先让右边部分进去,为了方便计算长度) arr1[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]; } //这两步则是如果上面的操作完成后还有多余的数字,那么把他依次填入数组进行排序 while (p1 <= mid) { arr1[i++] = arr[p1++]; } while ((p2 <= r)) { arr1[i++] = arr[p2++]; } //复制数组 for (int j = 0; j < arr1.length; j++) { arr[l + j] = arr1[j]; } return res; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。