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

相关推荐
TaoYuan__1 小时前
机器学习的常用算法
人工智能·算法·机器学习
用户40547878374822 小时前
深度学习笔记 - 使用YOLOv5中的c3模块进行天气识别
算法
shinelord明2 小时前
【再谈设计模式】建造者模式~对象构建的指挥家
开发语言·数据结构·设计模式
十七算法实验室2 小时前
Matlab实现麻雀优化算法优化随机森林算法模型 (SSA-RF)(附源码)
算法·决策树·随机森林·机器学习·支持向量机·matlab·启发式算法
黑不拉几的小白兔2 小时前
PTA部分题目C++重练
开发语言·c++·算法
迷迭所归处2 小时前
动态规划 —— dp 问题-买卖股票的最佳时机IV
算法·动态规划
chordful3 小时前
Leetcode热题100-32 最长有效括号
c++·算法·leetcode·动态规划
_OLi_3 小时前
力扣 LeetCode 459. 重复的子字符串(Day4:字符串)
算法·leetcode·职场和发展·kmp
Romanticroom3 小时前
计算机23级数据结构上机实验(第3-4周)
数据结构·算法
白藏y3 小时前
数据结构——归并排序
数据结构·算法·排序算法