Last active
August 29, 2015 13:57
-
-
Save finscn/9744730 to your computer and use it in GitHub Desktop.
检测 两组任意(不限个数 不限花色) 的扑克牌, 混到一起后能否构成任意长度(大于1 小于15)的顺子.A代表1或14,小王代表1--5,大王代表1--14
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
检测 两组任意(不限个数 不限花色) 的扑克牌, 混到一起后能否构成任意长度(大于1 小于15)的顺子. | |
A可表示1或14,小王可表示1--5,大王可表示1--14 | |
说明: | |
1 我微博里说 小王代表 1到9有误, 我这边实际遇到的场景是 小王代表 1--5 (当然 这个无所谓) | |
2 牌是可以有重复的 : 例如 可以 4个小王 9个大王 等等, 可以理解为是从无数副扑克牌当中随意抽取出两组 | |
3 组成的顺子 可以不是5张 , 其实严格说 就是 等差为1的等差数列 | |
4 能且只能组成一组顺子, 组成顺子后, 牌没有剩余 | |
*/ | |
// cards 结构: [ {point:牌面点数, num:对应数值}, .... ] | |
function checkSequence(cards1, cards2) { | |
var totalCount = cards1.length + cards2.length; | |
//总牌数>14, 必然无法构成等差数列 | |
if (totalCount > 14) { | |
return false; | |
} | |
var allCards = []; // 普通数字牌对应数组 | |
var countA = 0; // A数量 | |
var countRedJoker = 0; // 大王数量 | |
var countBlackJoker = 0; // 小王数量 | |
var _cards = cards1; | |
while (true) { | |
_cards.forEach(function(card) { | |
// 记录 A 大王 小王的个数 | |
if (card.point == "A") { | |
countA++; | |
} else if (card.point == "RED_JOKER") { | |
countRedJoker++; | |
} else if (card.point == "BLACK_JOKER") { | |
countBlackJoker++; | |
} else { | |
// 把普通数字牌混为一组 | |
allCards.push(card); | |
} | |
}); | |
if (_cards == cards2) { | |
break; | |
} | |
_cards = cards2; | |
} | |
// A大于2个 或者 虽然A等于2个,但总牌数小于14, 则必然无法构成等差数列 | |
if (countA > 2 || countA == 2 && totalCount < 14) { | |
return false | |
} | |
// 对普通数字牌排序 | |
allCards.sort(function(a, b) { | |
return a.num - b.num; | |
}); | |
var ANA, AN, NA; | |
if (countA == 2) { | |
//如果有两个A, 那么一个A当做1 放到最前面, 另一个A当做14, 放到后面 | |
ANA = [{ | |
point: "A", | |
num: 1 | |
}].concat(allCards).concat([{ | |
point: "A", | |
num: 14 | |
}]); | |
} else if (countA == 1) { | |
// 只有一个A 时, 把A放前面测一次, 放后面再测一次, 这样做代码上简单, 但是性能肯定不好 | |
AN = [{ | |
point: "A", | |
num: 1 | |
}].concat(allCards); | |
NA = [].concat(allCards).concat({ | |
point: "A", | |
num: 14 | |
}); | |
} | |
if (ANA) { | |
return _checkQueue(ANA, countRedJoker, countBlackJoker); | |
} else if (AN) { | |
return _checkQueue(AN, countRedJoker, countBlackJoker) || _checkQueue(NA, countRedJoker, countBlackJoker); | |
} else { | |
return _checkQueue(allCards, countRedJoker, countBlackJoker); | |
} | |
} | |
function _checkQueue(cardList, countRedJoker, countBlackJoker) { | |
console.log(cardList) | |
console.log(countRedJoker) | |
console.log(countBlackJoker) | |
// 小王代表的最大数 | |
var blackJokerMax = 5; | |
var prevNum = cardList[0].num; | |
for (var i = 1; i < cardList.length; ) { | |
var currentNum = cardList[i].num; | |
if (prevNum === currentNum) { | |
// 有重复的牌, 不是等差数列 | |
return false; | |
} | |
var useJoker = false | |
// 如果两张相邻牌的差不是1, 尝试用王补位 | |
if (prevNum + 1 != currentNum) { | |
//blackJokerMax之后的, 用大王补位 | |
if (prevNum + 1 > blackJokerMax) { | |
if (countRedJoker > 0) { | |
countRedJoker--; | |
useJoker = true; | |
} else { | |
return false; | |
} | |
} else { | |
//blackJokerMax或之前的, 有小王, 优先用小王补位 | |
if (countBlackJoker > 0) { | |
countBlackJoker--; | |
useJoker = true; | |
} else if (countRedJoker > 0) { | |
//blackJokerMax或之前的, 没有小王 尝试用大王补位 | |
countRedJoker--; | |
useJoker = true; | |
} else { | |
// 没有王, 则无法构成等差数列 | |
return false; | |
} | |
} | |
} | |
if (useJoker) { | |
//如果用王补过位, 则做相应的处理 | |
prevNum += 1; | |
} else { | |
prevNum = currentNum; | |
i++; | |
} | |
} | |
var firstNum = cardList[0].num; | |
var lastNum = cardList[cardList.length - 1].num; | |
// 此时队列中间部分已经排列好, 剩余的小王只能往前分配, 大王可能往前 可能往后 | |
// 剩余小王数大于队列前端能分配的最大数量, 则不是等差数列 | |
if (countBlackJoker >= firstNum) { | |
return false | |
} | |
// 如果有未分配的小王 | |
if (countBlackJoker > 0) { | |
// 如果此时数列最小值>blackJokerMax+1, 则小王不能直接分配到数列前面,需要先用若干个大王来补位 | |
if (firstNum > blackJokerMax + 1) { | |
//有大王 用大王补位,否则返回false | |
if (countRedJoker >= firstNum - (blackJokerMax + 1)) { | |
countRedJoker -= firstNum - (blackJokerMax + 1); | |
firstNum = blackJokerMax + 1; | |
} else { | |
return false; | |
} | |
} | |
// 分配所有剩余的小王 因为前面的一些预判断, 下面两行代码总是能得到预期结果的 | |
firstNum -= countBlackJoker; | |
countBlackJoker = 0; | |
} | |
// 至此, 小王全部分配完毕 | |
// 如果有未分配的大王 | |
if (countRedJoker > 0) { | |
// 优先尝试往后分配,且尽可能多的分配 | |
if (lastNum < 14) { | |
countRedJoker -= (14 - lastNum); | |
} | |
// 如果还有未分配的 大王, 且队列前面已经装不下了, 返回false | |
if (countRedJoker >= firstNum) { | |
return false; | |
} | |
countRedJoker = 0; | |
} | |
//如果大小王都分配完毕, 则符合等差数列 | |
if (countBlackJoker == 0 && countRedJoker == 0) { | |
return true; | |
} | |
return false; | |
} | |
//////////////////////////////////// | |
//////////////////////////////////// | |
//////////////////////////////////// | |
//////////////////////////////////// | |
// 以下为测试用例 | |
// 定义常量 | |
// 牌面点数 : 对应数值 | |
var Card = { | |
"2": 2, | |
"3": 3, | |
"4": 4, | |
"5": 5, | |
"6": 6, | |
"7": 7, | |
"8": 8, | |
"9": 9, | |
"10": 10, | |
"J": 11, | |
"Q": 12, | |
"K": 13, | |
"A": null, | |
"RED_JOKER": null, | |
"BLACK_JOKER": null, | |
}; | |
function test(c1, c2) { | |
var cards1 = [], | |
cards2 = []; | |
c1.forEach(function(c) { | |
cards1.push({ | |
point: c, | |
num: Card[c] | |
}) | |
}); | |
c2.forEach(function(c) { | |
cards2.push({ | |
point: c, | |
num: Card[c] | |
}) | |
}); | |
console.log(checkSequence(cards1, cards2)); | |
} | |
// 返回 true | |
test([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3,8]) | |
// 返回 false | |
test(["BLACK_JOKER", "BLACK_JOKER"], ["RED_JOKER", "RED_JOKER", 8, 9,10,"J","Q","A"]) |
@finscn 你那位朋友的代码里面totalCount没定义,最后几行有个地方的true 写成了ture。
var _Count = {
A: [1, 14],
BLACK_JOKER: [1, 2, 3, 4, 5],
RED_JOKER: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
};
function check(card1, card2) {
var cards = card1.concat(card2);
if (cards.length > 14)
return false;
var list = new Array(14);
var A = 0;
var BLACK_JOKER = 0;
var RED_JOKER = 0;
for (var x = 0; x < cards.length; x++) {
var index = new Number(cards[x]);
if (isNaN(index))
eval(cards[x] + "+=1");
else
if (list[index - 1] == null)
list[index - 1] = true;
else
return false;
}
function checkQueue() {
function insert(array) {
var min = 15;
var index = 0;
for (var x in array) {
if (list[array[array.length - 1 - x] - 1] != null)
continue;
for (var i = 1; i < 15; i++) {
if (i == 14 && min == 15) {
index = array[array.length - 1 - x] - 1;
min = i;
break;
}
if (list[array[array.length - 1 - x] - 1 - i] != null && list[array[array.length - 1 - x] - 1 + i] != null) {
index = array[array.length - 1 - x] - 1;
min = -1;
break;
}
if (list[array[array.length - 1 - x] - 1 - i] != null || list[array[array.length - 1 - x] - 1 + i] != null) {
if (i < min) {
index = array[array.length - 1 - x] - 1;
min = i;
break;
}
}
}
}
if (min == 15)
return false;
list[index] = true;
return true;
}
for (var i = 0; i < A; i++)
if (!insert(_Count.A))
return false;
for (var i = 0; i < BLACK_JOKER; i++)
if (!insert(_Count.BLACK_JOKER))
return false;
for (var i = 0; i < RED_JOKER; i++)
if (!insert(_Count.RED_JOKER))
return false;
var t = null;
for (var x in list)
if (t != null && t != x - 1)
return false;
else
t = x;
return true;
}
return checkQueue();
}
document.writeln(check([4, 6, 8, 9, 10, 2, 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER', 'RED_JOKER'])); // true
document.writeln(check(['A', 2, 3, 4, 5, 6], [7, 8, 9, 'BLACK_JOKER', 'RED_JOKER'])); //fail, 小王没地方放
document.writeln(check([12, 13], ['BLACK_JOKER'])); //false, 小王与12和13连不上
document.writeln(check(['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER'])); // 超过了5个小王,第六个放不下
document.writeln(check(['BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER'])); // success
document.writeln(check(['A', 5, 'A', 7], [8, 10, 'BLACK_JOKER', 'RED_JOKER'])); // fail
document.writeln(check(['A', 'A', 'A', 6, 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'RED_JOKER'])); // fail
document.writeln(check([3, 4, 5, 6, 7, 8, 9], [10])); // success
document.writeln(check(['A', 4], ['BLACK_JOKER'])); // fail
document.writeln(check(['A', 12], [13])); // success
document.writeln(check(['A', 2, 3, 4], [5, 6, 7, 8, 9, 10, 11, 12, 13, 'RED_JOKER'])); // success
document.writeln(check(['A', 3, 3], [4, 5, 'BLACK_JOKER'])); // fail
// 抄了楼下的测试用例(*_*)
document.writeln(check([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3, 8]));//true
document.writeln(check([5, 6, "A", "A", 8, 9, 10, 11, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER", 3, 3]));//false
document.writeln(check([5, 6, "A", "A", 8, 9, 10, 11, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER", 3, 4]));//true
document.writeln(check(["BLACK_JOKER", "BLACK_JOKER"], ["RED_JOKER", "RED_JOKER", 8, 9, 10, 11, 12, "A"]));//false
document.writeln(check([6, "RED_JOKER", "A", 8, 9, 10, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER"]));//true
document.writeln(check([6, "A", 8, 9, 10, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER"]));//false
document.writeln(check([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3, 8])); // true
document.writeln(check(['A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['A'])); //true
document.writeln(check(['A', 2, 3, 4, 5, 6, 7, 8, 9], ['A', 'A'])); // false
document.writeln(check(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['A'])); // true
document.writeln(check(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], ['A'])); //false
document.writeln(check(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['BLACK_JOKER'])); //false
我才发现你weibo里面发的不是小王当1-9么,这里又变成当1-5了……
@coswind 你这应该是性能最佳的方案了...
贴个渣实现
/*
测试
*/
function test(deck1, deck2) {
console.log('----------------------');
console.log("input", deck1, deck2);
var res = checkTwoArr(deck1, deck2);
if (!res) {
console.log("failed")
} else {
res = res.join(',').replace(/^(0,)*|(,0)*$/g, '').replace(/,/g, ', ');
console.log("success: [" + res + "]");
}
}
// Only accept "A",2,3,4,5,6,7,8,9,10,11,12,13,"BLACK_JOKER","RED_JOKER"
test([4, 6, 8, 9, 10, 2, 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER', 'RED_JOKER']);
// true
test(['A', 2, 3, 4, 5, 6], [7, 8, 9, 'BLACK_JOKER', 'RED_JOKER']);
//fail, 小王没地方放
test([12, 13], ['BLACK_JOKER']);
//false, 小王与12和13连不上
test(['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER']);
// 超过了5个小王,第六个放不下
test(['BLACK_JOKER'], ['BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'BLACK_JOKER', 'RED_JOKER']);
// success
test(['A', 5, 'A', 7], [8, 10, 'BLACK_JOKER', 'RED_JOKER']);
// fail
test(['A', 'A', 'A', 6, 'BLACK_JOKER', 'BLACK_JOKER'], ['BLACK_JOKER', 'RED_JOKER']);
// fail
test([3, 4, 5, 6, 7, 8, 9], [10]);
// success
test(['A', 4], ['BLACK_JOKER']);
// fail
test(['A', 12], [13]);
// success
test(['A', 2, 3, 4], [5, 6, 7, 8, 9, 10, 11, 12, 13, 'RED_JOKER']);
// success
test(['A', 3, 3], [4, 5, 'BLACK_JOKER']);
// fail
// 抄了楼下的测试用例(*_*)
test([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3, 8]);
//true
test([5, 6, "A", "A", 8, 9, 10, 11, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER", 3, 3]);
//false
test([5, 6, "A", "A", 8, 9, 10, 11, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER", 3, 4]);
//true
test(["BLACK_JOKER", "BLACK_JOKER"], ["RED_JOKER", "RED_JOKER", 8, 9, 10, 11, 12, "A"]);
//false
test([6, "RED_JOKER", "A", 8, 9, 10, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER"]);
//true
test([6, "A", 8, 9, 10, 12], ["RED_JOKER", "RED_JOKER", "BLACK_JOKER"]);
//false
test([2, 9, "A", "RED_JOKER", "BLACK_JOKER"], ["RED_JOKER", "BLACK_JOKER", 3, 8]);
// true
test(['A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['A']);
//true
test(['A', 2, 3, 4, 5, 6, 7, 8, 9], ['A', 'A']);
// false
test(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['A']);
// true
test(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], ['A']);
//false
test(['BLACK_JOKER', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], ['BLACK_JOKER']);
//false
function checkTwoArr(arr1, arr2) {
return checkSequence(arr1.concat(arr2));
}
function checkSequence(arr) {
if (arr.length > 14) {
return false;
}
var noJokerA_arr = [];
var b_joker_arr = [];
var r_joker_arr = [];
var a_arr = [];
var boundary = 5
var len = arr.length;
var checkFleg = true;
for (var i = 0; i < len; i++) {
if (arr[i] == "A") {
a_arr.push(arr[i]);
} else if (arr[i] == "BLACK_JOKER") {
b_joker_arr.push(arr[i]);
} else if (arr[i] == "RED_JOKER") {
r_joker_arr.push(arr[i]);
} else {
noJokerA_arr.push(arr[i]);
}
}
//noJokerA_arr = quickSort(noJokerA_arr);
//console.log("noJokerA_arr",noJokerA_arr);
for (i = 0; i < noJokerA_arr.length-1; i++) {
if(noJokerA_arr[i]==noJokerA_arr[i+1]){
return false;
}
}
switch(a_arr.length) {
case 1:
var checkArr1 = checkSequence(b_joker_arr.concat(r_joker_arr).concat(noJokerA_arr).concat([1]));
if (checkArr1) {
return checkArr1;
} else {
var checkArr2 = checkSequence(b_joker_arr.concat(r_joker_arr).concat(noJokerA_arr).concat([14]))
if (checkArr2) {
return checkArr2;
} else {
return false;
}
}
break;
case 2:
return checkSequence(noJokerA_arr.concat(b_joker_arr).concat(r_joker_arr).concat([1, 14]));
break;
default:
break;
}
if (noJokerA_arr.length > 0) {
var arrPock = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
noJokerA_arr = quickSort(noJokerA_arr);
var arrIndex = arrPock.indexOf(noJokerA_arr[0]);
var min = noJokerA_arr[0];
var max = noJokerA_arr[noJokerA_arr.length - 1];
for (var i = arrIndex; i < arrPock.length && arrPock[i] <= max; i++) {
var index = noJokerA_arr.indexOf(arrPock[i]);
if (index == -1) {
if (arrPock[i] <= boundary) {
checkFleg = (b_joker_arr.length > 0) ? (function() {
b_joker_arr.pop();
noJokerA_arr.push(arrPock[i]);
return true;
})() : (r_joker_arr.length > 0) ? (function() {
r_joker_arr.pop();
noJokerA_arr.push(arrPock[i]);
return true;
})() : false;
} else if (arrPock[i] <= 14) {
checkFleg = (r_joker_arr.length > 0) ? (function() {
r_joker_arr.pop();
noJokerA_arr.push(arrPock[i]);
return true;
})() : false;
}
}
}
if (!checkFleg) {
return checkFleg;
} else {
while (b_joker_arr.length > 0) {
var num1 = b_joker_arr.pop();
min--;
if (min <= boundary && min > 0) {
noJokerA_arr.push(min);
} else {
checkFleg = false;
break;
}
}
while (r_joker_arr.length > 0) {
var num2 = r_joker_arr.pop();
max++;
if (max <= 14) {
noJokerA_arr.push(max);
} else {
checkFleg = false;
break;
}
}
if (checkFleg) {
noJokerA_arr = quickSort(noJokerA_arr);
return noJokerA_arr;
} else {
return false;
}
}
} else {
if (b_joker_arr.length <= boundary) {
min = 6;
max = 5;
while (b_joker_arr.length) {
var num1 = b_joker_arr.pop();
min--;
noJokerA_arr.push(min);
}
while (r_joker_arr.length > 0) {
var num2 = r_joker_arr.pop();
max++;
noJokerA_arr.push(max);
}
noJokerA_arr = quickSort(noJokerA_arr);
return noJokerA_arr;
} else {
return false;
}
}
}
function quickSort(arr) {
var len = arr.length;
if (len <= 1) {
return arr;
} else {
var arrLeft = [], arrRight = [];
var nowArr=[];
for (var i = 1; i < len; i++) {
if (arr[0] <arr[i]) {
arrRight.push(arr[i]);
} else if (arr[0] > arr[i]) {
arrLeft.push(arr[i]);
}else{
nowArr.push(arr[0]);
}
}
return quickSort(arrLeft).concat(arr[0]).concat(nowArr).concat(quickSort(arrRight));
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
参照@ssnau的改了下,无节操。