算法笔记

95 阅读2分钟

德州扑克葫芦限制问题

  • 13到1张牌,3+2相同的牌组成最大数获胜

  • 设置了最大限制

  • 暴力枚举

    • 哈希统计每种牌的数量
    • 枚举找出满足下面条件的组合[a大于2,b大于1],[a等于b时a大于4]
    • 检查满足条件的组合的值是否小于max+1
    • 保留最大组合,没有则返回[0,0]
  • 排序和双指针

    • 统计牌的数量
    • 从大到小排序
    • 固定a,从大到小枚举
    • 双指针找到满足条件的最大b
  • 动态规划

    • 先排序好
    • dp[i][j][k],i表示前i种,j表示用j作为a的情况,k表示用k作为b的情况
    • 状态转移:
      • 不用当前i:dp[i][j][k] = dp[i-1][j][k]

      • 用i作为a:更新 dp[i][j][k] 为 (i, b),b 从之前的 k 状态继承

        • count[i] ≥ 3 且 j ≥ 3
      • i作为b:更新 dp[i][j][k] 为 (a, i),a 从之前的 j 状态继承

        • count[i] ≥ 2 且 k ≥ 2
      • i 同时作为 a 和 b

        • count[i] ≥ 5
        • 更新 dp[i][j][k] 为 (i, i)
  • 贪心+预处理

    • 统计数量
    • 预处理所有大于1和2的组合
    • 从大到小尝试a,找到最大可行的b
function findFullHouse(n, maxSum, array) {
    // 统计每种牌数量
    const count = new Map();
    for (let card of array) {
        count.set(card, (count.get(card) || 0) + 1);
    }
    
    // 获取所有可能的牌面值
    const values = Array.from(count.keys());
    
    let bestA = 0;
    let bestB = 0;
    
    // 枚举三张相同的牌 a
    for (let a of values) {
        if (count.get(a) < 3) continue;
        
        // 枚举两张相同的牌 b
        for (let b of values) {
            // 检查数量是否足够
            if (a === b) {
                if (count.get(a) < 5) continue;
            } else {
                if (count.get(b) < 2) continue;
            }
            
            // 检查和是否符合
            const sum = 3 * a + 2 * b;
            if (sum > maxSum) continue;
            
            // 更新最大组合
            if (a > bestA || (a === bestA && b > bestB)) {
                bestA = a;
                bestB = b;
            }
        }
    }
    
    return bestA === 0 ? [0, 0] : [bestA, bestB];
}

// 测试
const n = 9, maxSum = 34, array = [6, 6, 6, 8, 8, 8, 5, 5, 1];
console.log(findFullHouse(n, maxSum, array)); // [8, 5]


动态规划为n的平方,贪心为n