【字符串】剑指 Offer 61. 扑克牌中的顺子

题目:

从扑克牌中随机抽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] .

解答:

方法一:

找到不等于0的最小数字,如果是顺子,一定是从这个最小数字开始,以1为单位递增的数字序列。数字0代表大小王,可以替代任意数字,统计nums中0的个数并放入计数器cnt。遍历从最小数字开始的连续5个整数,看他们是否在给定数组nums中出现了,没出现则 --cnt;完成后如果cnt>=0则说明是顺子。

时间复杂度:O(n)

空间复杂度:O(n)

class Solution {
    public boolean isStraight(int[] nums) {

        Set<Integer> set = new HashSet<>();
        int min =nums[0],cnt = 0;
        for(int i:nums){
            if(min == 0 && i!=0) min = i;
            if(min>i && i!= 0) min = i;
            if(i == 0) cnt++;
            set.add(i);
        }
        
        for(int i = 1;i<=4;i++){
            if(!set.contains(min+i)) cnt--;
        }

        
        return cnt>=0;
    }
}

方法二:集合+遍历

思路:除大小王以外,最大值-最小值<5,则可构成顺子

时间复杂度:O(n)

空间复杂度:O(n)

class Solution {
    public boolean isStraight(int[] nums) {
        Set<Integer> repeat = new HashSet<>();
        int max = 0, min = 14;
        for(int num : nums) {
            if(num == 0) continue; // 跳过大小王
            max = Math.max(max, num); // 最大牌
            min = Math.min(min, num); // 最小牌
            if(repeat.contains(num)) return false; // 若有重复,提前返回 false
            repeat.add(num); // 添加此牌至 Set
        }
        return max - min < 5; // 最大牌 - 最小牌 < 5 则可构成顺子
    }
}

方法三: 排序+ 遍历

时间复杂度:O(nlogn)

空间复杂度:O(1)

class Solution {
    public boolean isStraight(int[] nums) {
        int joker = 0;
        Arrays.sort(nums); // 数组排序
        for(int i = 0; i < 4; i++) {
            if(nums[i] == 0) joker++; // 统计大小王数量
            else if(nums[i] == nums[i + 1]) return false; // 若有重复,提前返回 false
        }
        return nums[4] - nums[joker] < 5; // 最大牌 - 最小牌 < 5 则可构成顺子
    }
}

方法二和方法三的关键点:除大小王以外,最大值-最小值<5,则可构成顺子

 

posted @ 2020-08-02 17:10  3KBLACK  阅读(119)  评论(0)    收藏  举报