超市里的货物架调整 | c++解法
题目分析与解题思路
题目描述:
超市中有 n
个格子,每个格子内有一个商品,商品由小写字母表示(a
到 z
)。顾客有一系列商品需求,我们可以提前调整商品的位置,目标是尽量多地满足顾客的需求。每个顾客在遇到第一个空格子时就会离开,因此要尽量将顾客想要购买的商品排放到前面,以提高销售数量。
我们要计算在最优商品调整下,最多可以卖出的商品数量。
分析:
- 商品调整:商品的顺序可以重新排列,但每个顾客进来时只能依照当前的货架顺序进行查找。
- 顾客的查找顺序:顾客按顺序检查每个格子,一旦找到自己想要的商品就购买并离开。
- 目标:我们需要调整商品的顺序,使得尽可能多的商品能被顾客购买。
基本思想:
- 排序问题:考虑如何调整货架商品顺序。我们可以考虑通过贪心策略:尽量把顾客的需求商品放在货架前面,并且尽量让顾客找到商品后就离开。
- 贪心策略:通过对顾客需求的商品进行排序并尽量前置在货架上,以确保最大化满足顾客的需求。
步骤:
- 统计需求商品:可以统计顾客需求商品的数量,并依照这些商品的需求顺序调整货架上的商品。
- 模拟顾客查找:模拟顾客按顺序查找商品的过程,如果能找到则计数。
代码实现:
#include <bits/stdc++.h>
using namespace std;
using namespace std;
int solution(int n, int m, string s, string c) {
// 用数组存储货架上商品的数量
vector<int> shelf(26, 0); // 26个字母
vector<int> demand(26, 0); // 顾客需求的商品数量
// 填充货架和顾客需求
for (char ch : s) shelf[ch - 'a']++;
for (char ch : c) demand[ch - 'a']++;
int sold = 0;
// 依次尝试出售顾客想要的商品
for (int i = 0; i < 26; i++) {
// 如果货架上有该商品并且顾客有需求
int can_sell = min(shelf[i], demand[i]);
sold += can_sell;
shelf[i] -= can_sell; // 更新货架上商品的数量
}
return sold;
}
解题过程的关键点:
-
贪心算法:
- 本题中,目标是让尽可能多的商品被卖出,因此可以使用贪心暴力求解,把顾客最需要的商品尽量放在前面。在处理过程中,通过顺序比较货架上某个商品的数量和顾客的需求,并决定可以出售的数量。
-
计数与排序:
- 使用数组来统计每种商品在货架和顾客需求中的数量。根据需求和货架商品的数量来决定每种商品能够销售的数量。这里的
shelf
数组记录货架商品的数量,demand
数组记录顾客的需求数量。
- 使用数组来统计每种商品在货架和顾客需求中的数量。根据需求和货架商品的数量来决定每种商品能够销售的数量。这里的
-
最小值选择:
- 对于每种商品,计算出货架上商品的数量和顾客需求的最小值,表示该商品能够卖出的数量。前提条件是顾客只能按顺序购买商品,如果某个商品数量不足,顾客就不能购买到更多该商品。
复杂度分析:
- 时间复杂度:
O(n + m)
。其中n
是货架商品的数量,m
是顾客需求商品的数量。我们需要遍历一遍货架商品和顾客需求商品并计算最小值。 - 空间复杂度:
O(1)
,即固定大小的数组(26个字母对应的数组)。
适用场景:
贪心算法在每一步选择中都做出 局部最优解,以期达到 全局最优解 的算法设计策略。贪心算法常应用于 贪心选择性质 和 最优子结构性质 的问题。
- 商品优化排列:类似的贪心问题可以用于库存管理、商品推荐等场景,核心思想是利用统计与最小值来优化商品的展示顺序。
- 需求与库存匹配:当需求和库存都是不确定的时,通过统计来实现最优匹配,并尽量满足需求。
- 排序问题:通过贪心方式处理排序和需求问题,可以有效地解决类似的配对问题。
在这类题目中,贪心算法适用于需要根据已有顺序进行最优调整的情况,能够较为简洁地实现并求解最大化的目标。下面是一些具体的例子:
1. 活动选择问题 (Activity Selection Problem)
给定一组活动,每个活动有开始时间和结束时间,要求选择尽可能多的活动,且这些活动之间不能重叠。
每次选择 结束时间最早 的活动,因为这样可以为后续活动留出更多时间空间。
2. 区间覆盖问题 (Interval Covering Problem)
给定一组区间,要求用尽可能少的区间覆盖整个目标范围。
每次选择 右端点最靠左 的区间覆盖当前未覆盖的部分,直到目标范围被完全覆盖。
3. 最小生成树 (Minimum Spanning Tree, MST)
给定一个连通图,找到一棵树,包含所有节点且总权重最小。
- Kruskal 算法:每次选择权重最小的边,且不形成环。
- Prim 算法:每次选择连接到树上权重最小的边。