剑指Offer_#61_扑克牌中的顺子
Contents
题目
从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
示例 1:
输入: [1,2,3,4,5]
输出: True
示例 2:
输入: [0,0,1,2,5]
输出: True
限制:
数组长度为 5
数组的数取值为 [0, 13] .
思路分析
顺子的判断方法
一个连续的数组是否是顺子,需要满足两个条件。
条件1:没有重复牌
除了0之外,5个数字当中没有对子,即没有相同的两个牌。
条件2:0可以补齐缺失的牌
- 0的个数 ≥ 间隔的个数。间隔指的是连续数字中缺失的那些数字,这些数字可以由0来补齐。
max - min <= 4
- 如果最大值和最小值差距大于4,那么连续数组的长度一定大于5,但是输入数组只有5个数字,那么必定存在漏掉的数字,不可能是连续的。
- 对于连续的5个数字,最大值和最小值之间刚好相差4。最大值和最小值差距小于4时,
[min...max]
之间的数字个数少于5个,min和max之外剩下的数字只有可能是0或者min
和max
之间的数,一定可以构成一个连续数组。
方法1:比较0的个数与间隔个数
- 排序,0必然出现在最前面
- 遍历数组,统计间隔的数量及0的数量
- 遍历过程中发现相同的数,直接返回false
- 比较0的个数和间隔的个数,0的个数如果大于等于间隔的个数,返回true,否则返回false
方法2:HashSet方法
max - min <= 4
,如果是5张连续牌,最大与最小牌的差距最多到4。即需要统计最大牌和最小牌,通过循环遍历实现。这个方法避免了统计缺失的数字,还有0的个数。- 出现对子,直接返回false。所以需要判别重复。想到用Set数据结构,可以最快的找出重复,避免了排序。
Set<Integer> set = new HashSet<>();
解答
解答1:比较0的个数和间隔的个数
class Solution {
public boolean isStraight(int[] nums) {
//1.排序,0必然出现在最前面
Arrays.sort(nums);
int numberOfZero = 0;
int numberOfGap = 0;
//2.遍历数组,统计间隔的数量及0的数量
for(int i = 0;i <= 4;i++){
if(nums[i] == 0) numberOfZero++;
}
for(int i = numberOfZero;i <= 3;i++){
//出现一对相同数,不可能是顺子
if(nums[i] == nums[i + 1]) return false;
numberOfGap += nums[i+1] - nums[i] - 1;
}
return numberOfZero >= numberOfGap;
}
}
复杂度分析
时间复杂度:O(nlogn),排序的复杂度是O(nlogn)
空间复杂度:O(1)
解答2:利用HashSet判断重复
class Solution {
public boolean isStraight(int[] nums) {
Set<Integer> set = new HashSet<>();
//注意max和min的初始化,max要初始化为比最小值1还小的0,min要初始化为比最大的13还大的14
//目的是:进入循环后,一开始就会更新
int max = 0;
int min = 14;
for(int i = 0;i <= 4;i++){
//0不统计在内
if(nums[i] == 0) continue;
//更新最大值和最小值
max = Math.max(max, nums[i]);
min = Math.min(min, nums[i]);
if(set.contains(nums[i])) return false;
set.add(nums[i]);
}
return max - min <= 4;
}
}
复杂度分析
时间复杂度:O(n)
空间复杂度:O(n)