剑指Offer - 扑克牌顺子(Java实现)

题目描述:

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。

思路分析:
开始时候的思路,先排序数组,然后统计0的个数,然后再按照0出现的次数分别处理数组。本题的主要时间复杂度在于排序数组上。
原始代码实现如下:

//初步想法,根据0的个数来判断数组
//先排序,然后统计0的个数
//还得考虑重复的情况
//总和一下,判断的条件就是数组的相邻两个数的间隔之和不能大于4
import java.util.Arrays;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        
        if(numbers == null || numbers.length < 5 ){
            return false;
        }
        //先排序
        boolean flag = true;
        Arrays.sort(numbers);
        int numzero = 0;//记录0的个数
        int sum = 0 ; //记录间隔的和
        int length = numbers.length;
        for(int i = 0 ; i < length ; i++){
            if(numbers[i] == 0){
                numzero++;
            }
            if(numbers[i]>0){//排序后的数组,大于0后面肯定不会再次出现0了。
                break;
            }
        }
        //0的个数最多为四个,所以当抽到四个0的时候,肯定是没有问题的
        //当没0的时候就需要判断数组是否是连续的了
        if( numzero == 0){
            //遍历数组,判断是否连续
            for(int i = 1 ; i < length ; i++){
                //当相邻两个数间隔大于1的时候,判定为false;
                if(numbers[i]-numbers[i-1]>1){
                    flag = false;
                    break;
                }
                if(numbers[i] == numbers[i-1]){//去重
                       return false;
                   }
            }
        }else if(numzero == 1){
            //当数组中只有一个0的时候,数组中相邻两个数间隔之和不能大于4
            for(int i = 2 ; i < length ; i++){
                sum+=numbers[i]-numbers[i-1];
                if(numbers[i] == numbers[i-1]){
                       return false;
                   }
            }
            if(sum > 4){
                flag = false;
            }
        }else if(numzero == 2){
            //当数组中有两个0的时候,这时候需要判断余下的三个数的间隔之和不能大于4
               for(int i = 3 ; i < length ; i++){
                   sum+=numbers[i]-numbers[i-1];
                   if(numbers[i] == numbers[i-1]){//去重
                       return false;
                   }
               }
            if(sum > 4){
                flag = false;
            }
        }else if(numzero == 3){
            //当存在三个0的时候,剩余的两个数的差值不能大于4
            for(int i = 4 ; i < length ; i++){
                   sum+=numbers[i]-numbers[i-1];
                   if(numbers[i] == numbers[i-1]){//去重
                       return false;
                   }
               }
            if(sum > 4){
                flag = false;
            }
        }else{
            //存在四个0的时候,肯定能组成连续数字
            flag = true;
        }
        return flag;
    }
}

改进一:
然后发现每次判断0的时候,for循环的起始位置不就是0的个数+1么,那我为什么还要分别判断,直接缩写成一个表达式不就行了,开始的时候简直愚蠢。改进的代码实现如下:

import java.util.Arrays;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        
        if(numbers == null || numbers.length < 5 ){
            return false;
        }
        //先排序
        boolean flag = true;
        Arrays.sort(numbers);
        int numzero = 0;//记录0的个数
        int sum = 0 ; //记录间隔的和
        int length = numbers.length;
        for(int i = 0 ; i < length ; i++){
            if(numbers[i] == 0){
                numzero++;
            }
            if(numbers[i]>0){//排序后的数组,大于0后面肯定不会再次出现0了。
                break;
            }
        }
        //记录非0的间隔类和
        for(int i = numzero+1 ; i < length ; i++){
                sum+=numbers[i]-numbers[i-1];
                if(numbers[i] == numbers[i-1]){
                       return false;
                   }
            }
            if(sum > 4){
                flag = false;
            }
        
        return flag;
    }
}

改进二:
这时候又想到,间隔累和不就是最大值和最小值之间的差值么,那我为什么还要累加,这不是脱裤子放屁多此一举么,又犯傻了!!!改进的代码实现如下:

import java.util.Arrays;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        //先判空
        if(numbers == null || numbers.length < 5 ){
            return false;
        }
        //先排序
        boolean flag = true;
        Arrays.sort(numbers);
        int numzero = 0;//记录0的个数
        int interval = 0 ; //记录最大值和最小值的差值
        int length = numbers.length;
        for(int i = 0 ; i < length ; i++){
            if(numbers[i] == 0){
                numzero++;
            }
            if(numbers[i]>0){//排序后的数组,大于0后面肯定不会再次出现0了。
                break;
            }
        }
        //遍历数组的非零元素,判断是否有重复的数字。
        for(int i = numzero+1 ; i < length ; i++){
            if(numbers[i] == numbers[i-1]){
                return false;
            }
        }
        //非零数值,最大最小值不能超过4,否则一定不可能组成顺子 
        interval = numbers[length-1]-numbers[numzero];
        if( interval > 4){
            flag = false;
        }
        return flag;
    }
}

经过一系列的改进,代码最终变得稍微简洁明了,开始写的时候有点犯傻,疯狂写if else。简直愚蠢!!!还得再接再厉!!!以上只是本人的思维总结,不足之处希望大家批评指正。

猜你喜欢

转载自blog.csdn.net/justlikeu777/article/details/85931302