1711. 大餐计数

215 篇文章 0 订阅

难度:中等

大餐 是指 恰好包含两道不同餐品 的一餐,其美味程度之和等于 2 的幂。

你可以搭配 任意 两道餐品做一顿大餐。

给你一个整数数组 deliciousness ,其中 deliciousness[i] 是第 i​​​​​​​ 道餐品的美味程度,返回你可以用数组中的餐品做出的不同 大餐 的数量。结果需要对 109 + 7 取余。

注意,只要餐品下标不同,就可以认为是不同的餐品,即便它们的美味程度相同。

示例 1:

输入:deliciousness = [1,3,5,7,9]
输出:4
解释:大餐的美味程度组合为 (1,3) 、(1,7) 、(3,5) 和 (7,9) 。
它们各自的美味程度之和分别为 4 、8 、8 和 16 ,都是 2 的幂。

示例 2:

输入:deliciousness = [1,1,1,3,3,3,7]
输出:15
解释:大餐的美味程度组合为 3 种 (1,1) ,9 种 (1,3) ,和 3 种 (1,7) 。

提示:

  • 1 <= deliciousness.length <= 105
  • 0 <= deliciousness[i] <= 220

超出时间限制:

class Solution {
    public int countPairs(int[] deliciousness) {
        long sum = 0;
        for (int i = 0; i < deliciousness.length - 1; i++) {
            for (int j = i + 1; j < deliciousness.length; j++) {
                if (Integer.bitCount(deliciousness[i] + deliciousness[j]) == 1)
                    sum++;
            }
        }
        return Math.toIntExact(sum % (1000000000 + 7));
    }
}

超时again:

class Solution {
    public int countPairs(int[] deliciousness) {
        long sum = 0;
        int n = deliciousness.length;
        Map<Integer, Integer> dishes = new HashMap<>();
        for (int i = 0; i < n; i++) {
            dishes.put(deliciousness[i], dishes.getOrDefault(deliciousness[i], 0) + 1);
        }
        List<Integer> keySet = new ArrayList<>(dishes.keySet());
        //计算自身重复的方案,如 1 1 1
        for (int i = 0; i < keySet.size(); i++) {
            int num = keySet.get(i);
            if (dishes.get(num) > 1 && Integer.bitCount(2 * num) == 1)
                //Cn2=n!/(2!*(n-2)!)=n(n-1)/2
                sum += dishes.get(num) * (dishes.get(num) - 1) / 2;
        }
        for (int i = 0; i < keySet.size() - 1; i++) {
            for (int j = i + 1; j < keySet.size(); j++) {
                int A = keySet.get(i);
                int B = keySet.get(j);
                if (Integer.bitCount(A + B) == 1)
                    sum += dishes.get(A) * dishes.get(B);
            }
        }
        return Math.toIntExact(sum % (1000000000 + 7));
    }
}

分析:

方法一:哈希表
朴素的解法是遍历数组 \textit{deliciousness}deliciousness 中的每对元素,对于每对元素,计算两个元素之和是否等于 2 的幂。该解法的时间复杂度为 O(n^2)),会超出时间限制。

上述朴素解法存在同一个元素被重复计算的情况,因此可以使用哈希表减少重复计算,降低时间复杂度。具体做法是,使用哈希表存储数组中的每个元素的出现次数,遍历到数组 deliciousness 中的某个元素时,在哈希表中寻找与当前元素的和等于 2 的幂的元素个数,然后用当前元素更新哈希表。由于遍历数组时,哈希表中已有的元素的下标一定小于当前元素的下标,因此任意一对元素之和等于 2 的幂的元素都不会被重复计算。

令 maxVal 表示数组 deliciousness 中的最大元素,则数组中的任意两个元素之和都不会超过 maxVal×2。令 maxSum=maxVal×2,则任意一顿大餐的美味程度之和为不超过 maxSum 的某个 2 的幂。

对于某个特定的 2 的幂 sum,可以在 O(n)O(n) 的时间内计算数组 deliciousness 中元素之和等于sum 的元素对的数量。数组deliciousness 中的最大元素maxVal 满足maxVal≤C,其中 C=2^{20}
 ,则不超过maxSum 的 2 的幂有O(logmaxSum)=O(logmaxVal)=O(logC) 个,因此可以在 O(nlogC) 的时间内计算数组deliciousness 中的大餐数量。

出处:https://leetcode-cn.com/problems/count-good-meals/solution/da-can-ji-shu-by-leetcode-solution-fvg9/

代码:

class Solution {
    public int countPairs(int[] deliciousness) {
        final int MOD = 1000000007;
        int maxVal = 0;
        for (int val : deliciousness) {
            maxVal = Math.max(maxVal, val);
        }
        int maxSum = maxVal * 2;
        int pairs = 0;
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        int n = deliciousness.length;
        for (int i = 0; i < n; i++) {
            int val = deliciousness[i];
            for (int sum = 1; sum <= maxSum; sum <<= 1) {
                int count = map.getOrDefault(sum - val, 0);
                pairs = (pairs + count) % MOD;
            }
            map.put(val, map.getOrDefault(val, 0) + 1);
        }
        return pairs;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。
首先,需要读取给定的语料文件,并且对语料进行处理,得到所有的单词和它们的出现次数。 代码如下: ```python import re # 读取语料文件 with open('corpus.txt', 'r', encoding='utf-8') as f: corpus = f.read() # 对语料进行处理 corpus = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9]+', ' ', corpus) # 只保留中英文、数字 corpus = corpus.lower() # 统一转换为小写 # 统计每个单词的出现次数 word_count = {} for word in corpus.split(): if word not in word_count: word_count[word] = 0 word_count[word] += 1 ``` 接下来,需要定义一个函数来计算句子的N-Gram语言模型的值。 代码如下: ```python import math def calc_sentence_score(sentence, n=2): # 对句子进行处理,得到所有的N-Gram sentence = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9]+', '', sentence) # 只保留中英文、数字 sentence = sentence.lower() # 统一转换为小写 n_grams = [sentence[i:i+n] for i in range(len(sentence)-n+1)] # 计算N-Gram的概率乘积 score = 1.0 for n_gram in n_grams: count = word_count.get(n_gram, 0) score *= (count + 1) / (sum(word_count.values()) + len(word_count)) score = math.log(score) return score ``` 最后,我们可以使用上述函数来计算每个句子的N-Gram语言模型的值。 代码如下: ```python sentences = [ '小明今天抽奖抽到一台苹果手机。', '这个女人看见一个小猫。', '今天晚上请你吃大餐,我们一起吃日料。', '真是一只好看的小猫。', '今晚我去吃火锅。', '养乐多绿来一杯。' ] for sentence in sentences: score = calc_sentence_score(sentence) print('{} 的得分为:{}'.format(sentence, score)) ``` 输出结果如下: ``` 小明今天抽奖抽到一台苹果手机。 的得分为:-37.34757639228757 这个女人看见一个小猫。 的得分为:-34.58798230735276 今天晚上请你吃大餐,我们一起吃日料。 的得分为:-44.62010374218108 真是一只好看的小猫。 的得分为:-28.262247275439536 今晚我去吃火锅。 的得分为:-23.994537658168813 养乐多绿来一杯。 的得分为:-20.446027918828496 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值