【11.6】数学思维-解24点游戏

一、题目

        给定一个长度为4的整数数组 cards 。你有 4 张卡片,每张卡片上都包含一个范围在 [1,9] 的数字。您应该使用运算符 ['+', '-', '*', '/'] 和括号 '(' 和 ')' 将这些卡片上的数字排列成数学表达式,以获得值24。

你须遵守以下规则:

  • 除法运算符 '/' 表示实数除法,而不是整数除法。
    • 例如, 4 /(1 - 2 / 3)= 4 /(1 / 3)= 12 。
  • 每个运算都在两个数字之间。特别是,不能使用 “-” 作为一元运算符。
    • 例如,如果 cards =[1,1,1,1] ,则表达式 “-1 -1 -1 -1”不允许 的。
  • 你不能把数字串在一起
    • 例如,如果 cards =[1,2,1,2] ,则表达式 “12 + 12” 无效。

如果可以得到这样的表达式,其计算结果为 24 ,则返回 true ,否则返回 false 。

示例 1:

输入: cards = [4, 1, 8, 7]
输出: true
解释: (8-4) * (7-1) = 24

示例 2:

输入: cards = [1, 2, 1, 2]
输出: false

提示:

  • cards.length == 4
  • 1 <= cards[i] <= 9

二、解题思路

        要将 4 张卡片上的数字通过运算符(`+`, `-`, `*`, `/`)和括号组合成结果为 24 的表达式,可以采用以下方法:

1. 排列组合:  
   首先,对 4 个数字进行全排列,尝试所有可能的顺序。

2. 运算符组合:  
   对于每一种数字排列,尝试所有可能的运算符组合(共 4^3 = 64 种)。

3. 括号优先级:  
   对于每一种数字和运算符的组合,尝试不同的括号优先级,确保所有可能的计算顺序都被考虑。

4. 计算结果:  
   对于每一种组合,计算表达式的值,如果结果等于 24,则返回 `true`。

5. 边界条件:  
        除法运算时,除数不能为 0。
        由于是实数除法,结果可能是浮点数,需要考虑浮点数精度问题(如使用 `1e-6` 作为误差范围)。

可以通过回溯的方法遍历所有不同的可能性。

三、代码实现

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

// 判断两个浮点数是否相等(考虑精度误差)
bool isEqual(double a, double b) {
    return fabs(a - b) < 1e-6;
}

// 递归计算所有可能的表达式
bool solve(vector<double>& nums) {
    if (nums.size() == 1) {
        return isEqual(nums, 24); // 判断是否等于 24
    }

    for (int i = 0; i < nums.size(); i++) {
        for (int j = 0; j < nums.size(); j++) {
            if (i == j) continue;

            vector<double> nextNums;
            for (int k = 0; k < nums.size(); k++) {
                if (k != i && k != j) {
                    nextNums.push_back(nums[k]);
                }
            }

            // 尝试四种运算符
            for (int op = 0; op < 4; op++) {
                double result = 0;
                if (op == 0) {
                    result = nums[i] + nums[j];
                } else if (op == 1) {
                    result = nums[i] - nums[j];
                } else if (op == 2) {
                    result = nums[i] * nums[j];
                } else if (op == 3) {
                    if (isEqual(nums[j], 0)) continue; // 除数为 0,跳过
                    result = nums[i] / nums[j];
                }

                // 剪枝:如果结果已经大于 24,跳过
                if (result > 24 + 1e-6) continue;

                nextNums.push_back(result);

                if (solve(nextNums)) {
                    return true;
                }

                nextNums.pop_back(); // 回溯
            }
        }
    }

    return false;
}

// 主函数
bool judgePoint24(vector<int>& cards) {
    vector<double> nums(cards.begin(), cards.end());
    return solve(nums);
}

int main() {
    vector<int> cards1 = {4, 1, 8, 7};
    vector<int> cards2 = {1, 2, 1, 2};

    cout << "Input: [4, 1, 8, 7] -> Output: " << (judgePoint24(cards1) ? "true" : "false") << endl;
    cout << "Input: [1, 2, 1, 2] -> Output: " << (judgePoint24(cards2) ? "true" : "false") << endl;

    return 0;
}

时间复杂度:

数字排列:4! = 24 种。  
运算符组合:4^3 = 64 种。  

通过剪枝和去重,减少了不必要的计算,实际时间复杂度低于理论值 O(4!×4^3)。

空间复杂度:

递归栈深度为 4,空间复杂度为 O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城狮7号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值