0

0

统计数组中不满足降序排列条件的数对:归并排序优化方法

花韻仙語

花韻仙語

发布时间:2025-10-03 15:28:26

|

595人浏览过

|

来源于php中文网

原创

统计数组中不满足降序排列条件的数对:归并排序优化方法

本文详细探讨了如何高效统计数组中不满足降序排列条件的数对,即找出所有满足 hs[i]

引言:理解“不满足降序条件的数对”

在数组处理中,我们有时需要识别那些不符合特定排序规则的元素对。本教程关注的问题是:给定一个整数数组 hs,我们需要统计所有满足以下条件的数对 (hs[i], hs[j]) 的数量:

  1. i
  2. hs[i]

这类数对可以理解为在目标降序排列中出现的“逆序”对。例如,对于数组 hs = [7, 3, 5, 4, 1]:

  • 3 小于 5 (且 3 在 5 之前),形成一个不满足降序条件的数对 (3, 5)。
  • 3 小于 4 (且 3 在 4 之前),形成一个不满足降序条件的数对 (3, 4)。 因此,总数为 2。

再如 hs = [8, 5, 6, 7, 2, 1]:

  • 5 小于 6,形成 (5, 6)。
  • 5 小于 7,形成 (5, 7)。
  • 6 小于 7,形成 (6, 7)。 总数为 3。

接下来,我们将介绍两种解决此问题的方法。

方法一:暴力枚举法 (O(N^2))

最直观的方法是使用两层嵌套循环,遍历所有可能的数对 (hs[i], hs[j]) 并检查它们是否满足条件。

算法思路

  1. 初始化一个计数器 count 为 0。
  2. 外层循环从数组的第一个元素 i = 0 遍历到倒数第二个元素 hs.length - 1。
  3. 内层循环从 j = i + 1 遍历到数组的最后一个元素 hs.length - 1。
  4. 在内层循环中,比较 hs[i] 和 hs[j]。如果 hs[i]
  5. 循环结束后,count 即为所需结果。

示例代码

public class ArrayPairCounter {

    /**
     * 使用暴力枚举法统计不满足降序条件的数对。
     * 时间复杂度:O(N^2)
     *
     * @param hs 输入整数数组
     * @return 不满足降序条件的数对数量
     */
    public static int countBaadBruteForce(int[] hs) {
        int count = 0;
        for (int i = 0; i < hs.length; i++) {
            for (int j = i + 1; j < hs.length; j++) {
                // 比较当前位置 hs[i] 与其后的所有位置 hs[j]
                if (hs[i] < hs[j]) {
                    // System.out.println("Found bad pair: (" + hs[i] + "," + hs[j] + ")"); // 可选:打印数对
                    count++;
                }
            }
        }
        return count;
    }

    public static void main(String[] args) {
        int[] arr1 = {7, 3, 5, 4, 1};
        System.out.println("Array: " + java.util.Arrays.toString(arr1) + ", Bad pairs: " + countBaadBruteForce(arr1)); // 预期输出 2

        int[] arr2 = {8, 5, 6, 7, 2, 1};
        System.out.println("Array: " + java.util.Arrays.toString(arr2) + ", Bad pairs: " + countBaadBruteForce(arr2)); // 预期输出 3
    }
}

优缺点

  • 优点: 算法逻辑简单直观,易于理解和实现。
  • 缺点: 时间复杂度为 O(N^2),对于大型数组,性能会显著下降。

方法二:基于归并排序的优化算法 (O(N log N))

当数组规模较大时,O(N^2) 的暴力解法将无法满足性能要求。我们可以利用归并排序的特性,在 O(N log N) 的时间复杂度内完成计数。这种方法的核心在于归并(merge)阶段。

DALL·E 2
DALL·E 2

OpenAI基于GPT-3模型开发的AI绘图生成工具,可以根据自然语言的描述创建逼真的图像和艺术。

下载

归并排序基础回顾

归并排序是一种分治算法:

  1. 分解 (Divide): 将待排序数组分成两个大致相等的子数组。
  2. 解决 (Conquer): 递归地对这两个子数组进行排序。
  3. 合并 (Combine): 将两个已排序的子数组合并成一个完整的有序数组。

在合并两个已排序的子数组时,我们可以同时统计满足条件的数对。

计数原理

假设我们正在合并两个已经按照降序排列的子数组 l (左半部分) 和 r (右半部分)。我们的目标是统计原始数组中所有 hs[i]

当从 l 和 r 中选择元素合并到一个新的数组 a 时:

  • 如果 l[lIdx] >= r[rIdx]:这意味着 l[lIdx] 应该在 r[rIdx] 之前(或相等),符合降序排列。我们将 l[lIdx] 放入 a,并继续处理 l 的下一个元素。此时,l[lIdx] 与 r[rIdx] 不构成我们定义的“不满足降序条件的数对”。
  • 如果 l[lIdx]

通过在每次合并时累加这些计数,我们最终可以得到整个数组中不满足降序条件的数对总数。

代码实现

import java.util.Arrays; // 引入Arrays工具类用于打印和数组复制

public class MergeSortPairCounter {

    /**
     * 外部调用接口,用于统计不满足降序条件的数对。
     * 为了避免修改原始数组,先复制一份。
     *
     * @param hs 输入整数数组
     * @return 不满足降序条件的数对数量
     */
    public static int countBaadMergeSort(int[] hs) {
        // 复制数组以避免对原始数组的副作用
        int[] tempArray = Arrays.copyOf(hs, hs.length);
        return mergeSortAndCount(tempArray, tempArray.length);
    }

    /**
     * 归并排序的核心逻辑,同时进行计数。
     *
     * @param a 待排序并计数的数组
     * @param n 数组长度
     * @return 不满足降序条件的数对数量
     */
    private static int mergeSortAndCount(int[] a, int n) {
        // 基本情况:如果数组只有一个元素,无需排序,也没有不满足条件的数对
        if (n <= 1) { // 修正:n < 2 即可,n=1时返回0
            return 0;
        }

        int mid = n / 2;
        int[] l = new int[mid];
        int[] r = new int[n - mid];

        // 使用 System.arraycopy 提高数组复制效率
        System.arraycopy(a, 0, l, 0, mid);
        System.arraycopy(a, mid, r, 0, n - mid);

        // 累加左右子数组的计数结果
        int count = 0;
        count += mergeSortAndCount(l, mid);
        count += mergeSortAndCount(r, n - mid);

        // 累加当前归并操作产生的计数结果
        count += mergeAndCount(a, l, r);
        return count;
    }

    /**
     * 归并两个已排序的子数组,并统计不满足降序条件的数对。
     * 注意:此方法将合并后的结果存回数组 a,并按照降序排列。
     *
     * @param a 目标数组,用于存放合并后的结果
     * @param l 左子数组 (已降序排列)
     * @param r 右子数组 (已降序排列)
     * @return 当前归并操作中发现的不满足降序条件的数对数量
     */
    private static int mergeAndCount(int[] a, int[] l, int[] r) {
        // System.out.println("Merging " + Arrays.toString(l) + " and " + Arrays.toString(r)); // 可选:打印合并过程

        int badPairCount = 0;
        int lIdx = 0, rIdx = 0, aIdx = 0;

        // 当左右子数组都还有元素时进行比较合并
        while (lIdx < l.length && rIdx < r.length) {
            // 如果左边元素大于等于右边元素,符合降序排列,取左边元素
            if (l[lIdx] >= r[rIdx]) {
                a[aIdx++] = l[lIdx++];
            } else {
                // 如果左边元素小于右边元素,则 r[rIdx] 比 l[lIdx] 大
                // 并且 r[rIdx] 比 l 数组中从 lIdx 位置开始的所有剩余元素都大
                // 这些都构成“不满足降序条件”的数对
                // System.out.println("  Found bad pairs with " + r[rIdx] + " from left remaining: " + Arrays.toString(Arrays.copyOfRange(l, lIdx, l.length))); // 可选:打印详细数对
                badPairCount += (l.length - lIdx); // 累加计数
                a[aIdx++] = r[rIdx++]; // 取右边元素
            }
        }

        // 将剩余的左边元素复制到目标数组
        if (lIdx < l.length) {
            System.arraycopy(l, lIdx, a, aIdx, l.length - lIdx);
        }
        // 将剩余的右边元素复制到目标数组
        if (rIdx < r.length) {
            System.arraycopy(r, rIdx, a, aIdx, r.length - rIdx);
        }

        // System.out.println("  Merged result: " + Arrays.toString(a) + ", Current bad pairs: " + badPairCount); // 可选:打印合并结果和计数
        return badPairCount;
    }

    public static void main(String[] args) {
        int[] arr1 = {7, 3, 5, 4, 1};
        System.out.println("Array: " + java.util.Arrays.toString(arr1) + ", Bad pairs (Merge Sort): " + countBaadMergeSort(arr1)); // 预期输出 2

        int[] arr2 = {8, 5, 6, 7, 2, 1};
        System.out.println("Array: " + java.util.Arrays.toString(arr2) + ", Bad pairs (Merge Sort): " + countBaadMergeSort(arr2)); // 预期输出 3
    }
}

注意事项

  1. 累加所有子归并结果: mergeSortAndCount 函数必须累加递归调用 mergeSortAndCount(l, mid)、mergeSortAndCount(r, n - mid) 和当前 mergeAndCount 的结果,才能得到最终的总数。这是原代码中常见的错误点,只返回了最后一次合并的结果。
  2. 避免副作用:复制原始数组: mergeSortAndCount 方法会修改传入的数组以完成排序。如果需要保留原始数组不变,应在调用前使用 Arrays.copyOf() 创建一个副本,如 countBaadMergeSort 方法所示。
  3. 性能优化:使用 System.arraycopy: 在数组的复制和剩余元素的拷贝

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

198

2023.11.20

length函数用法
length函数用法

length函数用于返回指定字符串的字符数或字节数。可以用于计算字符串的长度,以便在查询和处理字符串数据时进行操作和判断。 需要注意的是length函数计算的是字符串的字符数,而不是字节数。对于多字节字符集,一个字符可能由多个字节组成。因此,length函数在计算字符串长度时会将多字节字符作为一个字符来计算。更多关于length函数的用法,大家可以阅读本专题下面的文章。

927

2023.09.19

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

408

2023.08.14

PHP 高并发与性能优化
PHP 高并发与性能优化

本专题聚焦 PHP 在高并发场景下的性能优化与系统调优,内容涵盖 Nginx 与 PHP-FPM 优化、Opcode 缓存、Redis/Memcached 应用、异步任务队列、数据库优化、代码性能分析与瓶颈排查。通过实战案例(如高并发接口优化、缓存系统设计、秒杀活动实现),帮助学习者掌握 构建高性能PHP后端系统的核心能力。

101

2025.10.16

PHP 数据库操作与性能优化
PHP 数据库操作与性能优化

本专题聚焦于PHP在数据库开发中的核心应用,详细讲解PDO与MySQLi的使用方法、预处理语句、事务控制与安全防注入策略。同时深入分析SQL查询优化、索引设计、慢查询排查等性能提升手段。通过实战案例帮助开发者构建高效、安全、可扩展的PHP数据库应用系统。

86

2025.11.13

JavaScript 性能优化与前端调优
JavaScript 性能优化与前端调优

本专题系统讲解 JavaScript 性能优化的核心技术,涵盖页面加载优化、异步编程、内存管理、事件代理、代码分割、懒加载、浏览器缓存机制等。通过多个实际项目示例,帮助开发者掌握 如何通过前端调优提升网站性能,减少加载时间,提高用户体验与页面响应速度。

29

2025.12.30

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

24

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

7

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

28

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 7.8万人学习

Java 教程
Java 教程

共578课时 | 52.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号