**(不会)数据结构--小和问题 逆序对问题

小和问题
在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和。 求一个数组的小和。
例子:
[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

解:利用归并排序中,在进行两部分小组合并时,会在对比时,如果左边的比右边的小,则加上 右边个数个的左边的数  num * (right - y + 1)

其中的某一次对比

求小和只发生在两个小组之间。

 

public class LittleSum {

    public int littleSum(int [] arrays){
        return mergeSort(arrays, 0, arrays.length - 1);
    }

    public int mergeSort(int[] arrays, int left, int right){
        if(left >= right){
            return 0;
        }

        int mid = left + ((right - left) >> 1);
        return mergeSort(arrays, left, mid)
                + mergeSort(arrays, mid + 1, right)
                + merge(arrays, left, mid, right);
    }

    public int merge(int[] arrays, int left, int mid, int right){
        int sum = 0;
        int[] help = new int[right - left + 1];
        int i = 0;
        int x = left, y = mid + 1;
        while(x <= mid && y <= right){
            sum += arrays[x] < arrays[y] ? arrays[x] * (right - y + 1) : 0;
            help[i++] = arrays[x] < arrays[y] ? arrays[x++] : arrays[y++];
        }
        while(x <= mid){
            help[i++] = arrays[x++];
        }
        while(y <= right){
            help[i++] = arrays[y++];
        }
        i = 0;
        while(i < help.length){
            arrays[left + i] = help[i++];
        }
        return sum;
    }

    public static void main(String[] args){
        int[] arrays = {1, 3, 4, 2, 5};

        LittleSum littleSum = new LittleSum();
        int sum = littleSum.littleSum(arrays);
        System.out.println(sum);
    }


}

  

逆序对问题
在一个数组中, 左边的数如果比右边的数大, 则折两个数构成一个逆序对, 请打印所有逆序对 

 解:逆序对的同理,在merge的过程中,比较相应的两个数,遇到arrays[x] > arrays[y] 则从x开始,到mid结束,都比arrays[y]大,都可以构成逆序对,所以只需要将它们输出即可

与小和相比,只有第一个while处不同,其余地方均没有改动

public void merge(int[] arrays, int left, int mid, int right){
        int[] help = new int[right - left + 1];
        int i = 0;
        int x = left, y = mid + 1;
        while(x <= mid && y <= right){
            if(arrays[x] > arrays[y]){
                for(int j = x; j <= mid; j++){
                    System.out.println(arrays[j] + " " + arrays[y]);
                }
                help[i++] = arrays[y++];
            } else{
                sum += arrays[x] * (right - y + 1);
                help[i++] = arrays[x++];
            }
        }
        while(x <= mid){
            help[i++] = arrays[x++];
        }
        while(y <= right){
            help[i++] = arrays[y++];
        }
        i = 0;
        while(i < help.length){
            arrays[left + i] = help[i++];
        }
    }

  

 

剑指offer中的逆序对:会有大小,溢出的问题,用int类型,会溢出,要用long型才可以

数组中的逆序对

public class Solution {
    public int InversePairs(int [] array) {
        if(array == null || array.length == 0) return 0;
        long res = mergeSort(array, 0, array.length - 1);
        return (int)(res % 1000000007);
    }

    public long mergeSort(int[] array, int left, int right){
        if(left >= right){
            return 0;
        }
        int mid = ((right - left) >> 1) + left;
        return mergeSort(array, left, mid) 
            + mergeSort(array, mid + 1, right) 
            + merge(array, left, mid, right);
    }

    public long merge(int[] array, int left, int mid, int right){
        int[] help = new int[right - left + 1];
        int i = left, j = mid + 1, flag = 0;
        long res = 0;
        while(i <= mid && j <= right){
            if(array[i] < array[j]){
                help[flag++] = array[i++];
            }else {
                help[flag++] = array[j++];
                res = res + (mid - i + 1);
            }
        }
        while(i <= mid){
            help[flag++] = array[i++];
        }
        while(j <= right){
            help[flag++] = array[j++];
        }

        for(i = 0; i < flag; i++){
            array[left + i] = help[i];
        }
        return res;
    }
}

  

posted @ 2018-04-04 10:43  SkyeAngel  阅读(951)  评论(0编辑  收藏  举报