LeetCode 914 卡牌分组

深入剖析 LeetCode 914:卡牌分组问题

一、题目详情

给定一副卡牌,每张卡牌上都写有一个整数。我们要判断是否存在一个数字 X(X ≥ 2),能够把整副牌按照如下规则分成一组或者更多组:

  • 每组都有恰好 X 张卡牌。
  • 同一组内所有卡牌上的整数完全相同。

若满足上述条件,返回 true,否则返回 false

示例情况

  • 输入 [1,2,3,4,4,3,2,1],预期输出为 true。因为可以将其分成两组,每组各有 4 张卡牌。
  • 输入 [1,1,1,2,2,2,3,3],预期输出是 false。由于无法找到一个 X ≥ 2 来满足分组要求。

二、解题思路探索

核心思路

  1. 统计卡牌出现频次:先统计每一个数字在卡牌中出现的次数。

  2. 找出频次的最大公约数(GCD):求出所有非零频次的最大公约数。

  3. 判断是否满足条件 :若最大公约数大于或等于 2,就说明能够按照要求进行分组,返回 true;反之则返回 false

思路解析

  • 为什么采用 GCD 方法:假设所有数字的出现次数的最大公约数是 G,那么我们就可以把每组的卡牌数量设为 G。因为每个数字的出现次数都是 G 的倍数,所以能够保证每组有 G 张卡牌。例如,若某个数字出现了 4 次,另一个数字出现了 6 次,它们的 GCD 是 2,那么就可以将这两个数字分别分成 2 组,每组 2 张和 3 张。

  • 特殊情况处理 :当所有数字的出现次数都是 1 时,此时 GCD 为 1,无法满足分组条件,应返回 false

三、代码实现展示

Java 代码

java 复制代码
class Solution {
    public boolean hasGroupsSizeX(int[] deck) {
        // 利用数组统计每个数字的出现频次
        int[] count = new int[10000];
        for (int num : deck) {
            count[num]++;
        }
        
        int g = -1;
        // 遍历所有可能的数字,计算非零频次的 GCD
        for (int i = 0; i < 10000; i++) {
            if (count[i] > 0) {
                if (g == -1) {
                    g = count[i];
                } else {
                    g = gcd(g, count[i]);
                }
            }
        }
        
        // 当 GCD 大于等于 2 时返回 true,否则返回 false
        return g >= 2;
    }
    
    // 递归实现欧几里得算法来计算 GCD
    private int gcd(int x, int y) {
        return x == 0 ? y : gcd(y % x, x);
    }
}

代码说明

  1. 统计频次 :使用一个长度为 10000 的数组 count 来记录每个数字的出现次数。这里假设输入数字的范围在 0 - 9999 之间,在实际应用中,若输入范围不确定,可考虑使用哈希表。
  2. 计算 GCD :初始化 g 为 -1,遍历数组中的每个数字。对于非零频次的数字,使用欧几里得算法逐步计算它们的 GCD。
  3. 结果判断 :如果最终得到的 GCD 大于或等于 2,就返回 true,表示可以分组;否则返回 false

四、测试用例验证

测试代码

java 复制代码
public class Main {
    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] deck1 = {1, 2, 3, 4, 4, 3, 2, 1};
        int[] deck2 = {1, 1, 1, 2, 2, 2, 3, 3};
        
        System.out.println(solution.hasGroupsSizeX(deck1)); // 输出 true
        System.out.println(solution.hasGroupsSizeX(deck2)); // 输出 false
    }
}

测试结果分析

  • deck1 :各个数字的出现次数都是 2,它们的 GCD 是 2,满足分组条件,所以输出 true
  • deck2 :数字的出现次数分别为 3、3、2,它们的 GCD 是 1,不满足条件,因此输出 false

五、总结与拓展

总结

这道题的关键在于将分组问题巧妙地转化为求最大公约数的问题。通过统计频次并计算 GCD,能够高效地解决问题,其时间复杂度为 O (N),其中 N 是卡牌的数量。

拓展思考

  • 数据范围问题 :如果输入数字的范围较大,使用数组统计频次可能会占用较多内存,此时可以改用哈希表(如 HashMap<Integer, Integer>)。
  • GCD 计算的优化:在计算多个数的 GCD 时,可以逐个进行计算,避免一次性处理所有数据。
  • 类似问题:像 LeetCode 594《最长和谐子序列》也涉及到频次统计和数学运算,解题思路有一定的相似性。

希望这篇博客对你有所帮助!如果需要对内容进行调整,或者有其他问题,随时都能和我交流。 😊

相关推荐
To_OC7 小时前
LC 51 N 皇后:我以为难的是回溯,结果栽在了对角线下标
javascript·算法·leetcode
Scott9999HH7 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔7 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
2401_841495648 小时前
【操作系统】进程同步与互斥实验报告
c++·算法·操作系统·进程·并发·同步·互斥
码智社8 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海8 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖9 小时前
JDK 26 新特性详解
java·开发语言
马优晨10 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
醇氧10 小时前
CountDownLatch / CyclicBarrier / Semaphore 面试高频问答清单
前端·面试·职场和发展