【LeetCode每日一题】——679.24 点游戏

一【题目类别】

  • 回溯

二【题目难度】

  • 困难

三【题目编号】

  • 679.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

七【解题思路】

  • 首先要读懂题意,搞清楚四种运算方式
  • 然后使用回溯解决该问题
    • 每次取出两个数字,进行相应的运算
    • 然后组成新的数组,该数组包括运算后的结果和剩下的数字
    • 然后递归重复进行运算
    • 如果最后发现满足24点的要求即可返回真,否则返回假
  • 有些细节需要注意:
    • 注意精度问题,因为是实数运算,所以需要使用浮点类型
    • 注意除法中的除数不能为零
    • 加法和乘法满足交换律,可以通过剪纸减少计算次数,从而提高效率
  • 最后返回结果即可
  • 具体细节可以参考下面的代码

八【时间频度】

  • 时间复杂度: O ( 1 ) O(1) O(1)
  • 空间复杂度: O ( 1 ) O(1) O(1)

九【代码实现】

  1. Java语言版
class Solution {
    // 目标值
    private static final double target = 24;
    // 误差
    private static final double deviation = 1e-6;
    // 四种运算,注意加和乘放在前两位,因为这两种运算满足交换律,方便后续处理
    private static final int add = 0;
    private static final int mul = 1;
    private static final int sub = 2;
    private static final int div = 3;

    public boolean judgePoint24(int[] cards) {
        // 将int数组转成double类型的List
        List<Double> cardList = new ArrayList<>();
        for (int card : cards) {
            cardList.add((double)card);
        }
        // 返回最终结果
        return dfs(cardList);
    }

    // 使用回溯判断满足运算结果为24的情况
    private boolean dfs(List<Double> cards) {
        // 边界条件
        if (cards.size() == 0) {
            return false;
        }
        // 返回结果
        if (cards.size() == 1) {
            return Math.abs(cards.get(0) - target) < deviation;
        }
        // 任取数组中的两个数
        for (int i = 0; i < cards.size(); i++) {
            for (int j = 0; j < cards.size(); j++) {
                // 取得数不能相同
                if (i != j) {
                    // 将剩下的数存到新的数组中
                    List<Double> newCards = new ArrayList<>();
                    for (int k = 0; k < cards.size(); k++) {
                        if (k != i && k != j) {
                            newCards.add(cards.get(k));
                        }
                    }
                    // 开始根据四种运算对最外层循环取出的两个数进行运算并将运算结果放到新的数组中
                    for (int l = 0; l < 4; l++) {
                        // 剪枝,满足交换律的运算(比如加和乘)只运算一次,提高效率
                        if (l < 2 && i > j) {
                            continue;
                        }
                        // 加、乘、减、除四种运算
                        double x = cards.get(i);
                        double y = cards.get(j);
                        if (l == add) {
                            newCards.add(x + y);
                        } else if (l == mul) {
                            newCards.add(x * y);
                        } else if (l == sub) {
                            newCards.add(x - y);
                        } else if (l == div) {
                            if (y < deviation) {
                                continue;
                            }
                            newCards.add(x / y);
                        }
                        // 根据当前运算结果进行下一次运算
                        if (dfs(newCards)) {
                            return true;
                        }
                        // 回溯,开始使用下一种运算符进行运算
                        newCards.remove(newCards.size() - 1);
                    }
                }
            }
        }
        // 所有情况都没满足
        return false;
    }
}
  1. Python语言版
class Solution:
    def judgePoint24(self, cards: List[int]) -> bool:
        # 目标值
        target = 24
        # 误差
        deviation = 1e-6
        # 四种运算,注意加和乘放在前两位,因为这两种运算满足交换律,方便后续处理
        add = 0
        mul = 1
        sub = 2
        div = 3

        # 使用回溯判断满足运算结果为24的情况
        def dfs(cards):
            # 边界条件
            if not cards:
                return False
            # 返回结果
            if len(cards) == 1:
                return abs(cards[0] - target) < deviation
            # 任取数组中的两个数
            for i, x in enumerate(cards):
                for j, y in enumerate(cards):
                    # 取得数不能相同
                    if i != j:
                        # 将剩下的数存到新的数组中
                        new_cards = list()
                        for k, z in enumerate(cards):
                            if k != i and k != j:
                                new_cards.append(z)
                        # 开始根据四种运算对最外层循环取出的两个数进行运算并将运算结果放到新的数组中
                        for l in range(4):
                            # 剪枝,满足交换律的运算(比如加和乘)只运算一次,提高效率
                            if l < 2 and i > j:
                                continue
                            # 加、乘、减、除四种运算
                            if l == add:
                                new_cards.append(x + y)
                            elif l == mul:
                                new_cards.append(x * y)
                            elif l == sub:
                                new_cards.append(x - y)
                            elif l == div:
                                if abs(y) < deviation:
                                    continue
                                new_cards.append(x / y)
                            # 根据当前运算结果进行下一次运算
                            if dfs(new_cards):
                                return True
                            # 回溯,开始使用下一种运算符进行运算
                            new_cards.pop()
            # 所有情况都没满足
            return False
        
        # 返回最终结果
        return dfs(cards)
  1. C语言版
// 目标值
#define target 24.0
// 误差
#define deviation 1e-6
// 四种运算,注意加和乘放在前两位,因为这两种运算满足交换律,方便后续处理
#define add 0
#define mul 1
#define sub 2
#define div 3

// 使用回溯判断满足运算结果为24的情况
bool dfs(double* cards, int size)
{
    // 边界条件
    if (size == 0)
    {
        return false;
    }
    // 返回结果
    if (size == 1)
    {
        return fabs(cards[0] - target) < deviation;
    }
    // 任取数组中的两个数
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            // 取得数不能相同
            if (i != j)
            {
                // 将剩下的数存到新的数组中
                double* newCards = (double*)malloc(sizeof(double) * (size - 1));
                int newCardsIndex = 0;
                for (int k = 0; k < size; k++)
                {
                    if (k != i && k != j)
                    {
                        newCards[newCardsIndex++] = cards[k];
                    }
                }
                // 开始根据四种运算对最外层循环取出的两个数进行运算并将运算结果放到新的数组中
                double x = cards[i];
                double y = cards[j];
                for (int l = 0; l < 4; l++)
                {
                    // 剪枝,满足交换律的运算(比如加和乘)只运算一次,提高效率
                    if (l < 2 && i > j)
                    {
                        continue;
                    }
                    if (l == add)
                    {
                        newCards[newCardsIndex] = x + y;
                    }
                    else if (l == mul)
                    {
                        newCards[newCardsIndex] = x * y;
                    }
                    else if (l == sub)
                    {
                        newCards[newCardsIndex] = x - y;
                    }
                    else if (l == div)
                    {
                        if (fabs(y) < deviation)
                        {
                            continue;
                        }
                        newCards[newCardsIndex] = x / y;
                    }
                    // 根据当前运算结果进行下一次运算,并隐含回溯,开始使用下一种运算符进行运算
                    if (dfs(newCards, newCardsIndex + 1))
                    {
                        free(newCards);
                        return true;
                    }
                }
            }
        }
    }
    // 所有情况都没满足
    return false;
}

bool judgePoint24(int* cards, int cardsSize)
{
    // 将int数组转成double类型的数组
    double* cardList = (double*)malloc(sizeof(double) * cardsSize);
    for (int i = 0; i < cardsSize; i++)
    {
        cardList[i] = (double)cards[i];
    }
    // 返回最终结果
    bool res = dfs(cardList, cardsSize);
    free(cardList);
    return res;
}

十【提交结果】

  1. Java语言版
    在这里插入图片描述

  2. Python语言版
    在这里插入图片描述

  3. C语言版
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

IronmanJay

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

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

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

打赏作者

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

抵扣说明:

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

余额充值