剑指 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] .
思路一:set + 遍历
遍历数组,把所有非0元素都添加到set集合中,如果发现集合中已存在,说明存在重复元素,可以直接返回false, 因为存在重复元素不可能构成顺子。在遍历元素的过程中记录数组中非0元素的最大值和非0元素的最小值。最后使用最大值减去最小值,判断结果是否小于5, 如果小于5说明加上大小王之后可以构成顺子,否则不行
1 class Solution { 2 public boolean isStraight(int[] nums) { 3 HashSet<Integer> set = new HashSet<>(); 4 int min = 1 << 30, max = -1 << 30; 5 for(int i = 0; i < 5; i++){ 6 if(nums[i] == 0){ 7 continue; 8 } 9 min = Math.min(nums[i], min); 10 max = Math.max(nums[i], max); 11 if(set.contains(nums[i])){ 12 return false; // 如果存在重复元素,直接返回false 13 } 14 set.add(nums[i]); 15 } 16 17 return max - min < 5; 18 } 19 }
leetcode 运行时间为1ms - 91.22%, 空间为36.8MB - 5.12%
复杂度分析:
时间复杂度:遍历数组,所以时间复杂度为O(n), 但是因为这个 n 恒定为5, 所以时间复杂度其实为O(1)
空间复杂度:额外的空间就是set的大小,最大为O(n), 但是因为这个 n 恒定为5, 所以时间复杂度其实为O(1)
思路二:排序 + 遍历
先对数组进行排序,然后统计前4个数字中0的个数和数组中是否存在重复元素,如果存在重复元素则不可能构成顺子,直接返回false, 因为大小王只有两个,所以最多只有两个0,所以0的个数肯定可以统计正确。
最后用判断 nums[4] - nums[zeroCount] 是否小于5, nums[4]是非0元素中的最大值,nums[zeroCount]是非0元素中的最小值,如果小于5说明加上大小王之后可以构成顺子,否则不行
1 class Solution { 2 public boolean isStraight(int[] nums) { 3 // 对数组进行排序 4 Arrays.sort(nums); 5 // 先统计0的个数 6 int zeroCount = 0; 7 // 遍历数组,统计0的个数,并判断是否存在重复元素,如果存在,直接返回false 8 // 只需遍历前4个数即可 9 for(int i = 0; i < 4; i++){ 10 if(nums[i] == 0){ 11 zeroCount++; 12 }else if(nums[i] == nums[i+1]){ 13 return false; 14 } 15 } 16 return nums[4] - nums[zeroCount] < 5; 17 } 18 }
leetcode运行时间为1ms - 91.22%, 空间为36.4MB - 58.39%
复杂度分析:
时间复杂度:时间主要花在排序上,复杂度为O(nlogn), 但是因为这个 n 恒定为5, 所以时间复杂度其实为O(1)
空间复杂度: O(1)
其实两种算法的实现思路是一样的,都是先去除重复元素不能构成顺子的情况,后面在统计最大值和最小值的差值是否小于5,如果小于5,可以构成顺子,否则不行