算法题 最大数

LeetCode 179. 最大数

问题描述

给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。注意:结果可能非常大,需返回字符串形式。

示例

输入: [10,2]
输出: "210"

输入: [3,30,34,5,9]
输出: "9534330"

算法思路

核心:自定义排序

  1. 问题本质:比较两个数字不同拼接顺序的结果大小
  2. 关键策略:定义比较规则 (a, b) -> (b + a).compareTo(a + b)
    • b+a > a+b,则 b 应排在 a
  3. 处理前导零:若排序后首位为 ‘0’,则直接返回 “0”

代码实现

class Solution {
    public String largestNumber(int[] nums) {
        // 将整数数组转换为字符串数组
        String[] numStrs = new String[nums.length];
        for (int i = 0; i < nums.length; i++) {
            numStrs[i] = String.valueOf(nums[i]);
        }
        
        // 自定义排序:比较拼接后的字典序
        Arrays.sort(numStrs, (a, b) -> {
            String order1 = b + a; // b在前a在后的组合
            String order2 = a + b; // a在前b在后的组合
            return order1.compareTo(order2); // 降序排列
        });
        
        // 处理全零情况
        if (numStrs[0].equals("0")) {
            return "0";
        }
        
        // 拼接结果字符串
        StringBuilder sb = new StringBuilder();
        for (String s : numStrs) {
            sb.append(s);
        }
        return sb.toString();
    }
}

算法分析

  • 时间复杂度O(n log n)
    排序主导时间复杂度(字符串比较 O(k),k 为字符串长度)
  • 空间复杂度O(n)
    存储字符串数组

算法过程

输入 [3,30,34,5,9]

  1. 转换为字符串["3","30","34","5","9"]
  2. 自定义排序
    • 比较 “9” 和 “5”:"95" vs "59""95">"59" → “9” 排在 “5” 前
    • 比较 “5” 和 “34”:"534" vs "345""534">"345" → “5” 排在 “34” 前
    • 比较 “34” 和 “3”:"343" vs "334""343">"334" → “34” 排在 “3” 前
    • 比较 “3” 和 “30”:"330" vs "303""330">"303" → “3” 排在 “30” 前
  3. 排序结果["9","5","34","3","30"]
  4. 拼接字符串"9534330"

测试用例

public static void main(String[] args) {
    Solution solution = new Solution();
    
    // 测试用例1:标准示例
    int[] nums1 = {10,2};
    System.out.println("Test 1: " + solution.largestNumber(nums1)); // "210"
    
    // 测试用例2:含前缀相同的数字
    int[] nums2 = {3,30,34,5,9};
    System.out.println("Test 2: " + solution.largestNumber(nums2)); // "9534330"
    
    // 测试用例3:全零数组
    int[] nums3 = {0,0,0,0};
    System.out.println("Test 3: " + solution.largestNumber(nums3)); // "0"
    
    // 测试用例4:单个元素
    int[] nums4 = {1};
    System.out.println("Test 4: " + solution.largestNumber(nums4)); // "1"
    
    // 测试用例5:大数组合
    int[] nums5 = {999999998,999999997,999999999};
    System.out.println("Test 5: " + solution.largestNumber(nums5)); // "999999999999999998999999997"
    
    // 测试用例6:含0的非全零数组
    int[] nums6 = {10,0,2};
    System.out.println("Test 6: " + solution.largestNumber(nums6)); // "2100"
    
    // 测试用例7:易错案例
    int[] nums7 = {34323,3432}; // 34323+3432=343233432 < 3432+34323=343234323
    System.out.println("Test 7: " + solution.largestNumber(nums7)); // "343234323"
}

关键点

  1. 比较规则设计

    • 核心:(b+a).compareTo(a+b) 实现降序排列
    • 证明:若 a+b > b+aa 应排在 b
  2. 前导零处理

    • 仅需检查排序后首位(若首位为 ‘0’ 则必全零)
    • 避免输出 “00…0” 非法格式
  3. 大数处理

    • 直接操作字符串避免数值溢出
    • 字符串比较按字典序(与数值序一致)

常见问题

1. 为什么不用数值比较?
拼接后数值可能超 long 范围(如 [999999998,999999997,999999999])。

2. 比较规则如何保证正确性?
传递性证明:若 a≻b(即 a+b>b+a)且 b≻c,则 a≻c
反例:a=3,b=32,c=321

  • 3+32="332">"323"=32+3a≻b
  • 32+321="32321">"32132"=321+32b≻c
  • 3+321="3321">"3213"=321+3a≻c
    本例满足传递性

3. 时间复杂度是否过高?

  • 字符串比较 O(k)(k 为数字字符串平均长度)
  • 总复杂度 O(nk log n),k ≤ 10,实际效率接近 O(n log n)

4. 如何验证极端案例?
测试用例7展示:343233432 比较

  • 34323+3432="343233432"
  • 3432+34323="343234323"
  • 字典序比较:"343234323" > "343233432"
    3432 应排在 34323
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值