请教一个关于扑克牌顺子的算法问题

2018-09-12 10:52:55 +08:00
 orqzsf1

算法的问题:从扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这 5 张牌是连续的,JQK 用 11、12、13 表示。(不考虑大小王和花色

我的思路是:

  1. 判断是否重复,重复则一定不是顺子
  2. (最大的数字)-(最小的数字)!= 4 则不是
  3. 是顺子

这里有一个问题。。没有考虑特殊情况 10JQKA。

请教一下,应该如何判断这个特殊的边界问题比较好?

4807 次点击
所在节点    算法
24 条回复
whileFalse
2018-09-12 11:07:44 +08:00
所以到底是要做什么?有什么资源限制?
tux
2018-09-12 11:28:28 +08:00
那就把 A 替换成 14
xubeiyan
2018-09-12 11:32:01 +08:00
不考虑花色的话,顺子一共的牌型才 10 种( A2345-10JQKA ),检查在不在这 10 种排型里面就是了
princelai
2018-09-12 11:37:26 +08:00
判断两次,(sum%5==0 and max-min==4) or (sum==47 and max-min==12),我随便写的,没验证过
Bryan0Z
2018-09-12 11:47:47 +08:00
这有啥难的,先排序,然后,A2345678910JQKA 顺着比较就行了
moresteam
2018-09-12 11:50:06 +08:00
直接穷举可不可以呢
xenme
2018-09-12 11:52:49 +08:00
sort,然后逐个检查就行了。
这么简单的问题。

又不是让你排一百万,限制你的算法复杂度啥的。
dongxiaozhuo
2018-09-12 14:06:34 +08:00
随便瞎猜的:
把 A 换成 14。顺子就是等差为 1 的等差数列。上限为 5 张,遍历一次拿到最大值,最小值,同时计算数列的和 (sum) 。然后用等差数列的公式,用最大值、最小值、count、等差值算出理论值,与数列的和对比,如果相等,就是顺子,如果不相等,就不是顺子。

时间上是一次遍历,很短,同时没有排序。空间上使用 5 个变量:最大值、最小值、和、等差数列和、长度。
orqzsf1
2018-09-12 14:09:50 +08:00
@tux A 换成 14,那 12345 呢,142345 这样?
orqzsf1
2018-09-12 14:10:19 +08:00
@moresteam 穷举当然可以,看看有没有更好的解法
orqzsf1
2018-09-12 14:11:34 +08:00
@dongxiaozhuo 把 A 换成 14,12345 这样情况怎么处理?
orqzsf1
2018-09-12 14:12:30 +08:00
@Bryan0Z 能否详细说下如何顺着比较?
mbtfdwlx
2018-09-12 14:20:47 +08:00
我也推荐 7L 的做法。同时,把 A 的牌换成 14。再 check 一次。 首先这样做肯定算法时间复杂度是最高的。但是好处也多
1.易读性强。其他人读你的算法一读就知道是干嘛的。
2.兼容性更强。你要判断 5 张牌 差是 4。如果后续开发需要判断 3 张牌呢?是不是要多传一个参数?所以逐一排查就更方便。
3.优化空间更大。排序的算法可以在顺子算法之外做。只要保证传进的数组是有序的就可以。所以不需要每次都在判断顺子的函数内排序。
mbtfdwlx
2018-09-12 14:23:16 +08:00
补充一下 不如 A78910 五张牌,先 check 1 78910。再 check78910 14 只要一个满足条件就是顺子 没有 A 的牌只需要检查一次
orange1818
2018-09-12 14:29:08 +08:00
function checkShunzi(arr, min, max) { //思路圆环
arr = arr.sort();
if (isShunNum(arr)) {
return true;
}
//如果不是 123456 这种,而是 9012 这种,那么剩余的 345678 是 shunNum,就判断剩余的号码是不是 shunNum
const restArr = [];
for (let i = min; i < max; i++) {
if (arr.indexOf(i) === -1) {
restArr.push(i);
}
}

return isShunNum(arr);

function isShunNum(arr) {
return arr.every(function (item, index, arr) {
return 0 === index || item - 1 === arr[index - 1];
})
}
}
dongxiaozhuo
2018-09-12 14:30:40 +08:00
@orqzsf1

给 A 一个特殊属性,遇到 A 的时候,开启特殊计算,需要分别计算 1 和 14 的情况。

我理解,如果是扑克牌游戏的话,以后是 5 张,还是 10 张很难说。用 7L 的排序也可以,简单明了一些。
tux
2018-09-12 14:41:26 +08:00
@orqzsf1 A 换成 14,换之前判断一次,换之后再判断一次,2 种情况其实都是顺子吧?
mangoDB
2018-09-12 14:42:32 +08:00
> 设有 N 张牌,长度为 N 的数组模拟一个 [首尾相连] 的 [环] 。
1. 每次取 X 张牌( X<N ),然后分别在环上对应节点进行标记。
2. 遍历整个环,当 gap 数等于 2 时,X 张牌为顺子。
orqzsf1
2018-09-12 14:58:08 +08:00
@mbtfdwlx 明白了,感谢!
dongxiaozhuo
2018-09-12 15:26:37 +08:00
@mangoDB 首尾相连的环,有一个问题是,会出现 [11, 12, 13, A, 2] 和 [12,13,A,2,3] 这样的顺子,看起来不一定预期想要的结果吧?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/488446

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX