【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语言版
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语言版
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语言版
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语言版

相关推荐
蓝胖子教编程2 分钟前
【题解】【枚举】——[NOIP2018 普及组] 龙虎斗
c++·算法
奇偶变不变33 分钟前
RTOS之事件集
java·linux·jvm·单片机·算法
Sunsets_Red37 分钟前
CF1548A Web of Lies 题解
c++·学习·算法·信息与通信
Solitudefire1 小时前
蓝桥杯刷题——day7
算法·蓝桥杯
了一li1 小时前
MATLAB转换C语言--问题(一)FFT 和 IFFT 的缩放因子
算法
古希腊掌管学习的神2 小时前
[机器学习] 决策树
python·算法·决策树·机器学习
呆呆的猫3 小时前
【LeetCode】726、原子的数量
算法·leetcode·职场和发展
莫叫石榴姐3 小时前
SQL进阶技巧:如何计算算法题分发糖果问题?
大数据·数据结构·数据库·sql·算法·数据挖掘·数据分析
arnold664 小时前
华为OD E卷(100分)25-整数对最小和
算法·华为od
arnold664 小时前
华为OD E卷(100分)32-字符串分割
算法·华为od