可上 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳
od1441了解算法冲刺训练(备注【CSDN】否则不通过)
文章目录
相关推荐阅读
- 【华为OD机考正在更新】2025年双机位A卷真题【完全原创题解 | 详细考点分类 | 不断更新题目 | 六种主流语言Py+Java+Cpp+C+Js+Go】
- 【华为OD机考】2025C+2025B+2024E+D卷真题【完全原创题解 | 详细考点分类 | 不断更新题目】
- 【华为OD笔试】双机位A+2025C+2025B+2024E+D卷真题机考套题汇总【真实反馈,不断更新,限时免费】
- 【华为OD笔试】2024E+D卷命题规律解读【分析500+场OD笔试考点总结】
- 【华为OD流程】性格测试选项+注意事项】
题目练习网址:【哈希表】双机位A-采购订单
题目描述与示例
题目描述
在一个采购系统中,采购申请(PR)需要经过审批后才能生成采购订单(PO)。每个PR包含商品的单价(假设相同商品的单价一定是一样的)及数量信息。
系统要求对商品进行分类处理:单价高于100元的商品需要单独处理,单价低于或等于100元的相同商品可以合并到同一采购订单PO中。针对单价低于100的小额订单,如果量大可以打折购买。
具体规则如下:
如果PR状态为"审批通过",则将其商品加入到PO中。如果PR的状态为"审批拒绝"或"待审批",则忽略该PR。
对于单价高于100元的商品,每个商品单独生成一条PO记录。对于单价低于或等于100元的商品,将相同商品的数量合并到一条PO记录中。
如果商品单价<100且商品数量>=100,则单价打9折。
输入描述
第一行包含整数N,表示PR的数量。
接下来N行,每行包含四个用空格分割的整数,按顺序表示:商品ID,数量,单价,PR状态 (0表示审批通过,1表示审批拒绝,2表示待审批)
输出描述
输出若干行,每行表示一条PO记录,按以下格式输出:
对于单价高于100元的商品:商品ID 数量 单价
对于单价低于或等于100元的商品: 商品ID 总数量 打折后的单价(向上取整)
输出的PO记录按商品ID升序升序排列,相同商品按照数量降序排列
补充说明
2 <= n <= 10001 <= 商品价格 <= 2001 <= 商品数量 <= 10001 <= 商品编号 <= 1000
示例一
输入
python
2
1 200 90 0
2 30 101 0
输出
python
1 200 81
2 30 101
说明
商品1的原始单价为90,审批通过,生成一条PO,满足打折条件,打折后单价为81。
商品2的单价为101,审批通过,生成一条PO
示例二
输入
python
3
1 10 90 0
1 5 90 0
2 8 120 0
输出
python
1 15 90
2 8 120
说明
PR1和PR2均为商品1,单价90,审批通过,单价低于100元,合并数量为15
PR3为商品2,单价120元,审批通过,单价高于100元,单独生成一条PO记录。
示例三
输入
python
4
1 5 80 0
2 3 120 0
3 2 90 1
4 10 150 2
输出
python
1 5 80
2 3 120
说明
PR1:商品1,单价80元,审批通过,单价低于100元,合并到PO中。
PR2:商品2,单价120元,审批通过,单价高于100元,单独生成一条PO记录。
PR3:审批拒绝, 忽略。
PR4:待审批,忽略。
解题思路
题目的细节较多,需要仔细读题。注意以下几个点
- 审批状态必须为
0,如果审批状态为1或2,则直接忽略该条订单 - 单价 > 100,不合并订单,不打折
- 单价 = 100,合并订单,不打折
- 单价 < 100,合并订单,打折
单价 = 100的情况,属于特殊的边界情况,在题目中需要仔细读题才能判断出来。
当单价 ≤ 100时,本题涉及到多个同类型商品订单的合并过程。
容易想到用哈希表来维护这个过程。
我们可以设计一个哈希表dic,其中key为商品编号,由于需要同时储存商品单价和商品数量,value可以设计为一个长度为2的数组来储存上述信息。
而不需要合并的订单,我们可以直接用另一个列表lst来储存,同时储存编号,单价,数量。
故可用如下代码来完成数组的更新和哈希表的构建
python
# 储存有效订单的列表
lst = list()
# 储存单价小于等于100的商品信息的哈希表
dic = dict()
# 循环n次
for _ in range(n):
# 输入订单信息,包含编号、数量、单价、状态
idx, num, price, state = map(int, input().split())
# 如果状态为1或2,则属于无效订单,直接跳过
if state != 0:
continue
# 如果单价大于100,则需要单独储存
# 将其编号、数量、单价作为一个三元组存入lst中
# 储存后跳过后续判断
if price > 100:
lst.append([idx, num, price])
continue
# 如果单价小于等于100
# 判断其是否位于哈希表中
# 如果是首次出现,则以编号为key
# 数量和单价构成的二元组作为value
# 构建键值对
if idx not in dic:
dic[idx] = [num, price]
# 如果当前商品已经存在于哈希表中
# 则将数量累加到哈希表中
else:
dic[idx][0] += num
哈希表构建完毕之后,我们需要再次遍历整个哈希表,将其中可以打折的商品进行单价的修改。
python
# 再次遍历哈希表中的所有键值对
for idx in dic:
num, price = dic[idx]
# 如果数量大于等于100且单价小于100
# 则单价打9折,向上取整
if num >= 100 and price < 100:
dic[idx][1] = ceil(price * 0.9)
接下来我们需要将哈希表dic中的键值对,同样根据编号,数量,单价的格式合并到lst中。
python
# 再次遍历哈希表中的所有键值对
# 将更新后的商品信息,按照编号、数量、单价的三元组格式
# 存入lst中
for idx in dic:
num, price = dic[idx]
lst.append([idx, num, price])
最后将lst中的元素进行排序,按照先编号升序排序,后根据数量降序排序的规则进行排序。即
python
# 对lst中的元素进行排序
# 先按照编号升序排序,在按照数量降序排序
lst.sort(key = lambda x: (x[0], -x[1]))
代码
Python
python
# 欢迎来到「欧弟算法 - 华为OD全攻略」,收录华为OD题库、面试指南、八股文与学员案例!
# 地址:https://www.odalgo.com
# 华为OD机试刷题网站:https://www.algomooc.com
# 添加微信 278166530 获取华为 OD 笔试真题题库和视频
# 题目:【哈希表】双机位A-采购订单
# 分值:100
# 作者:许老师-闭着眼睛学数理化
# 算法:哈希表/排序
# 代码看不懂的地方,请直接在群上提问
from math import ceil
# 输入订单条数
n = int(input())
# 储存有效订单的列表
lst = list()
# 储存单价小于等于100的商品信息的哈希表
dic = dict()
# 循环n次
for _ in range(n):
# 输入订单信息,包含编号、数量、单价、状态
idx, num, price, state = map(int, input().split())
# 如果状态为1或2,则属于无效订单,直接跳过
if state != 0:
continue
# 如果单价大于100,则需要单独储存
# 将其编号、数量、单价作为一个三元组存入lst中
# 储存后跳过后续判断
if price > 100:
lst.append([idx, num, price])
continue
# 如果单价小于等于100
# 判断其是否位于哈希表中
# 如果是首次出现,则以编号为key
# 数量和单价构成的二元组作为value
# 构建键值对
if idx not in dic:
dic[idx] = [num, price]
# 如果当前商品已经存在于哈希表中
# 则将数量累加到哈希表中
else:
dic[idx][0] += num
# 再次遍历哈希表中的所有键值对
for idx in dic:
num, price = dic[idx]
# 如果数量大于等于100且单价小于100
# 则单价打9折,向上取整
if num >= 100 and price < 100:
dic[idx][1] = ceil(price * 0.9)
# 再次遍历哈希表中的所有键值对
# 将更新后的商品信息,按照编号、数量、单价的三元组格式
# 存入lst中
for idx in dic:
num, price = dic[idx]
lst.append([idx, num, price])
# 对lst中的元素进行排序
# 先按照编号升序排序,在按照数量降序排序
lst.sort(key = lambda x: (x[0], -x[1]))
# 输出答案
for idx, num, price in lst:
print(idx, num, price)
Java
java
// 欢迎来到「欧弟算法 - 华为OD全攻略」,收录华为OD题库、面试指南、八股文与学员案例!
// 地址:https://www.odalgo.com
// 华为OD机试刷题网站:https://www.algomooc.com
// 添加微信 278166530 获取华为 OD 笔试真题题库和视频
// 题目:【哈希表】双机位A-采购订单
// 分值:100
// 作者:许老师-闭着眼睛学数理化
// 算法:哈希表/排序
// 代码看不懂的地方,请直接在群上提问
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
// 输入订单条数
int n = sc.nextInt();
// 储存有效订单的列表
List<int[]> lst = new ArrayList<>();
// 储存单价小于等于100的商品信息的哈希表
Map<Integer, int[]> dic = new HashMap<>();
// 循环n次
for (int i = 0; i < n; i++) {
// 输入订单信息,包含编号、数量、单价、状态
int idx = sc.nextInt();
int num = sc.nextInt();
int price = sc.nextInt();
int state = sc.nextInt();
// 如果状态为1或2,则属于无效订单,直接跳过
if (state != 0) {
continue;
}
// 如果单价大于100,则需要单独储存
// 将其编号、数量、单价作为一个三元组存入lst中
if (price > 100) {
lst.add(new int[] {idx, num, price});
continue;
}
// 如果单价小于等于100
// 判断其是否位于哈希表中
if (!dic.containsKey(idx)) {
dic.put(idx, new int[] {num, price});
} else {
// 如果已存在,则数量累加
dic.get(idx)[0] += num;
}
}
// 遍历哈希表中的所有键值对
for (Map.Entry<Integer, int[]> entry : dic.entrySet()) {
int idx = entry.getKey();
int num = entry.getValue()[0];
int price = entry.getValue()[1];
// 如果数量大于等于100且单价小于100,则单价打9折,向上取整
if (num >= 100 && price < 100) {
entry.getValue()[1] = (int) Math.ceil(price * 0.9);
}
}
// 将更新后的哈希表内容转为三元组形式加入lst中
for (Map.Entry<Integer, int[]> entry : dic.entrySet()) {
int idx = entry.getKey();
int num = entry.getValue()[0];
int price = entry.getValue()[1];
lst.add(new int[] {idx, num, price});
}
// 对lst进行排序,先按照编号升序,再按照数量降序
lst.sort((a, b) -> {
if (a[0] != b[0]) {
return a[0] - b[0];
}
return b[1] - a[1]; // 数量降序
});
// 输出答案
for (int[] item : lst) {
System.out.println(item[0] + " " + item[1] + " " + item[2]);
}
}
}
C++
cpp
// 欢迎来到「欧弟算法 - 华为OD全攻略」,收录华为OD题库、面试指南、八股文与学员案例!
// 地址:https://www.odalgo.com
// 华为OD机试刷题网站:https://www.algomooc.com
// 添加微信 278166530 获取华为 OD 笔试真题题库和视频
// 题目:【哈希表】双机位A-采购订单
// 分值:100
// 作者:许老师-闭着眼睛学数理化
// 算法:哈希表/排序
// 代码看不懂的地方,请直接在群上提问
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cmath>
using namespace std;
int main() {
int n;
// 输入订单条数
cin >> n;
// 储存有效订单的列表(三元组:idx, num, price)
vector<vector<int>> lst;
// 储存单价 <= 100 的商品信息的哈希表
unordered_map<int, pair<int, int>> dic;
// 循环n次
for (int i = 0; i < n; i++) {
int idx, num, price, state;
cin >> idx >> num >> price >> state;
// 如果状态为1或2,则属于无效订单,直接跳过
if (state != 0) continue;
// 如果单价 > 100,直接入列表,不合并
if (price > 100) {
lst.push_back({idx, num, price});
continue;
}
// 如果单价 <= 100,合并相同编号订单(只累加数量,保留首次价格)
if (dic.find(idx) == dic.end()) {
dic[idx] = {num, price};
} else {
dic[idx].first += num; // 数量累加
}
}
// 遍历哈希表,处理折扣
for (auto &p : dic) {
int &num = p.second.first;
int &price = p.second.second;
// 数量>=100 且 单价<100,打9折,向上取整
if (num >= 100 && price < 100) {
price = ceil(price * 0.9);
}
}
// 将dic内容写回lst
for (auto &p : dic) {
int idx = p.first;
int num = p.second.first;
int price = p.second.second;
lst.push_back({idx, num, price});
}
// 排序:编号升序,数量降序
sort(lst.begin(), lst.end(), [](const vector<int> &a, const vector<int> &b) {
if (a[0] != b[0]) return a[0] < b[0];
return a[1] > b[1];
});
// 输出答案
for (auto &item : lst) {
cout << item[0] << " " << item[1] << " " << item[2] << endl;
}
return 0;
}
C
c
// 欢迎来到「欧弟算法 - 华为OD全攻略」,收录华为OD题库、面试指南、八股文与学员案例!
// 地址:https://www.odalgo.com
// 华为OD机试刷题网站:https://www.algomooc.com
// 添加微信 278166530 获取华为 OD 笔试真题题库和视频
// 题目:【哈希表】双机位A-采购订单
// 分值:100
// 作者:许老师-闭着眼睛学数理化
// 算法:哈希表/排序
// 代码看不懂的地方,请直接在群上提问
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX_ORDERS 10000 // 最大订单数
// 定义结构体用于存储订单信息(编号,数量,单价)
typedef struct {
int idx;
int num;
int price;
} Order;
// 定义哈希表节点
typedef struct HashNode {
int idx;
int num;
int price;
struct HashNode *next;
} HashNode;
#define HASH_SIZE 20011 // 哈希表大小(素数)
// 哈希函数(取模)
int hash(int key) {
return key % HASH_SIZE;
}
// 在哈希表中查找订单编号对应节点
HashNode* find(HashNode* table[], int idx) {
int h = hash(idx);
HashNode *cur = table[h];
while (cur) {
if (cur->idx == idx) return cur;
cur = cur->next;
}
return NULL;
}
// 插入或更新哈希表节点
void insert_or_update(HashNode* table[], int idx, int num, int price) {
int h = hash(idx);
HashNode *node = find(table, idx);
if (node) {
node->num += num; // 如果存在,则数量累加
} else {
// 否则新建节点插入链表头
node = (HashNode*)malloc(sizeof(HashNode));
node->idx = idx;
node->num = num;
node->price = price;
node->next = table[h];
table[h] = node;
}
}
int compare(const void *a, const void *b) {
Order *x = (Order*)a;
Order *y = (Order*)b;
if (x->idx != y->idx) return x->idx - y->idx; // 按编号升序
return y->num - x->num; // 数量降序
}
int main() {
int n;
// 输入订单条数
scanf("%d", &n);
Order lst[MAX_ORDERS]; // 存储有效订单(三元组)
int lst_size = 0;
// 初始化哈希表
HashNode* dic[HASH_SIZE] = {0};
// 循环n次读取订单
for (int i = 0; i < n; i++) {
int idx, num, price, state;
scanf("%d %d %d %d", &idx, &num, &price, &state);
// 如果状态为1或2,则属于无效订单,直接跳过
if (state != 0) continue;
// 如果单价 > 100 直接入数组,不合并
if (price > 100) {
lst[lst_size++] = (Order){idx, num, price};
continue;
}
// 否则加入哈希表中累加数量
insert_or_update(dic, idx, num, price);
}
// 遍历哈希表,处理折扣
for (int i = 0; i < HASH_SIZE; i++) {
HashNode *cur = dic[i];
while (cur) {
if (cur->num >= 100 && cur->price < 100) {
cur->price = (int)ceil(cur->price * 0.9); // 单价打9折,向上取整
}
cur = cur->next;
}
}
// 将哈希表内容写回数组
for (int i = 0; i < HASH_SIZE; i++) {
HashNode *cur = dic[i];
while (cur) {
lst[lst_size++] = (Order){cur->idx, cur->num, cur->price};
cur = cur->next;
}
}
// 排序:编号升序,数量降序
qsort(lst, lst_size, sizeof(Order), compare);
// 输出结果
for (int i = 0; i < lst_size; i++) {
printf("%d %d %d\n", lst[i].idx, lst[i].num, lst[i].price);
}
return 0;
}
Node JavaScript
javascript
// 欢迎来到「欧弟算法 - 华为OD全攻略」,收录华为OD题库、面试指南、八股文与学员案例!
// 地址:https://www.odalgo.com
// 华为OD机试刷题网站:https://www.algomooc.com
// 添加微信 278166530 获取华为 OD 笔试真题题库和视频
// 题目:【哈希表】双机位A-采购订单
// 分值:100
// 作者:许老师-闭着眼睛学数理化
// 算法:哈希表/排序
// 代码看不懂的地方,请直接在群上提问
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let input = [];
rl.on('line', (line) => {
input.push(line.trim());
});
rl.on('close', () => {
let index = 0;
// 输入订单条数
const n = parseInt(input[index++]);
// 储存有效订单的列表
const lst = [];
// 储存单价小于等于100的商品信息的哈希表
const dic = new Map();
// 循环n次读取订单信息
for (let i = 0; i < n; i++) {
const [idx, num, price, state] = input[index++].split(' ').map(Number);
// 如果状态为1或2,则属于无效订单,直接跳过
if (state !== 0) {
continue;
}
// 如果单价大于100,单独存入lst
if (price > 100) {
lst.push([idx, num, price]);
continue;
}
// 单价小于等于100的商品处理逻辑
if (!dic.has(idx)) {
dic.set(idx, [num, price]);
} else {
dic.get(idx)[0] += num; // 累加数量
}
}
// 遍历哈希表,处理满足折扣条件的商品
dic.forEach((value, idx) => {
const [num, price] = value;
if (num >= 100 && price < 100) {
dic.set(idx, [num, Math.ceil(price * 0.9)]);
}
});
// 将哈希表中的订单加入lst列表
dic.forEach((value, idx) => {
const [num, price] = value;
lst.push([idx, num, price]);
});
// 对lst进行排序:先编号升序,再数量降序
lst.sort((a, b) => a[0] !== b[0] ? a[0] - b[0] : b[1] - a[1]);
// 输出答案
lst.forEach(item => {
console.log(item.join(' '));
});
});
Go
go
// 欢迎来到「欧弟算法 - 华为OD全攻略」,收录华为OD题库、面试指南、八股文与学员案例!
// 地址:https://www.odalgo.com
// 华为OD机试刷题网站:https://www.algomooc.com
// 添加微信 278166530 获取华为 OD 笔试真题题库和视频
// 题目:【哈希表】双机位A-采购订单
// 分值:100
// 作者:许老师-闭着眼睛学数理化
// 算法:哈希表/排序
// 代码看不懂的地方,请直接在群上提问
package main
import (
"bufio"
"fmt"
"math"
"os"
"sort"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var n int
// 输入订单条数
fmt.Fscan(reader, &n)
// 储存有效订单的列表
lst := make([][]int, 0)
// 储存单价小于等于100的商品信息的哈希表(key=编号, value=[数量, 单价])
dic := make(map[int][]int)
// 循环读取订单
for i := 0; i < n; i++ {
var idx, num, price, state int
fmt.Fscan(reader, &idx, &num, &price, &state)
// 如果状态为1或2,则属于无效订单
if state != 0 {
continue
}
// 单价大于100,则加入lst
if price > 100 {
lst = append(lst, []int{idx, num, price})
continue
}
// 单价小于等于100:处理哈希表
if _, exists := dic[idx]; !exists {
dic[idx] = []int{num, price}
} else {
dic[idx][0] += num // 累加数量
}
}
// 遍历哈希表中的订单,处理折扣
for idx, data := range dic {
num, price := data[0], data[1]
// 数量大于等于100 且 单价小于100 的订单,单价打9折(向上取整)
if num >= 100 && price < 100 {
dic[idx][1] = int(math.Ceil(float64(price) * 0.9))
}
}
// 将最终哈希表数据加入lst
for idx, data := range dic {
lst = append(lst, []int{idx, data[0], data[1]})
}
// 对lst排序:先编号升序,再数量降序
sort.Slice(lst, func(i, j int) bool {
if lst[i][0] != lst[j][0] {
return lst[i][0] < lst[j][0]
}
return lst[i][1] > lst[j][1]
})
// 输出结果
for _, item := range lst {
fmt.Printf("%d %d %d\n", item[0], item[1], item[2])
}
}
时空复杂度
时间复杂度:O(n)。所有操作都仅需遍历一次数组或者哈希表。
空间复杂度:O(n)。哈希表和列表所占空间。
华为OD算法/大厂面试高频题算法练习冲刺训练
-
华子OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务1000+同学成功上岸!
-
课程讲师为全网200w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
-
90+天陪伴式学习,100+直播课时,300+动画图解视频,500+LeetCode经典题,500+华为OD真题/大厂真题,还有简历修改、模拟面试、陪伴小群、资深HR对接将为你解锁
-
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
-
可查看链接OD真题汇总(持续更新)
-
绿色聊天软件戳
od1441或了解更多