超市里的货物架调整
问题描述
在一个超市里,有一个包含 𝑛n 个格子的货物架,每个格子中放有一种商品,商品用小写字母 a 到 z 表示。当顾客进入超市时,他们会依次从第一个格子查找到第 𝑛n 个格子,寻找自己想要购买的商品。如果在某个格子中找到该商品,顾客就会购买它并离开;如果中途遇到一个空格子,或查找完所有格子还没有找到想要的商品,顾客也会离开。
作为超市管理员,你可以在顾客到来之前重新调整商品的顺序,以便尽可能多地出售商品。当第一个顾客进入后,商品位置不能再调整。你需要计算在最优调整下,最多可以卖出多少件商品。输入变量说明:
n:货物架的格子数m:顾客想要购买的商品种类数s:货物架上商品的初始顺序c:顾客想要购买的商品种类
测试样例
样例1:
输入:
n = 3 ,m = 4 ,s = "abc" ,c = "abcd"
输出:3
样例2:
输入:
n = 4 ,m = 2 ,s = "abbc" ,c = "bb"
输出:2
样例3:
输入:
n = 5 ,m = 4 ,s = "bcdea" ,c = "abcd"
输出:4
一、问题理解
-
核心问题
- 超市有n个格子放置商品(商品用a−z表示),有m种顾客想买的商品,初始商品顺序为s,顾客想买的商品种类为c。需要重新调整商品顺序,在第一个顾客进入后不能再调整,要计算最优调整下最多能卖出的商品数量。
2. 输入变量含义
- n
决定了货物架的规模,即有多少个格子可供放置商品。
- m
表示顾客想要购买的商品种类数量,这影响到可能的销售上限。
- s
是初始的商品排列顺序,是解决问题的起始状态。
- c
明确了顾客的需求,是判断销售与否的依据。
二、解题思路
-
解题算法
- 可以使用哈希表(
HashMap)来统计商品的数量,然后通过比较两种商品集合(初始摆放和顾客需求)中相同商品的数量来确定最终可卖出的商品数量。 - 还有一种可能的思路是采用贪心算法。我们希望将顾客最可能购买的商品放在前面的格子。对于每个顾客想要购买的商品种类c中的元素,在初始商品顺序s中查找其位置。将在s中靠前位置的商品尽可能地排在货物架的前面格子。
- 可以使用哈希表(
2. 具体步骤
以HashMap为例进行分析:
-
统计初始商品数量(
map1)-
首先将表示初始商品顺序的字符串s转换为字符数组ch1。
-
创建一个
HashMap对象map1,然后遍历字符数组ch1。 -
对于每个字符ch,使用
getOrDefault方法获取当前字符在map1中的数量,如果不存在则默认为00,然后将其数量加1。这样就统计出了初始商品顺序中每个商品的数量。
-
-
统计顾客需求商品数量(
map2)-
类似地,将表示顾客需求的字符串c转换为字符数组ch2,并创建
HashMap对象map2。 -
遍历字符数组ch2,对每个字符在
map2中的数量进行统计,方法与统计map1相同。
-
-
计算可卖出商品数量(
count)-
通过一个循环,从a到z遍历所有可能的商品字符。
-
对于每个字符i,检查它是否同时存在于
map1和map2的键集中。 -
如果存在,就使用
Math.min方法获取该商品在map1和map2中的数量的最小值,并累加到count变量中。这是因为可卖出的商品数量受限于初始摆放和顾客需求中数量较少的一方。
-
-
验证结果
- 在
main方法中,通过调用solution函数并与预期结果进行比较来验证代码的正确性。例如,System.out.println(solution(3, 4, "abc", "abcd") == 3)等语句。
- 在
下面用java进行代码实现:
import java.util.HashMap;
import java.util.Map;
public class Main {
public static int solution(int n, int m, String s, String c) {
int count=0;
//用两个hashmap去储存它,返回同一个值中较小的值
char[] ch1 = s.toCharArray();
char[] ch2 = c.toCharArray();
HashMap<Character,Integer> map1=new HashMap<>();
HashMap<Character,Integer> map2=new HashMap<>();
for (char ch : ch1) {
map1.put(ch, map1.getOrDefault(ch, 0)+1);
}
for (char ch : ch2) {
map2.put(ch, map2.getOrDefault(ch, 0)+1);
}
for(char i='a';i<='z';i++){
if(map1.keySet().contains(i)&&map2.keySet().contains(i)){
count+=Math.min(map1.get(i), map2.get(i));
}
}
return count;
}
public static void main(String[] args) {
System.out.println(solution(3, 4, "abc", "abcd") == 3);
System.out.println(solution(4, 2, "abbc", "bb") == 2);
System.out.println(solution(5, 4, "bcdea", "abcd") == 4);
}
}
三、复杂度分析
(一)时间复杂度
-
创建字符数组
- 将字符串
s和c转换为字符数组ch1和ch2的操作,时间复杂度分别为O(len(s))和O(len(c)),其中len(s)和len(c)分别是字符串s和c的长度。
- 将字符串
-
填充
HashMap- 填充
map1的循环遍历ch1,对于每个字符执行put操作。由于HashMap的put操作在平均情况下时间复杂度为O(1),所以这个循环的时间复杂度为O(len(s))。 - 同理,填充
map2的循环时间复杂度为O(len(c))。
- 填充
-
计算可卖出商品数量(
count)- 循环从
a到z,共26次迭代。在每次迭代中,contains方法在平均情况下时间复杂度为O(1),get方法在HashMap中平均时间复杂度也为O(1),Math.min操作时间复杂度为O(1)。所以这个循环的时间复杂度为O(1)(常数时间,因为循环次数固定为26)。 - 综合起来,整个
solution方法的时间复杂度为O(len(s)+len(c)),主要由填充HashMap的操作决定。
- 循环从
(二)空间复杂度
- 代码创建了两个
HashMap对象map1和map2,在最坏情况下,它们可能存储所有不同的字符,空间复杂度为O(min(len(s), len(c))),因为map1最多存储s中不同字符的数量,map2最多存储c中不同字符的数量。 - 还创建了两个字符数组
ch1和ch2,空间复杂度为O(len(s)+len(c))。 - 总体空间复杂度为O(len(s)+len(c))。
四、总结
在实际应用中,如果输入的字符串长度较短,这种算法能够快速准确地计算出结果。然而,如果需要处理大量的商品数据或者较长的字符串,可能需要考虑优化算法或者数据结构,以降低时间和空间复杂度,比如使用贪心算法。