LintCode 1672. 扑克牌

该博客介绍了LintCode算法题1672,内容关于如何解决帮助QW用最少次数出完手中扑克牌的问题。QW可以按三种方式出牌:单张、相同点数的多张或点数连续的五张以上。博客提供了样例输入和期望输出,并提及了问题的分析及JAVA代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述
QW是一名打牌小能手,现在他手里有n张牌,给定数组cards表示QW牌的点数,牌的点数范围为1~9,他想要用尽量少的次数把牌出完,请输出QW最少出牌次数
QW有以下三种出牌方式:
1.打出任意一张牌
2.打出两张及以上相同点数的牌
3.打出至少5张点数连续的牌(2,3,4,5,6是合法的而3,3,4,5,6,7是不合法的)

样例
给定cards=[2,2,2,3,4,5,7,1],返回3

**解释:**
1.打出1,2,3,4,5
2.打出2,2
3.打出7

给定cards=[1,2,3,4,5,5,6,7,8,9],返回2

**解释:**
1.打出1,2,3,4,5
2.打出5,6,7,8,9

分析:

使用DFS+贪心。
容易知道,最终的结果肯定是在排除连续的牌基础上进行计算的,首先把连续的牌进行DFS求解。

JAVA代码:

 private int min;
 public int getAns(int[] cards) {
    int[] newCards = new int[9];
    for (int card : cards)
        newCards[card - 1]++;
    min = newCards.length;
    dfs(newCards, 0);
    return min;
}

private void dfs(int[] cards, int sum) {
    boolean flag = cards[4] == 0;
	int index1 = 0, index2 = 8;
	for (int i = 3; i >= 0; i--) 
		if (cards[i] == 0) {
			index1 = i;
			break;
		}
	for (int i = 5; i < 9; i++) 
		if (cards[i] == 0) {
			index2 = i;
			break;
		}
	if (flag || !flag && (index2 - index1) <= 5) {
		int res = 0;
		for (int i = 0; i < cards.length; i++)
			if (cards[i] != 0)
				res++;
		min = Math.min(min, res + sum);
		return;
	}
    A:
    for (int i = 0; i < 5; i++) {
        int j = i, count = 0;
        for (; j < cards.length; j++) {
            if (cards[j] == 0 && j - i < 5)
                continue A;
            if (cards[j] == 0) {
                count = j - i;
            } else if (j == cards.length - 1)
                count = j - i + 1;
        }
        while (count != 4) {
            for (int k = i; k < i + count; k++)
                cards[k]--;
            dfs(cards, 1 + sum);
            for (int k = i; k < i + count; k++)
                cards[k]++;
            count--;
        }
    }
}

拓展:

一般情况下,数字长度可以任意并且顺子情况牌的数量可以任意

JAVA代码:

private static int min;

//partOfCount表示能构成顺子的最少数量,count表示一共有多少种牌(1,2,3,4,5,6,7.......100......)
public static int getAns(int[] cards, int count, int partOfCount) {
    int[] newCards = new int[count];
    for (int card : cards)
        newCards[card - 1]++;
    min = newCards.length;
    dfs(newCards, 0, partOfCount);
    return min;
}

private static void dfs(int[] cards, int sum, int partOfCount) {
	/*
    //dp分析最大构成的顺子长度
    int[] dp = new int[cards.length];
    dp[0] = cards[0] == 0 ? 0 : 1;
    int max = 0;
    for (int i = 1; i < cards.length; i++) {
        dp[i] = cards[i] == 0 ? 0 : dp[i - 1] + 1;
        max = Math.max(max, dp[i]);
        if (max >= partOfCount)
            break;
    }
    */
    int start = 0, end = 0;
    for (int i = 0; i < cards.length; i++) {
        if (cards[i] == 0) {
            start = i;
            end = i;
        } else
            end = i;
        if (end - start >= partOfCount)
            break;
    }
    if (end-start < partOfCount) {
        int res = 0;
        for (int i = 0; i < cards.length; i++)
            if (cards[i] != 0)
                res++;
        min = Math.min(min, res + sum);
        return;
    }
    A:
    for (int i = 0; i <= cards.length - partOfCount; i++) {
        int j = i, count = 0;
        for (; j < cards.length; j++) {
            if (cards[j] == 0 && j - i < partOfCount)
                continue A;
            if (cards[j] == 0) {
                count = j - i;
                break;
            } else if (j == cards.length - 1)
                count = j - i + 1;
        }
        while (count != partOfCount - 1) {
            for (int k = i; k < i + count; k++)
                cards[k]--;
            dfs(cards, 1 + sum, partOfCount);
            for (int k = i; k < i + count; k++)
                cards[k]++;
            count--;
        }
    }
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值