青训营X豆包 MarsCode AI|豆包MarsCode AI刷题

5 阅读5分钟

超市里的货物架调整 | c++解法

题目分析与解题思路

题目描述
超市中有 n 个格子,每个格子内有一个商品,商品由小写字母表示(az)。顾客有一系列商品需求,我们可以提前调整商品的位置,目标是尽量多地满足顾客的需求。每个顾客在遇到第一个空格子时就会离开,因此要尽量将顾客想要购买的商品排放到前面,以提高销售数量。

我们要计算在最优商品调整下,最多可以卖出的商品数量。

分析

  1. 商品调整:商品的顺序可以重新排列,但每个顾客进来时只能依照当前的货架顺序进行查找。
  2. 顾客的查找顺序:顾客按顺序检查每个格子,一旦找到自己想要的商品就购买并离开。
  3. 目标:我们需要调整商品的顺序,使得尽可能多的商品能被顾客购买。

基本思想

  1. 排序问题:考虑如何调整货架商品顺序。我们可以考虑通过贪心策略:尽量把顾客的需求商品放在货架前面,并且尽量让顾客找到商品后就离开。
  2. 贪心策略:通过对顾客需求的商品进行排序并尽量前置在货架上,以确保最大化满足顾客的需求。

步骤

  1. 统计需求商品:可以统计顾客需求商品的数量,并依照这些商品的需求顺序调整货架上的商品。
  2. 模拟顾客查找:模拟顾客按顺序查找商品的过程,如果能找到则计数。

代码实现

#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;
}

解题过程的关键点

  1. 贪心算法

    • 本题中,目标是让尽可能多的商品被卖出,因此可以使用贪心暴力求解,把顾客最需要的商品尽量放在前面。在处理过程中,通过顺序比较货架上某个商品的数量和顾客的需求,并决定可以出售的数量。
  2. 计数与排序

    • 使用数组来统计每种商品在货架和顾客需求中的数量。根据需求和货架商品的数量来决定每种商品能够销售的数量。这里的 shelf 数组记录货架商品的数量,demand 数组记录顾客的需求数量。
  3. 最小值选择

    • 对于每种商品,计算出货架上商品的数量和顾客需求的最小值,表示该商品能够卖出的数量。前提条件是顾客只能按顺序购买商品,如果某个商品数量不足,顾客就不能购买到更多该商品。

复杂度分析

  • 时间复杂度:O(n + m)。其中 n 是货架商品的数量,m 是顾客需求商品的数量。我们需要遍历一遍货架商品和顾客需求商品并计算最小值。
  • 空间复杂度:O(1),即固定大小的数组(26个字母对应的数组)。

适用场景

贪心算法在每一步选择中都做出 局部最优解,以期达到 全局最优解 的算法设计策略。贪心算法常应用于 贪心选择性质最优子结构性质 的问题。

  • 商品优化排列:类似的贪心问题可以用于库存管理、商品推荐等场景,核心思想是利用统计与最小值来优化商品的展示顺序。
  • 需求与库存匹配:当需求和库存都是不确定的时,通过统计来实现最优匹配,并尽量满足需求。
  • 排序问题:通过贪心方式处理排序和需求问题,可以有效地解决类似的配对问题。

在这类题目中,贪心算法适用于需要根据已有顺序进行最优调整的情况,能够较为简洁地实现并求解最大化的目标。下面是一些具体的例子:

1. 活动选择问题 (Activity Selection Problem)

给定一组活动,每个活动有开始时间和结束时间,要求选择尽可能多的活动,且这些活动之间不能重叠。

每次选择 结束时间最早 的活动,因为这样可以为后续活动留出更多时间空间。

2. 区间覆盖问题 (Interval Covering Problem)

给定一组区间,要求用尽可能少的区间覆盖整个目标范围。

每次选择 右端点最靠左 的区间覆盖当前未覆盖的部分,直到目标范围被完全覆盖。

3. 最小生成树 (Minimum Spanning Tree, MST)

给定一个连通图,找到一棵树,包含所有节点且总权重最小。

  • Kruskal 算法:每次选择权重最小的边,且不形成环。
  • Prim 算法:每次选择连接到树上权重最小的边。