Day45:扑克牌顺子

时间:2022-07-24
本文章向大家介绍Day45:扑克牌顺子,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

剑指Offer_编程题——扑克牌顺子

题目描述:

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

具体要求:

时间限制: C/C++ 1秒,其他语言2秒 空间限制: C/C++32M,其他语言64M

具体实现:

思路一:   这个题可以先把整数数组排序,然后由于左端可能是大小王,所以右端开始往左判断。首尾各一个指针,当尾部指针的值比它左面的值恰好大1的情况下。不需要大小王,如果差值比1大的话,左端恰好有一个大小王的话,则把当前的尾部指针向后移一个位置。也就是用掉一个王,这样知道首尾指针相等的情况下,则该这幅牌就是顺子,如果不是顺子的话早就返回了。具体用java实现如下:

import java.util.*;
public class Solution{
	public boolean isContinuous(int []numbers){
		if(numbers.length <= 1)
			return false;
		Arrays.sort(numbers);
		int begin = 0;
		int end = numbers.length - 1;
		boolean flag = false;
		while(begin < end){
			if(numbers[end] - numbers[end - 1] == 1)
				end--;
			else{
				if(numbers[begin] == 0){
					begin++;
					numbers[end]--;
				}else
					break;
			}
		}
		if(begin == end)
			return true;
		return flag;
	}
}

代码效果图如图所示:

思路二:   接下来给大家介绍一种判断五个数字是否为连续的经典方法。最直观的就是把数组排序。值得注意的是:由于0可以当做任意的数字,我们可以用0区补充数组的空缺,如果排序之后的数组不是连续的。即相邻的两个数字相隔若干个数字,但只要我们有足够的0可以补满这两个数字的空缺,这个数字实际上还是连续的。例如:数组排序之后为{0,1,3,4,5},在1和3之间空缺了一个2,刚好我们有一个0,也就是我们可以把它当成2去填补这个空缺。因此我们还需要做以下几件是事:首先把数组排序,在统计数组中0的个数,最后统计排序之后的数组中相邻数字之间的空缺总数。如果空缺的总数小于或者等于0的个数,那么这个数组就是连续的,反之则不连续。另外,我们需要注意的是,如果数组中的非0数字重复出现,则该数组不是连续的。换成扑克牌的描述方式就是如果一副牌里含有对子,则肯定不是顺子。具体我们用java以及python两种语言将其实现: 1、首先我们用java实现以上思路:

import java.util.Arrays;
public class Solution{
	public boolean isContinuous(int []numbers){
		if(numbers == null || numbers.length == 0)
			return false;
		Arrays.sort(numbers);
		int numberOfZero = 0;
		int numberOfGap = 0;
		for(int i = 0; i < numbers.length && numbers[i] == 0; i++){
			numberOfZero++;
		}
		int low = numberOfZero;
		int high = low + 1;
		while(high < numbers.length){
			if(numbers[low] == numbers[high])
				return false;
			numberOfGap += numbers[high] - numbers[low] - 1;
			low = high;
			high++;
		}
			return numberOfGap <= numberOfZero ? true:false;
	}
}

代码效果图如图所示:

2、接下来我们用python将其实现:

class Solution:
	def IsContinuous(self, numbers):
		if not numbers:
			return False
		numbers.sort()
		zeros = numbers.count(0)
		gaps = 0
		small = zeros
		big = small + 1
		while big < len(numbers):
			if numbers[small] == numbers[big]:
				return False
			gaps += numbers[big] - numbers[small] - 1
			small = big
			big += 1
		return gaps <= zeros

代码效果图如图所示:

  在这里需要注意的是:代码中为什么是numbers[big] - numbers[small] - 1。因为0是来填补空缺的,如果空缺是1则不用填补。这个做法是我们看出不等于1的空缺有多少。 思路三:   在以上思路的基础上,我们首先对排序数组,然后统计数组中0的个数,最后就是统计排序后数组中相邻数字之间的空缺总数。如果空缺的总数小于或者等于0的个数,那么数组就是连续的,反之不连续。接下来我们用python将其实现:

class Solution:
	def IsContinuous(self, numbers):
		if not numbers:
			return False
		numbers.sort()
		zeros = 0
		pre = None
		for num in numbers:
			if num == 0:
				zeros += 1
			if not pre:
				pre = num
			elif num == pre:
				return False
			else:
				diff = num - pre - 1
				zeros -= diff
				pre = num
			if zeros < 0:
				return False
		return True 

代码效果图如图所示:

思路四:   统计数组中最大值和最小值,0的个数和非0数字的个数。如果最大值和最小值之间的空位可以被0和剩余非0数字填满,则数组是连续的,否则不连续。我们用python将其实现:

class Solution:
	def IsContinuous(self, numbers):
		if not numbers:
			return False
		zeros, maxi, mini = 0, -1, 14
		counts = 0
		exist = set()
		for num in numbers:
			if num == 0:
				zeros += 1
				continue
			if num in exist:
				return False
			if num > maxi:
				maxi = num
			if num < mini:
				mini = num
			counts += 1
			exist.add(num)
		return maxi - mini + 1 - counts <= zeros

代码效果图如图所示:

总结

  本道题通过与上一道题类似,均是通过实际问题来考察我们对字符串的理解,我们对本题给出了四种解题思路,均分别用java和python将其实现。首先就是正常的思路解题。其次给大家介绍了一种很常用的思路。最后是统计数组中最大值和最小值,0的个数和非0数字的个数。如果最大值和最小值之间的空位可以被0和剩余非0数字填满,则数组是连续的,否则不连续。因此,我们在做题的时候,应该多次尝试各种方法,扩展自己的思维,写出优质的代码。总之,我们要继续加油,争取早日找到工作,Good Luck!!!

参考文献

[1] 扑克牌顺子 [2] qq_27668313 [3] 负雪明烛