Sword se refiere a la Oferta 51. Pares invertidos en una matriz (aplicación de clasificación por fusión)

Viernes 12 de febrero de 2021, hace buen tiempo [No te lamentes del pasado, no desperdicies el presente, no temas al futuro]


1. Introducción

Sword se refiere a la Oferta 51. Pares invertidos en la matriz
Inserte la descripción de la imagen aquí

2. Aplicación de ordenación combinada

Antes de resolver el problema para estar muy familiarizado con el tipo de combinación, se recomiendan los algoritmos de clasificación de gráficos (d) del tipo de combinación , con gráficos que pueden comprender muy rápidamente el significado del tipo de combinación.

Después de dominar la combinación y la clasificación, y luego mirar cuidadosamente la solución del jefe superkakayong en Leetcode , la idea de resolver este problema es más clara. Después de eso, siga las ideas y escriba el código paso a paso. El proceso de construcción de código a partir de ideas debe estar lleno de dificultades, pero esto también es lo que necesitamos para enfocarnos en la capacitación.Sólo escribiendo a mano el código de acuerdo con las ideas podemos realmente dominar el método.

El siguiente es el código de resolución de problemas de leetcode de superkakayong:

class Solution {
    
    
public:
    int reversePairs(vector<int>& nums) {
    
    
        int len = nums.size();

        if (len < 2) {
    
    
            return 0; // 若不存在数对,直接 return 0
        }

        vector<int> helper(len);

        return reversePairs(nums, 0, len - 1, helper);
    }

private:
    int reversePairs(vector<int>& nums, int left, int right, vector<int>& helper) {
    
    
        if (left == right) {
    
    
            return 0; // 递归终止条件是只剩一个元素了(即不存在数对了)
        }

        int mid = left + (right - left) / 2; // 此算式等同于 (left + right) / 2,是为了避免溢出

        int leftPairs = reversePairs(nums, left, mid, helper); // 计算左半部分的逆序对
        int rightPairs = reversePairs(nums, mid + 1, right, helper); // 计算右半部分的逆序对

        if (nums[mid] <= nums[mid + 1]) {
    
    
            // 此判断用于加速,即如果左右都已排好序,而且左边的最大值 <= 右边的最小值,
            // 那么就不存在跨越左边和右边的逆序对了
            return leftPairs + rightPairs; 
        }

        int crossPairs = mergeAndCount(nums, left, mid, right, helper); // 计算跨越左边和右边的逆序对

        return leftPairs + rightPairs + crossPairs;
    }

    int mergeAndCount(vector<int>& nums, int left, int mid, int right, vector<int>& helper) {
    
    
        // 本函数的前提条件是:左半部分和右半部分都是已经按升序排好序了的
        // 因为本函数是从左右部分都是只有一个元素的情况开始运行的(自底向上),所以是可以保证前提条件的
        for (int i = left; i <= right; ++i) {
    
    
            helper[i] = nums[i]; // 先填充 helper 辅助数组
        }

        int i = left, j = mid + 1; // i 和 j 分别是左半部分和右半部分的起点
        int count = 0; // count 用来统计逆序对数量

        for (int k = left; k <= right; ++k) {
    
    
            if (i == mid + 1) {
    
    
                // 假如 i 已经越过左边的边界,直接填充右半部分进 nums
                nums[k] = helper[j];
                ++j;
            } else if (j == right + 1) {
    
    
                // 假如 j 已经越过右边的边界,直接填充左半部分进 nums
                nums[k] = helper[i];
                ++i;
            } else if (helper[i] <= helper[j]) {
    
     // 注意健壮的归并排序这里要是 <=
                // 假如左边小于等于右边,那就不是逆序对,不用修改 count
                nums[k] = helper[i];
                ++i;
            } else {
    
    
                // 假如左边大于右边,是逆序对,count += 当前左边 [i, mid] 的所有元素
                // 因为假如左边是 [7,8],右边是[5,6],然后 i 指向 7,j 指向 5
                // 那么 5 和 7、8 都构成了逆序对,也就是此时有两对新的逆序对
                // 所以可以总结出规律:count += mid - i + 1
                nums[k] = helper[j];
                count += mid - i + 1;
                ++j;
            }
        }

        return count;
    }
};

referencias

"Oferta de Sword Finger Segunda Edición"

https://www.cnblogs.com/chengxiao/p/6194356.html

https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solution/zi-jie-ti-ku-jian-51-kun-nan-shu-zu- zhon-eipc /

Supongo que te gusta

Origin blog.csdn.net/m0_37433111/article/details/113797539
Recomendado
Clasificación