java
复制代码
import java.util.Arrays;
/**
* @title CalculationArrayXiaoHe
* @description 计算数组小和 https://www.nowcoder.com/practice/edfe05a1d45c4ea89101d936cac32469
* 描述
* 例如,数组 s = [1, 3, 5, 2, 4, 6] ,
* 在 s[0] 的左边小于或等于 s[0] 的数的和为 0 ; 在 s[1] 的左边小于或等于 s[1] 的数的和为 1 ;
* 在 s[2] 的左边小于或等于 s[2] 的数的和为 1+3=4 ; 在 s[3] 的左边小于或等于 s[3] 的数的和为 1 ;
* 在 s[4] 的左边小于或等于 s[4] 的数的和为 1+3+2=6 ;在 s[5] 的左边小于或等于 s[5] 的数的和为 1+3+5+2+4=15 。
* 所以 s 的小和为 0+1+4+1+6+15=27
* 给定一个数组 s ,实现函数返回 s 的小和
* 输入描述:
* 第一行有一个整数N。表示数组长度
* 接下来一行N个整数表示数组内的数
* 输出描述:
* 一个整数表示答案
* author zzw
* version 1.0.0
* create 2024/10/28 22:32
**/
public class CalculationArrayXiaoHe {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 2, 4, 6};
arr = new int[]{5, 5, 5, 5, 5};
long result = smallSum(arr, 0, arr.length - 1);
System.out.println(result);
System.out.println(Arrays.toString(arr));
}
public static long smallSum(int[] arr, int l, int r) {
if (l == r) {
return 0;
}
int m = l + (r - l) / 2;
return smallSum(arr, l, m) + smallSum(arr, m + 1, r) + merge(arr, l, m, r);
}
/**
* 返回跨左右产生的小和累加和。左侧有序、右侧有序,让左右有序
* arr[l ... m] arr[m+1 ... r]
*
* @param arr 处理中的数组
* @param l 左侧数组起始位置
* @param m 左侧数组终止位置 ,m+1 右侧数据起始位置
* @param r 右侧数据终止位置
* @return 数组从l到r的小和
*/
public static long merge(int[] arr, int l, int m, int r) {
//
long result = alculateCumulativeSum(arr, l, m, r);
orderedArrayMerging(arr, l, m, r);
return result;
}
/**
* 计算数组arr中子数组 arr[l ... r] 的累加和
*
* @param arr 处理中的数组
* @param l 左侧数组起始位置
* @param m 左侧数组终止位置 ,m+1 右侧数据起始位置
* @param r 右侧数据终止位置
* @return 数组从l到r的小和
*/
public static long alculateCumulativeSum(int[] arr, int l, int m, int r) {
// 默认右侧数组的第一位的小和sum为0
// 从右侧数组的第一位开始,从左侧数组的第一位开始进行比较,
// 如果右侧数组的数字大于等于左侧的数字,则将sum加上左侧数组当前下标的值
// 如果左侧数组的下标移动到了大于右侧数组处理下标处的数字或者移出了左侧数组的边界,将sum累加到ans上。
// 将右侧数组下标向后移动一位
long ans = 0;
int sum = 0;
for (int i = m + 1, j = l; i <= r; i++) {
for (; j <= m && arr[j] <= arr[i]; j++) {
sum += arr[j];
}
ans += sum;
}
return ans;
}
/**
* 数组中的连续的两个有序部分进行合并
*
* @param arr 处理中的数组
* @param l 左侧数组起始位置
* @param m 左侧数组终止位置 ,m+1 右侧数据起始位置
* @param r 右侧数据终止位置
*/
public static void orderedArrayMerging(int[] arr, int l, int m, int r) {
int ls = l;
int rs = m + 1;
int i = 0;
int[] tmpArr = new int[r - l + 1];
while (ls <= m && rs <= r) {
tmpArr[i++] = arr[ls] <= arr[rs] ? arr[ls++] : arr[rs++];
}
while (ls <= m) {
tmpArr[i++] = arr[ls++];
}
while (rs <= r) {
tmpArr[i++] = arr[rs++];
}
for (int j = l; j <= r; j++) {
arr[j] = tmpArr[j - l];
}
}
}