题目:扑克牌的顺子
从扑克牌中随机抽出5张牌,判断是不是一个顺子,即这五张牌是不是连续的。2——10为数字本身,A为1,J为11,Q为12,K为13,而大小王为任意数字。
算法分析:
我们需要把扑克牌的背景抽象成计算机语言。不难想象,我们可以把五张牌看成由五个数字组成的数组。大小王是特殊的数字,我们不妨把他们定义为0,这样就能和其他牌区分开来了。
接下来我们分析判断5个数字是不是连续的,最直观的方法是把数组排序。值得注意的是,由于0可以当成任意的数字,我们可以用0去补满数组中的空缺。如果排序之后的数组不是连续的,即相邻的两个数字像个若干个数字,但只要我们有足够的0可以补满这两个空缺的数字,这个数组实际上还是连续的。举个例子,数组排序之后为{0,1,3,4,5},在1和3之间空缺一个2,刚好我们有一个0,也就是我们可以把它当成2去填补这个空缺。
于是我们需要做3件事:首先把数组排序,再统计数组中0的个数,最后统计排序之后数组中相邻的数字之间的空缺总数。如果空缺综述小于或者等于0的个数,那么这个数组就是连续的;反之则不连续。
最后我们还需要注意一点:如果数组中的非0数字反复出现,则该数组不是连续的。换成扑克牌的描述方式就是如果一副牌里含有对子,则不可能是顺子。
代码:
import java.util.Arrays;
public class Offer44 {
public boolean isContinuous(int [] numbers){
if(numbers == null || numbers.length<1)
return false;
Arrays.sort(numbers);//这里也可以用其他的排序算法
int numberOfZero = 0;
int numberOfGap = 0;
//统计数组中0 个数
for(int i = 0;i<numbers.length&& numbers[i]==0;i++)
numberOfZero++;
//统计数组中的间隔数目
int small = numberOfZero;
int big = small +1;
while(big<numbers.length){
//两个数字相等,有对子,不可能是顺子
if(numbers[small] == numbers[big])
return false;
numberOfGap += numbers[big] - numbers[small] -1;
small = big;
big++;
}
return (numberOfGap > numberOfZero) ? false:true;
}
public static void main(String[] args) {
Offer44 of44 = new Offer44();
//功能测试,1,抽出的牌中有一个大小王
int [] num1 = {1,3,4,7,0};
System.out.println(of44.isContinuous(num1));
//功能测试,2,抽出的牌中有2个大小王
int [] num2 = {1,0,4,5,0};
System.out.println(of44.isContinuous(num2));
//功能测试,3,抽出的牌中没有大小王
int [] num3 = {1,3,4,5,6};
System.out.println(of44.isContinuous(num3));
//功能测试,4,抽出的牌中有对子
int [] num4 = {1,3,3,5,4};
System.out.println(of44.isContinuous(num4));
//特殊输入测试 ,输入NULL指针
int [] num5 = null;
System.out.println(of44.isContinuous(num5));
}
}
运行结果:
false
true
false
false
false