题目表述
小C点菜问题
小C来到了一家餐馆,准备点一些菜。
已知该餐馆有 m 道菜,第 i 道菜的售价为 wi。
小C准备点一些价格相同的菜,但小C不会点单价超过 m 的菜。
小C想知道,自己最多可以点多少道菜?
测试样例
样例1:
输入:
m = 6, w = [2, 3, 3, 6, 6, 6, 9, 9, 23]
输出:3
样例2:
输入:
m = 4, w = [1, 2, 4, 4, 4]
输出:3
样例3:
输入:
m = 5, w = [5, 5, 5, 5, 6, 7, 8]
输出:4
这道题比较简单,用到的方法只要为哈希表,只要掌握了哈希表相关的用法,写起来就会得心应手。 接下来我将简介一下哈希表的一些用法(c++),这里大概讲述一些本题目中会用到的用法,并不包含全部。
哈希表知识点
1.头文件
首先要使用哈希表方法要引入头文件<unordered_map>,如下所示
#include <unordered_map>
2.哈希表的声明
使用 unordered_map 声明一个哈希表,其中键和值的类型可以自定义。例如,可以创建一个 string 类型的键和 int 类型的值的哈希表:
std::unordered_map<std::string, int> myMap;
其中关于键和值的定义可以强调一下。
在哈希表(如 C++ 中的 unordered_map)中,键(key)和值(value)是两个核心概念,它们构成了哈希表中的每个元素的键值对(key-value pair)。
1. 键(Key)
键是数据的唯一标识符,用来定位哈希表中的特定元素。可以将键理解为一种“标签”或“名字”,通过它可以找到对应的值。
- 在 C++ 的
unordered_map中,键可以是任何基本类型,如int、string,也可以是更复杂的类型(只要可以定义哈希函数)。 - 键在哈希表中是唯一的,也就是说每个键只能对应一个值。如果向哈希表中插入一个相同的键,旧的值将会被新值替换。
- 例如,在下面的哈希表中,
"apple"和"banana"就是键:
std::unordered_map<std::string, int> myMap;
myMap["apple"] = 5;
myMap["banana"] = 3;
2. 值(Value)
值是与键对应的数据,即存储的实际信息。键用来查找数据,而值则是该数据的内容。例如,在商品库存系统中,值可以是库存数量、价格等。
在上面的例子中,5 和 3 就是 "apple" 和 "banana" 对应的值。
键值对示例
在哈希表 myMap 中:
- 键
"apple"对应的值是5。 - 键
"banana"对应的值是3。
通过键 "apple",可以找到并访问对应的值 5,而不需要遍历整个哈希表。
示例:现实中的键值对
假设我们有一个电话本,每个人的名字和电话号码形成一个键值对:
| 键(姓名) | 值(电话号码) |
|---|---|
| Alice | 123-4567 |
| Bob | 987-6543 |
| Charlie | 555-7890 |
在这里:
- 姓名(如
"Alice"、"Bob")是键,用于查找某个人的电话号码。 - 电话号码(如
123-4567、987-6543)是值,是每个人的具体信息。
这样,如果要查找 "Alice" 的电话号码,我们只需要根据键 "Alice" 找到对应的值 123-4567。
3.插入元素
可以使用 [] 运算符或 insert 方法将键值对插入到哈希表中:
myMap["apple"] = 5; // 使用 [] 运算符
myMap.insert({"banana", 3}); // 使用 insert 方法
4. 访问元素
可以使用 [] 运算符或 at 方法访问元素:
int appleCount = myMap["apple"]; // 使用 [] 访问
int bananaCount = myMap.at("banana"); // 使用 at 访问
注意:at 方法在键不存在时会抛出异常,而 [] 运算符则会插入一个默认值。
5. 删除元素
可以使用 erase 方法删除指定键的元素:
myMap.erase("banana");
6. 遍历哈希表
可以使用范围 for 循环遍历哈希表中的所有键值对:
for (const auto &pair : myMap) {
std::cout << pair.first << ": " << pair.second << "\n";
}
题目解答
刚刚我们一起学习了c++中哈希表的一些简单的用法,现在我们再来看这道题目是不是就很有头绪了。题目中每道菜和它所附带的价格是不是正好对应哈希表中的键和值呢?首先我们是不是需要遍历所给数组,用一个哈希表来接收每一个价格的菜出现的次数后,再遍历哈希表,并根据所给的m来判断不超过m的出现次数最多的菜就可以啦。
接下来是我给出的c++代码,仅供参考。
#include <iostream>
#include <unordered_map>
#include <vector>
#include <algorithm>
using namespace std;
long solution(int m, vector<int>& w) {
// 使用unordered_map来统计每个价格出现的次数
unordered_map<int, int> priceCount;
// 遍历数组,统计每个价格出现的次数
for (int price : w) {
priceCount[price]++;
}
int maxCount = 0;
// 遍历哈希表,筛选出价格不超过m的菜,并记录这些菜的最大数量
for (auto& entry : priceCount) {
int price = entry.first;
int count = entry.second;
if (price <= m) {
maxCount = max(maxCount, count);
}
}
return maxCount;
}
int main() {
cout << (solution(6, {2, 3, 3, 6, 6, 6, 9, 9, 23}) == 3) << endl;
cout << (solution(4, {1, 2, 4, 4, 4}) == 3) << endl;
cout << (solution(5, {5, 5, 5, 5, 6, 7, 8}) == 4) << endl;
return 0;
}
可惜目前marscode只支持java和朋py,所以这里我再给出java的代码
import java.util.HashMap;
import java.util.Map;
public class Main {
public static long solution(int m, int[] w) {
// 使用HashMap来统计每个价格出现的次数
Map<Integer, Integer> priceCount = new HashMap<>();
// 遍历数组,统计每个价格出现的次数
for (int price : w) {
priceCount.put(price, priceCount.getOrDefault(price, 0) + 1);
}
int maxCount = 0;
// 遍历哈希表,筛选出价格不超过m的菜,并记录这些菜的最大数量
for (Map.Entry<Integer, Integer> entry : priceCount.entrySet()) {
int price = entry.getKey();
int count = entry.getValue();
if (price <= m) {
maxCount = Math.max(maxCount, count);
}
}
return maxCount;
}
public static void main(String[] args) {
System.out.println(solution(6, new int[]{2, 3, 3, 6, 6, 6, 9, 9, 23}) == 3);
System.out.println(solution(4, new int[]{1, 2, 4, 4, 4}) == 3);
System.out.println(solution(5, new int[]{5, 5, 5, 5, 6, 7, 8}) == 4);
}
}
总结
哈希表是一个我们刷题过程中需要掌握的知识点,我目前对他的理解也比较浅薄,觉得他对于物体和数值之间有一对一关系的题目做起来非常方便。哈希表有几个特性:-
- 无序性:
unordered_map的元素没有特定顺序,它是基于哈希函数的存储方式。 - 复杂度:平均情况下,
insert、find和erase操作的时间复杂度为 O(1)O(1)O(1)。 - 适用场景:
unordered_map适用于需要快速查找和更新的情况。
希望大家看完我的笔记后能够在做题过程中有一个新思路,掌握更多的知识。