【算法刷题】蓝桥杯:0星际争霸(大数比较 + 多关键字自定义排序)

【算法刷题】蓝桥杯:0星际争霸(大数比较 + 多关键字自定义排序)

📌 题目链接与描述

  • 题目名称:0星际争霸
  • 题目链接蓝桥云课 - 0星际争霸
  • 数据规模 : 1 ≤ n ≤ 1000 1 \le n \le 1000 1≤n≤1000, 1 ≤ a i ≤ 10 1000 1 \le a_i \le 10^{1000} 1≤ai≤101000(包含前导零,保留原格式输出)
  • 核心问题 :给定 n n n 个数字字符串,按照以下三级优先级 进行升序排序:
    1. 第一优先级:字符串内部的"逆序对"数量(较小的排前面)。
    2. 第二优先级:逆序对相同时,按照数值大小排序(即字符串长度较短的排前面)。
    3. 第三优先级:长度相同时,按照字典序从小到大排序。

🔍 核心思路解析

1. 内部逆序对的计算

对于长度为 L L L 的字符串 S S S,统计内部所有满足 i < j i < j i<j 且 S i > S j Si > Sj Si>Sj 的字符对数量。

  • 由于字符串长度 L ≤ 1000 L \le 1000 L≤1000,采用双重循环遍历的复杂度为 O ( L 2 ) \mathcal{O}(L^2) O(L2)。
  • 1000 2 / 2 = 5 × 10 5 1000^2 / 2 = 5 \times 10^5 10002/2=5×105 次比较,运行耗时极短,完全不会超时。

2. 多关键字自定义排序规则(避坑关键)

当逆序对数量相同时,需要按数值大小排序。因为题目数据规模高达 10 1000 10^{1000} 101000,必须使用字符串存储:

  • 不能直接比较字典序 :例如字符串 "9""10",如果仅使用字典序比较,"10" < "9" 会得出错误结论;必须先比较字符串长度 ,长度短的数值小("9" 长度为 1,"10" 长度为 2)。
  • 排序三步走
    逆序对 r e v ⟶ 字符串长度 s i z e ( ) ⟶ 字典序 v a l \text{逆序对 } rev \longrightarrow \text{字符串长度 } size() \longrightarrow \text{字典序 } val 逆序对 rev⟶字符串长度 size()⟶字典序 val

💻 C++ 完整 AC 代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

// 存储结构体
struct W {
    string val; // 原始字符串
    long long rev; // 内部逆序对数量
};

// 1. 计算单个字符串内部的逆序对数量
long long d_count(const string& a) {
    long long cnt = 0;
    int n = a.size();
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (a[i] > a[j]) {
                cnt++;
            }
        }
    }
    return cnt;
}

// 2. 自定义多关键字排序规则
bool cmp(const W& w1, const W& w2) {
    // 优先级 1:逆序对数量升序
    if (w1.rev != w2.rev) {
        return w1.rev < w2.rev;
    }
    // 优先级 2:字符串长度升序(代表数值大小)
    if (w1.val.size() != w2.val.size()) {
        return w1.val.size() < w2.val.size();
    }
    // 优先级 3:长度相同时比字典序
    return w1.val < w2.val;
}

int main() {
    // 开启快速 I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    if (!(cin >> n)) return 0;

    vector<W> w(n);
    for (int i = 0; i < n; i++) {
        cin >> w[i].val;
        w[i].rev = d_count(w[i].val); // 预计算逆序对
    }

    // 排序
    sort(w.begin(), w.end(), cmp);

    // 输出
    for (int i = 0; i < n; i++) {
        cout << w[i].val << "\n";
    }

    return 0;
}

❌ 易错点总结

  • 漏掉"字符串长度"比较 :直接使用 w1.val < w2.val 会导致 "10" 排在 "9" 前面(字典序错误)。
  • 逆序对变量类型溢出 :当字符串长度达 1000 时,最大逆序对数可能达到 ≈ 5 × 10 5 \approx 5 \times 10^5 ≈5×105,累计总数虽不会溢出 int,但建议统一写成 long long 保证健壮性。

⏱️ 复杂度分析

  • 时间复杂度 : O ( n ⋅ L 2 + n log ⁡ n ⋅ L ) \mathcal{O}(n \cdot L^2 + n \log n \cdot L) O(n⋅L2+nlogn⋅L)
    • 预处理 :计算 n n n 个长度为 L L L 的字符串逆序对,耗时 O ( n ⋅ L 2 ) \mathcal{O}(n \cdot L^2) O(n⋅L2)。
    • 排序瓶颈 :排序比较共进行 O ( n log ⁡ n ) \mathcal{O}(n \log n) O(nlogn) 次,每次比较耗时 O ( L ) \mathcal{O}(L) O(L)。
    • 实际测试数据中,总运行时间控制在 20ms~160ms 之间,轻松 AC。
  • 空间复杂度 : O ( n ⋅ L ) \mathcal{O}(n \cdot L) O(n⋅L),用于存储 n n n 个长为 L L L 的字符串结构体数组。
相关推荐
洛阳纸贵2 分钟前
MATLAB-matlab基础知识
学习·算法·matlab
落羽的落羽7 分钟前
【AI】快速理解AI应用的相关名词概念
linux·c++·人工智能·python·计算机网络·算法
Nil20824 分钟前
leetcode 17电话号码的字母组合
算法·leetcode·职场和发展
203号居民2 小时前
LeetCode hot 100 — 25. K 个一组翻转链表
算法·leetcode·链表
ocean21033 小时前
2025-2026年AI算法与模型研发面试高频知识点洞察
人工智能·算法·面试
Nil2083 小时前
leetcode 78子集
数据结构·算法·leetcode
en.en..4 小时前
Linux fork() 工作原理
数据结构·算法
地平线开发者4 小时前
bevformer算法模型详细解读
算法
liliangcsdn5 小时前
ICIR权重矩阵如何加权标准化为综合因子
算法
SDWAN_Cheap5 小时前
SD-WAN智能选路技术的算法与实现机制
算法·php·sdwan