当前位置: 首页 > news >正文

排序题目:一手顺子

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:一手顺子

出处:846. 一手顺子

难度

5 级

题目描述

要求

Alice 手中有一把牌,她想要重新排列这些牌,分成若干组,使每一组的牌数都是 groupSize \texttt{groupSize} groupSize,并且由 groupSize \texttt{groupSize} groupSize 张连续的牌组成。

给定一个整数数组 hand \texttt{hand} hand,其中 hand[i] \texttt{hand[i]} hand[i] 是写在第 i \texttt{i} i 张牌上的值,和一个整数 groupSize \texttt{groupSize} groupSize。如果她可能重新排列这些牌,返回 true \texttt{true} true;否则,返回 false \texttt{false} false

示例

示例 1:

输入: hand = [1,2,3,6,2,3,4,7,8], groupSize = 3 \texttt{hand = [1,2,3,6,2,3,4,7,8], groupSize = 3} hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
输出: true \texttt{true} true
解释:Alice 手中的牌可以被重新排列为 [1,2,3],[2,3,4],[6,7,8] \texttt{[1,2,3],[2,3,4],[6,7,8]} [1,2,3],[2,3,4],[6,7,8]

示例 2:

输入: hand = [1,2,3,4,5], groupSize = 4 \texttt{hand = [1,2,3,4,5], groupSize = 4} hand = [1,2,3,4,5], groupSize = 4
输出: false \texttt{false} false
解释:Alice 手中的牌无法被重新排列成大小为 4 \texttt{4} 4 的组。

数据范围

  • 1 ≤ hand.length ≤ 10 4 \texttt{1} \le \texttt{hand.length} \le \texttt{10}^\texttt{4} 1hand.length104
  • 0 ≤ hand[i] ≤ 10 9 \texttt{0} \le \texttt{hand[i]} \le \texttt{10}^\texttt{9} 0hand[i]109
  • 1 ≤ groupSize ≤ hand.length \texttt{1} \le \texttt{groupSize} \le \texttt{hand.length} 1groupSizehand.length

解法

思路和算法

由于题目要求将数组 hand \textit{hand} hand 中的牌分成若干组,每组的牌数都是 groupSize \textit{groupSize} groupSize,因此只有当总牌数是 groupSize \textit{groupSize} groupSize 的倍数时才可能根据要求分组。如果总牌数不是 groupSize \textit{groupSize} groupSize 的倍数,则返回 false \text{false} false

当总牌数是 groupSize \textit{groupSize} groupSize 的倍数时,遍历数组 hand \textit{hand} hand 并使用哈希表记录每个值的出现次数,然后将数组 hand \textit{hand} hand 排序,遍历排序后的数组判断是否可以根据要求分组。

遍历排序后的数组的过程中,对于遍历到的每个元素 start \textit{start} start,如果 start \textit{start} start 在哈希表中记录的出现次数大于 0 0 0,则考虑以 start \textit{start} start 作为一个分组的最小值,判断剩余的牌是否可以组成 [ start , start + groupSize − 1 ] [\textit{start}, \textit{start} + \textit{groupSize} - 1] [start,start+groupSize1] 的分组。具体做法如下。

  1. start \textit{start} start start + groupSize − 1 \textit{start} + \textit{groupSize} - 1 start+groupSize1 的每个整数的计数都应该大于 0 0 0,如果该范围内存在一个整数的计数是 0 0 0,则无法组成 [ start , start + groupSize − 1 ] [\textit{start}, \textit{start} + \textit{groupSize} - 1] [start,start+groupSize1] 的分组,返回 false \text{false} false

  2. 对于从 start \textit{start} start start + groupSize − 1 \textit{start} + \textit{groupSize} - 1 start+groupSize1 的每个整数 val \textit{val} val,将 val \textit{val} val 在哈希表中的计数减 1 1 1

遍历结束之后,如果没有遇到不可以完成分组的情况,则返回 true \text{true} true

上述解法的正确性说明如下。

  1. 遍历排序后的数组的过程中,遍历元素的顺序是从小到大,因此当遍历到元素 start \textit{start} start 时,小于 start \textit{start} start 的元素都已经遍历过并完成分组, start \textit{start} start 是尚未分组的最小值, start \textit{start} start 一定是一个分组中的最小值。

  2. 由于已知 start \textit{start} start 一定是一个分组中的最小值,因此该分组的取值范围是 [ start , start + groupSize − 1 ] [\textit{start}, \textit{start} + \textit{groupSize} - 1] [start,start+groupSize1],只有当该范围内的每个值都存在时才可能完成分组。

代码

class Solution {public boolean isNStraightHand(int[] hand, int groupSize) {int length = hand.length;if (length % groupSize != 0) {return false;}Map<Integer, Integer> counts = new HashMap<Integer, Integer>();for (int val : hand) {counts.put(val, counts.getOrDefault(val, 0) + 1);}Arrays.sort(hand);for (int i = 0; i < length; i++) {int start = hand[i];if (!counts.containsKey(start)) {continue;}for (int j = 0; j < groupSize; j++) {int val = start + j;if (!counts.containsKey(val)) {return false;}counts.put(val, counts.get(val) - 1);if (counts.get(val) == 0) {counts.remove(val);}}}return true;}
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 hand \textit{hand} hand 的长度。排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间,遍历数组更新哈希表需要 O ( n ) O(n) O(n) 的时间,时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 hand \textit{hand} hand 的长度。需要使用哈希表记录每个值的出现次数,哈希表的空间是 O ( n ) O(n) O(n),排序需要 O ( log ⁡ n ) O(\log n) O(logn) 的递归调用栈空间,空间复杂度是 O ( n ) O(n) O(n)


http://www.mrgr.cn/news/25410.html

相关文章:

  • 【办公】会议纪要模板
  • OJ 两两交换链表中的节点
  • MySQL之库和表操作
  • Python容器一之字符串
  • 好看好听的小猪包扩音器,轻巧便携更好用,得胜E10上手
  • 批量插入insert到SQLServer数据库,BigDecimal精度丢失解决办法,不动代码,从驱动层面解决
  • 干部画像系统是什么?
  • 卫生间漏水原因很多,切莫病急乱投医
  • 直播电商平台如何合理分账给供应商/主播
  • 基于SpringBoot的准妈妈孕期交流平台
  • 开源模型应用落地-qwen2-7b-instruct-LoRA微调-unsloth(让微调起飞)-单机单卡-V100(十六)
  • Vue3使用Websocket进行跨页面通信
  • Vue路由的分类与使用
  • 缓存预热/雪崩/穿透/击穿
  • 牛客小白月赛99(下)
  • Shell脚本-拆分文件并重命名(性能测试)
  • 记一次幸运的漏洞挖掘
  • 植物三萜皂苷生物合成途径及调控机制研究进展-文献精读48
  • 【数据结构-一维差分】力扣1893. 检查是否区域内所有整数都被覆盖
  • Linux和C语言(Day 12)