• 算法——计算数组中的逆序对


    在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
    输入: [7,5,6,4]
    输出: 5
    链接: leetcode.

    解题思路:利用归并排序的思想。在归并排序中,需要通过两个指针比较前后两个元素的大小,当前元素大于后元素时,这就是一个有效的逆序对。同时,如果某一前元素大于后元素,则前段元素区间中,该元素的后面元素也会大于后段区间中该后元素,所以,也需要将这一部分逆序对计算上。
    这样做会不会产生重复的逆序对计算呢?答案是不会的,每次比较的两个相等长度的段中的元素,随着递归,前面计算的段已经被合并,段的长度会增长,之后比较的元素一定不会再被重复比较,这样就不会产生重复计算。

    下面提供了两种做法,还是推荐递归做法,这样没用考虑很多边界问题。

    1. 递归做法
    class Solution {
        int res = 0;
        public int reversePairs(int[] nums) {
            merge(nums, 0, nums.length - 1);
    
            return res;
        }
    
        public void merge(int[] nums, int l, int r) {
            if(l >= r) return;
    
            int mid = l + r >> 1;
            merge(nums, l, mid);
            merge(nums, mid + 1, r);
    
            int i = l, j = mid + 1;
            List<Integer> temp = new ArrayList<>();
    
            while(i <= mid && j <= r) {
                if(nums[i] <= nums[j]) {
                    temp.add(nums[i]);
                    i++;
                } else {
                	// 逆序对计算,数量应当是i及i到mid之间的元素数量
                	// 因为i大于j位置的元素,那i之后的元素也一定大于j位置的元素
                    res += mid - i + 1;
                    temp.add(nums[j]);
                    j++;
                }
            }
    
            while(j <= r) {
                temp.add(nums[j]);
                j++;
            }
    
            while(i <= mid) {
                temp.add(nums[i]);
                i++;
            }
    
            i = l;
    
            while(i <= r) {
                nums[i] = temp.get(i - l);
                i++;
            }
    
        }
    }
    
    1. 非递归
    class Solution {
        public int reversePairs(int[] nums) {
            int n = nums.length;
            if(n == 0 || n == 1) return 0;
            int res = 0;
    
            for(int len = 1; len < n; len *= 2) {
                for(int i = 0; i < n; i += 2 * len) {
                    List<Integer> temp = new ArrayList<>();
                    int l = i, r = i + len;
                    int mid = i + len;
                    while(l < mid && r < i + len * 2 && r < n) {
                        if(nums[l] > nums[r]) {
                            res += mid - l;
                            temp.add(nums[r]);
                            r++;
                        } else{
                            temp.add(nums[l]);
                            l++;
                        }
                    }
    
                    while(l < mid && l < n) {
                        temp.add(nums[l++]);
                    }
    
                    while(r < i + len * 2 && r < n) {
                        temp.add(nums[r++]);
                    }
    
                    for(int j = 0; j < temp.size(); j++) {
                        nums[j + i] = temp.get(j);
                    }
                }
            }
    
            return res;
        }
    }
    
  • 相关阅读:
    How Many Answers Are Wrong
    Agri-Net —poj1258
    食物链
    A Bug's Life
    畅通工程
    Shortest path of the king
    Alex and Number
    KMP
    快速幂
    0x04
  • 原文地址:https://www.cnblogs.com/lippon/p/14117688.html
Copyright © 2020-2023  润新知