题目描述
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--;
}
}
}