阿里3.20 面试题一

有一叠扑克牌,每张牌介于1和10之间
有四种出牌方法:
  1. 单出1张
  2. 出2张对子
  3. 出五张顺子,如12345
  4. 出三连对子,如112233
给10个数,表示1-10每种牌有几张,问最少要多少次能出完


思路:

        根据剩余牌数, 找出最长可行的出牌方法, 若相同出牌方法有不同的组合, 则分别计算每种组合所对应的解, 取最小的解

        当最长可行解为一张牌时, 出牌次数等于已出的次数加上剩余牌的个数

        分别计算相同出牌方法的不同组合时, 必须在进行下一次计算时恢复当前计算所改变的每种牌的张数及剩余牌数和已出牌数状态


代码如下:
import java.util.Arrays;
import java.util.Scanner;

public class Poke {
    /**
     * 有一叠扑克牌,每张牌介于1和10之间
     * 有四种出牌方法:
     * 单出1张
     * 出2张对子
     * 出五张顺子,如12345
     * 出三连对子,如112233
     * 给10个数,表示1-10每种牌有几张,问最少要多少次能出完
     */
    
    public static int res = Integer.MAX_VALUE;
    
    public static void main(String[] args) {
    
        int remain = 7;
        int[] nums = {2, 1, 1, 1, 1, 1, 0, 0, 0, 0};
        
//        第一行输入共有多少张牌, 第二行输入每一种牌的张数,
        Scanner sc = new Scanner(System.in);
        remain = sc.nextInt();
        for (int i = 0; i < 10; i++) {
            nums[i] = sc.nextInt();
        }
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
        }
//        System.out.println(sum);
//        System.out.println(remain);
        if (sum != remain) {
            System.out.println("输入错误!");
            return;
        }
        
        for (int i = 1; i < 11; i++) {
            System.out.print(i + " ");
        }
        dfs(remain, 0, nums);
        System.out.println("最少出牌次数为: " + res);
    }
    
    public static void dfs(int remain, int cnt, int[] nums) {
        
        if (remain == 0) {
            System.out.println("本次出牌次数为: " + cnt);
            res = cnt < res ? cnt : res;
            return;
        }
        System.out.println();
        boolean flag = false;
        int[] tempNums = Arrays.copyOf(nums, 10);
        int tempCnt = cnt;
        int tempRemain = remain;

//      判断剩余牌数
        if (remain >= 6) {

//            判断是否可以出连对
            for (int k = 0; k < 8; k++) {
                if (nums[k] >= 2) {
                    if (nums[k + 1] >= 2 && nums[k + 2] >= 2) {
//                        可以出连对
                        nums[k] -= 2;
                        nums[k + 1] -= 2;
                        nums[k + 2] -= 2;
                        System.out.printf("第%d次: 可以出连对: 两个%d, 两个%d, 两个%d\n\n", cnt + 1, k + 1, k + 2, k + 3);
                        print(nums);
                        cnt += 1;
                        remain -= 6;
                        dfs(remain, cnt, nums);
//                        状态恢复
                        cnt = tempCnt;
                        remain = tempRemain;
                        nums = Arrays.copyOf(tempNums, 10);
                        flag = true;
                    }
                }
            }
            if (flag) return;
        }
        
        if (remain >= 5) {
//            判断是否可以出顺子
            for (int k = 0; k < 6; k++) {
                if (nums[k] >= 1 && nums[k + 1] >= 1 && nums[k + 2] >= 1 && nums[k + 3] >= 1 && nums[k + 4] >= 1) {
//                        可以出连对
                    nums[k]--;
                    nums[k + 1]--;
                    nums[k + 2]--;
                    nums[k + 3]--;
                    nums[k + 4]--;
                    System.out.printf("第%d次: 可以出顺子: %d, %d, %d, %d, %d\n\n", cnt + 1, k + 1, k + 2, k + 3, k + 4, k + 5);
                    print(nums);
                    cnt += 1;
                    remain -= 5;
                    dfs(remain, cnt, nums);
//                        状态恢复
                    cnt = tempCnt;
                    remain = tempRemain;
                    nums = Arrays.copyOf(tempNums, 10);
                    System.out.println("状态恢复");
                    flag = true;
                }
            }
            if (flag) return;
        }
        if (remain >= 2) {
//            判断是否可以出对子
            for (int i = 0; i < nums.length; i++) {
                if (nums[i] >= 2) {
                    nums[i] -= 2;
                    System.out.printf("第%d次: 可以出对子: 对%d\n\n", cnt + 1, i + 1);
                    print(nums);
                    cnt++;
                    remain -= 2;
                    dfs(remain, cnt, nums);
//                              状态恢复
                    cnt = tempCnt;
                    remain = tempRemain;
                    nums = Arrays.copyOf(tempNums, 10);
                    flag = true;
                }
            }
            if (flag) return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) {
                nums[i]--;
                System.out.printf("第%d次: 只能单走一张%d\n\n", cnt + 1, i + 1);
                print(nums);
                cnt++;
                remain--;
            }
        }
        //        只能单走一张, 如果只能单走一张牌的时候, 那剩下的出牌可能就是剩余牌数, remain为0, cnt += nums[i] != 0 的元素个数
        dfs(remain, cnt, nums);
    }
    
    private static void print(int[] nums2) {
        for (int i : nums2) {
            System.out.print(i + " ");
        }
        System.out.println();
        for (int i = 1; i < 11; i++) {
            System.out.print(i + " ");
        }
        System.out.println('\n');
    }
}
	
        


#阿里2020暑期实习春招##阿里巴巴##面试题目#
全部评论
如果是 1,1,2,3,4,5,6,七张牌。 那么按照你的代码,会打出12345,1,6.,打三次。 而实际上应该打,对1,23456,打两次。
1 回复 分享
发布于 2020-03-20 22:21
ac了吗
点赞 回复 分享
发布于 2020-03-20 21:24

相关推荐

蚂蚁 基架java (n+6)*16 签字费若干
点赞 评论 收藏
分享
挣K存W养DOG:他真的很中意你,为什么不回他
点赞 评论 收藏
分享
11-24 00:11
已编辑
广东工业大学 算法工程师
避雷深圳&nbsp;&nbsp;yidao,试用期&nbsp;6&nbsp;个月。好嘛,试用期还没结束,就直接告诉你尽快找下一家吧,我谢谢您嘞
牛客75408465号:笑死,直属领导和 hr 口径都没统一,各自说了一些离谱的被裁理由,你们能不能认真一点呀,哈哈哈哈哈😅😅😅
点赞 评论 收藏
分享
评论
2
5
分享
牛客网
牛客企业服务