算法--2016搜狐面试:搜狐员工放假了,都玩什么?
扎金花這種小游戲,我想作為一名程序員。大部分小時候都玩過吧!現在我們一起來看看搜狐這道面試題吧!看看如何用代碼實現扎金花。
Q題目
事因
兩個搜狐的程序員加了一個月班,終于放假了,于是他們決定扎金花渡過愉快的假期 。游戲規則:
共52張普通牌,牌面為2,3,4,5,6,7,8,9,10,J,Q,K,A之一,大小遞增,各四張; 每人抓三張牌。兩人比較手中三張牌大小,大的人獲勝。
對于牌型的規則如下:
1.三張牌一樣即為豹子
2.三張牌相連為順子(A23不算順子)
3.有且僅有兩張牌一樣為對子 豹子>順子>對子>普通牌型 在牌型一樣時,比較牌型數值大小(如AAA>KKK,QAK>534,QQ2>10104) 在二人均無特殊牌型時,依次比較三張牌中最大的。大的人獲勝,如果最大的牌一樣,則比較第二大,以此類推(如37K>89Q) 如二人牌面相同,則為平局。
輸入描述:
輸入兩個字符串代表兩個玩家的牌(如”10KQ” “354”), 先輸入的作為玩家1,后輸入的作為玩家2輸出描述:
1 代表 玩家1贏 0 代表 平局 -1 代表 玩家2贏 -2 代表不合法的輸入輸入例子:
KQ3 3Q9 10QA 6102 5810 7KK 632 74J 10102 K77 JKJ 926 68K 27A輸出例子:
1 1 -1 -1 1 1 -1A解法
1.邏輯分析
(1)拿到玩家1和2輸入的字符串,判斷是否合法
(2)合法后,拆分字符串為字符串數組
(3)將字符串數組轉化為int數組,并排序
(4)判斷3張牌的相等情況
(5)比較大小,誰輸誰贏
2.難點分析
存在10時,字符串的拆分問題:可以根據字符串長度來判斷拆分
將字母轉為數字:先將拿到的字符串都轉為大寫,這樣小寫和大寫字母都一樣了,然后直接用if判斷return就可以了
比較誰輸誰贏:采用從大到小的方式比較,先判斷是否有豹子,在判斷順子,再判斷對子,最后判斷無牌型的
對順子的處理問題
3.代碼實現
package 搜狐面試2016;import java.util.Arrays; import java.util.Scanner;public class Test1 {public static void main(String[] args) {// 2,3,4,5,6,7,8,9,10,J,Q,K,AScanner scanner = new Scanner(System.in);boolean isContinue=true;while (isContinue) {//1.游戲規則System.out.println("游戲規則:共52張普通牌,牌面為2,3,4,5,6,7,8,9,10,J,Q,K,A之一,大小遞增,各四張; 每人抓三張牌。兩人比較手中三張牌大小,大的人獲勝。");System.out.println("對于牌型的規則如下:");System.out.println("1.三張牌一樣即為豹子");System.out.println("2.三張牌相連為順子(A23不算順子)");System.out.println("3.有且僅有兩張牌一樣為對子 豹子>順子>對子>普通牌型 在牌型一樣時,比較牌型數值大小");System.out.println("誰輸誰贏:1 --代表玩家1贏;0 --代表 平局 ;-1 --代表玩家2贏 ;-2 --代表不合法的輸入");//2.分別出牌System.out.println("請玩家1出牌:");String num1 = scanner.next();System.out.println("請玩家2出牌:");String num2 = scanner.next();//3.判斷是否合法boolean flag=isValid(num1, num2);if(!flag){//不合法System.out.println("-2");}else {//輸入合法---先拆分字符串---再轉化為int數組//4.拆分字符串String[] nums1=getStrArray(num1);String[] nums2=getStrArray(num2);System.out.println("拆分后的字符串數組A:"+Arrays.toString(nums1));System.out.println("拆分后的字符串數組B:"+Arrays.toString(nums2));//5.轉化為int數組int[] nums11=strToNumber(nums1);int[] nums22=strToNumber(nums2);System.out.println("轉化為int后的數組A:"+Arrays.toString(nums11));System.out.println("轉化為int后的數組B:"+Arrays.toString(nums22));//6.獲得三張牌的相等情況int[] equalNum11=equalNum(nums11);int[] equalNum22=equalNum(nums22);System.out.println("三張牌的相等情況--數組A:"+Arrays.toString(equalNum11));System.out.println("三張牌的相等情況--數組B:"+Arrays.toString(equalNum22));//7.判斷輸贏int whoWin=whoWin(equalNum11, nums11, equalNum22, nums22);System.out.println(""+whoWin);}//是否繼續System.out.println("是否繼續?輸入N或n退出,其他任意鍵繼續!");String string = scanner.next();string=string.toUpperCase();if("N".equals(string)){isContinue=false;}}}/*1.判斷輸入的內容是否合法* 不合法兩種情況:(1)出現的字符不是2,3,4,5,6,7,8,9,10,J,Q,K,A(2)每種牌只有4張,超過4張則不合法了*方法說明:*該方法只處理情況(1),情況(2)放在判斷輸贏的時候處理,因為第二種情況涉及牌面轉化后計算的問題*/public static boolean isValid(String num1, String num2) {String reg = "([2-9JQKA]|10){3}";// 正則匹配,只能出現2,3,4,5,6,7,8,9,10,J,Q,K,A,并且一共只能出現3次boolean a = num1.matches(reg);boolean b = num2.matches(reg);// 有一方不合法就返回falseif (a == false || b == false) {return false;} else {// 都合法return true;}}// 1.拆分字符串,得到三個數字public static String[] getStrArray(String num) {// 字符串的長度和拆分后的數組int length = num.length();String[] nums = new String[3];// 無論輸入的J,Q,K,A是否為大寫,都改為大寫num.toUpperCase();// 字符串不含10時,長度都為3if (length == 3) {// nums=num.split("");//使用該方法拆分會多出一個空格位--比如33a-->[,3,3,1]for (int i = 0; i < nums.length; i++) {nums[i] = num.substring(i, i + 1);}} else if (length == 4) {// 字符串含一個10int index = num.indexOf("1");// 10在首位:10XXif (index == 0) {nums[0] = "10";nums[1] = num.substring(2, 3);nums[2] = num.substring(3);} else if (index == 1) {// 10在中位:X10Xnums[0] = num.substring(0, 1);nums[1] = "10";nums[2] = num.substring(3);} else {// 10在末位:XX10nums[0] = num.substring(0, 1);nums[1] = num.substring(1, 2);nums[2] = "10";}} else if (length == 5) {// 字符串2個10----1010X 或 10X10 或 X1010int first = num.indexOf("1");// 第一個10int second = num.lastIndexOf("1");// 第二個10int cha = second - first;// 兩個1距離大于2時,說明X在中間if (cha > 2) {nums[0] = nums[2] = "10";nums[1] = num.substring(2, 3);} else {// 兩個1距離等于2時,說明兩個10是挨在一起的if (first == 0) {nums[0] = nums[1] = "10";nums[2] = num.substring(4);} else {nums[0] = num.substring(0, 1);nums[1] = nums[2] = "10";}}} else {// 字符串為3個10for (int i = 0; i < nums.length; i++) {nums[i] = "10";}}return nums;}// 2.將字符串數組轉為int數組public static int[] strToNumber(String[] nums) {int[] arr = new int[3];for (int i = 0; i < nums.length; i++) {arr[i] = letterToNumber(nums[i]);}Arrays.sort(arr);return arr;}/** 3.比較拆分后的三個數字相等情況,并返回數組--[參數1,參數2] * * 參數1:數字相同的個數;* 參數2:若有相同數字,參數2表示相同的是哪個數字;-------此時參數2只可能為2-14中的一個 * 若沒有相同數字--參數2表示是否有順子--有順子為1,沒順子為0----此時參數2只可能是0或1* * 例如: * 若有兩個相同,則返回[2,相同的數字]; * 若三個都相同,則返回[3,相同的數字];* 若三個數字都不同,且不是順子,則返回[0,0];若是順子則返回[0,1]*/public static int[] equalNum(int[] nums) {int[] arr = new int[2];// 判斷相等的個數if (nums[0] == nums[1] && nums[0] == nums[2]) {// 三個數相等arr[0] = 3;arr[1] = nums[0];} else if (nums[0] != nums[1] && nums[0] != nums[2] && nums[1] != nums[2]) {// 三個數均不相等--此時有一個順子的問題要處理arr[0] = 0;// 因為A23不算順子,所以只能出現2-14間的順子,即234,345,...,121314// 此時相鄰兩個數差為1if (nums[1] - nums[0] == 1 && nums[2] - nums[1] == 1) {// 為順子arr[1] = 1;} else {arr[1] = 0;}} else {// 兩個數相等arr[0] = 2;// 若數組中兩個數差值為0,說明就是這個數為對子if(nums[0]-nums[1]==0){arr[1]=nums[0];}else if (nums[0]-nums[2]==0) {arr[1]=nums[0];}else {arr[1]=nums[2];}}return arr;}/** 4.判斷誰輸誰贏 參數說明:a,primaryA--玩家1 b,primaryB--玩家2* * 參數a,b:判斷數字相等情況后返回的數組----即方法isEqual()處理后的結果* 參數primaryA,primaryB:原始數組(備注:轉化為int后的數組---即方法strToNumber()處理后的結果)* * * 備注:該方法太長,可以將豹子,順子,對子,普通牌型分別提取為一個方法* 那么需要再創建一個方法用于判斷玩家1和2的牌中出現是豹子,順子,對子,普通牌型中的哪一種* 將返回值做為if的條件,再分別去調用對應的豹子,順子,對子,普通牌型方法* * 因為這樣方法太多,筆者就不單獨提出來封裝了*/public static int whoWin(int[] a, int[] primaryA, int[] b, int[] primaryB) {// 1)判斷是否為豹子if (a[0] == 3 && b[0] == 3) {// 都是豹子則比大小if (a[1] > b[1]) {return 1;} else if (a[1] < b[1]) {return -1;} else {// 玩家1和2豹子相同是不可能的,每種牌只有4張return -2;}} else if (a[0] == 3 && b[0] != 3) {// 只有玩家1是豹子--處理可能出現5張相同牌的情況--需要判斷玩家2是否有對子,有,那么是否與豹子是相同的牌// 玩家2有對子,并且與玩家1的豹子牌面相同if (b[0] == 2 && a[1] == b[1]) {return -2;}return 1;} else if (a[0] != 3 && b[0] == 3) {// 只有玩家2是豹子--同理上面// 玩家1有對子,并且與玩家2的豹子牌面相同if (a[0] == 2 && a[1] == b[1]) {return -2;}return -1;} else {// 2)都沒豹子,判斷是否為順子--利用非順子時a[1]和b[1]不可能出現1,只會為2-14if (a[1] == 1 && b[1] == 1) {// 都為順子,則比大小--因為是順子,所以比較第一個數值即可if (primaryA[0] > primaryB[0]) {return 1;} else if (primaryA[0] < primaryB[0]) {return -1;} else {return 0;}} else if (a[1] == 1 && b[1] != 1) {// 只有玩家1是順子return 1;} else if (a[1] != 1 && b[1] == 1) {// 只有玩家2是順子return -1;} else {// 3)都不是順子,判斷是否有對子if (a[0] == 2 && b[0] == 2) {// 都有對對子,則比大小if (a[1] > b[1]) {return 1;} else if (a[1] < b[1]) {return -1;} else {// 對子相同,則比較單個的那個數int thirdA = 0;// 玩家1,單獨的牌int thirdB = 0;// 玩家2,單獨的牌for (int i = 0; i < primaryA.length; i++) {if (primaryA[i] != a[1]) {thirdA = primaryA[i];}if (primaryB[i] != b[1]) {thirdB = primaryB[i];}}// 比較單個數字if (thirdA > thirdB) {return 1;} else if (thirdA < thirdB) {return -1;} else {return 0;}}} else if (a[0] == 2 && b[0] != 2) {// 只有玩家1有對子return 1;} else if (a[0] != 2 && b[0] == 2) {// 只有玩家2有對子return -1;} else {// 4)都沒豹子,順子,對子,直接比大小if (primaryA[2] > primaryB[2]) {return 1;} else if (primaryA[2] < primaryB[2]) {return -1;} else {// 最大值相等,比較第二大的if (primaryA[1] > primaryB[1]) {return 1;} else if (primaryA[1] < primaryB[1]) {return -1;} else {// 最大值和第二大值都相等if (primaryA[0] > primaryB[0]) {return 1;} else if (primaryA[0] < primaryB[0]) {return -1;} else {return 0;}}}}}}}// 5.將字符轉為數字----------將非數字的J,Q,K,A轉換為數字11,12,13,14--并將本身數字的字符串轉為int類型public static int letterToNumber(String letter) {if (letter.equals("J")) {return 11;} else if (letter.equals("Q")) {return 12;} else if (letter.equals("K")) {return 13;} else if (letter.equals("A")) {return 14;}return Integer.parseInt(letter);} }運行測試
長度不合法
單個牌6出現了5次,不合法
豹子
順子和對子
都是字母,順子和對子
出現10,兩個順子
都無牌型,直接比大小
總結
以上是生活随笔為你收集整理的算法--2016搜狐面试:搜狐员工放假了,都玩什么?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法--组合数学:杨辉三角数学分析以及J
- 下一篇: Eclipse常用快捷