劍指Offer - 撲克牌順子(Java實現)
阿新 • • 發佈:2019-01-14
題目描述:
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。簡直愚蠢!!!還得再接再厲!!!以上只是本人的思維總結,不足之處希望大家批評指正。