在一个数组中,一个数左边比它小的数的总和,叫数的小和,所有数的小和累加起来,叫数组小和。求数组小和。
5 2 6 1 7 小和原始的求法是:任何一个数左边比它小的数累加起来。 5左边比它小数累加:0 2左边比它小数累加:0 6左边比它小数累加:5 + 2 = 7 1左边比它小数累加:0 7左边比它小数累加:5 + 2 + 6 + 1 = 14 总共21。
如果左侧某数a比右侧某数b小,则在求b的小和的时候,肯定会累加一个a,即sum+=a。 反过来,在遍历到a的时候,如果我们知道右侧有几个数比a大,则可以提前知道会累加几个a 使用归并排序时恰好有左右对比操作,所以使用归并排序来做 即: 每个数右边比它大的数的个数 * 这个数自身 所以: 在原来归并排序的基础上,增加一个ans用于记录结果 在进行归并时左侧<右侧时产生小数 n * number
小和求法还可以是:每个数右边比它大的数的个数 * 这个数自身 5 2 6 1 7 5的右边比它大的数的个数:2个(6和7),所以产生:2个 * 5 = 10 2的右边比它大的数的个数:2个(6和7),所以产生:2个 * 2 = 4 6的右边比它大的数的个数:1个(7),所以产生:1个 * 6 = 6 1的右边比它大的数的个数:1个(7),所以产生:1个 * 1 = 1 7的右边比它大的数的个数:0个,所以产生:0个 * 7 = 0 总共21。
-
- public static int smallSum(int [] arr){
- if(arr == null || arr.length <2)
- return 0;
-
- int [] help = new int[arr.length];
- int step = 1;
- int N = arr.length;
- int L = 0;
- int ans = 0;
-
- while (step < N){
- L = 0;
- while (L < N){
- //左组最后一个数位置
- int m = L + step - 1;
- if(m >= N){
- break;
- }
- if(step >= N - L){
- break;
- }
- int R = Math.min(m+step,N-1);
- ans += merge(arr,L,m,R,help);
-
- L = R + 1;
- }
- if(step > N/2){
- break;
- }
- step <<= 1;
- }
- return ans;
- }
-
- public static int merge(int[] arr,int l,int m,int r,int [] help){
- //help index
- int i = 0;
- //p1 左侧开始index,p2 右侧开始index
- int p1 = l;
- int p2 = m+1;
- //结果保存
- int ans = 0;
- while (p1 <= m && p2 <= r){
- ans += arr[p1]
1):0; - help[i++] = arr[p1]
- }
- while (p1 <= m){
- help[i++] = arr[p1++];
- }
- while (p2 <= r){
- help[i++] = arr[p2++];
- }
- for (i = 0; i < r-l+1 ; i++) {
- arr[l+i] = help[i];
- }
- return ans;
- }
递归
- public static int progress(int [] arr,int l,int r,int [] help){
-
- if(l == r)
- return 0;
- int m = l + ((r -l) >> 1);
-
- return progress(arr,l,m,help)
- + progress(arr,m+1,r,help)
- + merge(arr,l,m,r,help);
- }
逆序对问题
描述
一个数组中,左边的数比右边的数大,求有多少个这样的组合
比如 [3,1,0,4,3,1] 有7个逆序对,分别是
(3,1),(3,0),(3,1)
(1,0)
(4,3),(4,1)
(3,1)
code
- //递归
- public static int reversePair(int [] arr){
- if(arr == null || arr.length <2)return 0;
-
- return progress(arr,0,arr.length -1);
- }
- public static int progress(int [] arr,int l,int r){
- if(l == r)return 0;
- int m = l + ((r-l)>>1);
- return progress(arr,l,m)
- +progress(arr,m+1,r)
- +merge(arr,l,m,r);
- }
-
- //非递归
- public static int reversePair2(int [] arr){
- if(arr == null || arr.length < 2)return 0;
-
- int ans = 0;
- int L = 0;
- int N = arr.length;
- int step = 1;
- while (step < N){
- L = 0;
- while (L < N){
- if(L+step >= N)break;
- int m = L + step - 1;
- if(m >= N)break;
- int r = Math.min(N-1,m+step);
- int temp = merge(arr,L,m,r);
- ans += temp;
- L = r + 1;
- }
- if(step > N/2)break;
- step <<= 1;
- }
- return ans;
- }
- public static int merge(int [] arr,int L,int M,int R){
- // 先算有多少逆序对
- // 和归并过程分离
- int res = 0;
- int p = M + 1;
- for (int i = L; i <= M; i++) {
- while (p <= R && arr[i] > arr[p]) {
- p++;
- }
- res += p - (M + 1);
- }
- // 下面完全和归并排序一样
- int[] help = new int[R - L + 1];
- int i = 0;
- int p1 = L;
- int p2 = M + 1;
- while (p1 <= M && p2 <= R) {
- help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
- }
- // 要么p1越界了,要么p2越界了
- while (p1 <= M) {
- help[i++] = arr[p1++];
- }
- while (p2 <= R) {
- help[i++] = arr[p2++];
- }
- for (i = 0; i < help.length; i++) {
- arr[L + i] = help[i];
- }
- return res;
- }
左边大于右边倍数的数
描述
在一个数组中,
对于每个数num,求有多少个后面的数 * 2 依然
思路
右边有多少个数*2比左边的数小
在归并排序过程中,分组后左侧有序,右侧有序,在进行左右侧合并时,统计验证关系【2倍关系】
这样可以得到该左侧位置相对于右侧位置的2倍关系统计和
code
-
- //递归
- public static int biggerThatRightTwice(int []arr){
- if(arr == null || arr.length<2){
- return 0;
- }
- return progress(arr,0,arr.length-1);
- }
- public static int progress(int[] arr,int l,int r){
- if(l == r){
- return 0;
- }
- int m = l + ((r-l)>>1);
- System.out.println("l,m,r:"+l+","+m+","+r);
-
- return progress(arr,l,m)
- +progress(arr,m+1,r)
- +merge(arr,l,m,r);
- }
-
- //非递归
- public static int biggerThatRightTwice2(int [] arr){
- if(arr == null || arr.length <2)return 0;
-
- int L = 0;
- int step = 1;
- int N = arr.length;
- int ans = 0;
- while (step < N){
- L = 0;
- while (L < N){
- if(step >= N-L)break;
- int m = L + step - 1;
- if(m >= N)break;
- int r = Math.min(m+step,N-1);
- ans += merge(arr,L,m,r);
- L = r + 1;
- }
- if(step > N/2)break;
- step <<=1;
- }
- return ans;
- }
- public static int merge(int[] arr,int l,int m,int r){
- //[l,m] [m+1,r]进行归并,其中[l,m],[m+1,r]分别已经有序
-
- //先计算
- int p1 = l,p2 = m+1;
- int ans = 0;
- //左侧遍历l
- while (p1 <= m){
- //右侧遍历
- while (p2 <= r){
- //如果左侧 > 右侧 * 2,则继续判断,知道不满足条件
- //当不满足条件时,则右侧从开始位置m+1到p2位置为p1满足条件的数
- if(arr[p1] > arr[p2] *2){
- p2++;
- }else{
- break;
- }
- }
- //p2 - (m+1) => [m+1,p2) 即从m+1到p2个元素个数,不包含p2
- ans += (p2 - (m+1));
- p1++;
- }
- //再进行归并
- int [] help = new int[r-l+1];
- int i = 0;
- p1 = l;
- p2 = m+1;
- while (p1<=m && p2<=r){
- help[i++] = arr[p1]
- }
- while (p1<=m){
- help[i++] = arr[p1++];
- }
- while (p2<=r){
- help[i++] = arr[p2++];
- }
- for(i=0;i
- arr[l+i] = help[i];
- }
- return ans;
- }
-
相关阅读:
数据结构——树
js数组操作——对象数组根据某个相同的字段分组
【接口自动化测试入门】接口测试基础(超详细~)
「零基础从零开始写VO视觉里程计」G2O基础知识讲解(7-5)
准入控制器(Admission Controller):ResourceQuota,ImagePolicyWebhook
解决HBuilderX无法登录的问题
Dubbo反序列化漏洞分析集合
Apacha Flume
【无标题】
Java服务启动报Unsupported record version Unknown-0.0
-
原文地址:https://blog.csdn.net/hey_lie/article/details/132741871