1. 程式人生 > >劍指Offer - 撲克牌順子(Java實現)

劍指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。簡直愚蠢!!!還得再接再厲!!!以上只是本人的思維總結,不足之處希望大家批評指正。