阿里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

相关推荐

03-06 18:20
门头沟学院 Java
点赞 评论 收藏
分享
评论
2
6
分享

创作者周榜

更多
正在热议
更多
# 春招至今,你的战绩如何? #
9937次浏览 92人参与
# 你的实习产出是真实的还是包装的? #
1793次浏览 41人参与
# 巨人网络春招 #
11307次浏览 223人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
7494次浏览 43人参与
# 简历第一个项目做什么 #
31591次浏览 332人参与
# 重来一次,我还会选择这个专业吗 #
433398次浏览 3926人参与
# MiniMax求职进展汇总 #
23895次浏览 308人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
187025次浏览 1122人参与
# 牛客AI文生图 #
21414次浏览 238人参与
# 不考虑薪资和职业,你最想做什么工作呢? #
152310次浏览 887人参与
# 研究所笔面经互助 #
118882次浏览 577人参与
# 简历中的项目经历要怎么写? #
310120次浏览 4197人参与
# AI时代,哪些岗位最容易被淘汰 #
63489次浏览 806人参与
# 面试紧张时你会有什么表现? #
30490次浏览 188人参与
# 你今年的平均薪资是多少? #
213034次浏览 1039人参与
# 你怎么看待AI面试 #
179917次浏览 1237人参与
# 高学历就一定能找到好工作吗? #
64317次浏览 620人参与
# 你最满意的offer薪资是哪家公司? #
76452次浏览 374人参与
# 我的求职精神状态 #
448008次浏览 3129人参与
# 正在春招的你,也参与了去年秋招吗? #
363299次浏览 2637人参与
# 腾讯音乐求职进展汇总 #
160600次浏览 1111人参与
# 校招笔试 #
470578次浏览 2964人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务