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

相关推荐
QuantumStack24 分钟前
【C++ 真题】B2003 输出第二个整数
开发语言·c++·算法
L_cl1 小时前
数据结构与算法——Java实现 32.堆
java·数据结构·算法
AutoAutoJack1 小时前
C#中,虚方法(virtual) 和 抽象方法(abstract)的应用说明
开发语言·数据结构·算法·架构·c#
伤心男孩拯救世界(Code King)1 小时前
【优选算法】--- 位运算
c++·算法
594h22 小时前
传智杯 第六届—C
数据结构·c++·算法
阳光男孩012 小时前
力扣1930. 长度为3的不同回文子序列
数据结构·算法·leetcode
夜雨翦春韭2 小时前
【代码随想录Day34】动态规划Part03
java·数据结构·算法·leetcode·动态规划
single5942 小时前
【优选算法】(第三十四篇)
java·开发语言·数据结构·c++·python·算法·leetcode
Rstln2 小时前
【线段树】个人练习-Leetcode-3161. Block Placement Queries
算法
Sheep Shaun2 小时前
希尔排序和直接插入排序
c语言·数据结构·算法·排序算法