【双机位A卷】华为OD笔试之【哈希表】双机位A-采购订单【Py/Java/C++/C/JS/Go六种语言】【欧弟算法】全网注释最详细分类最全的华子OD真题题解

可上 欧弟OJ系统 练习华子OD、大厂真题

绿色聊天软件戳 od1441了解算法冲刺训练(备注【CSDN】否则不通过)

文章目录

相关推荐阅读

题目练习网址:【哈希表】双机位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 <= 1000
  • 1 <= 商品价格 <= 200
  • 1 <= 商品数量 <= 1000
  • 1 <= 商品编号 <= 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,如果审批状态为12,则直接忽略该条订单
  • 单价 > 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或了解更多

相关推荐
勿忘,瞬间2 小时前
Maven
java·maven
一 乐2 小时前
高校教务|教务管理|基于springboot+vue的高校教务管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·教务管理
数字冰雹2 小时前
重塑城市公共安全管理的“智慧之眼”
java·大数据·数据库
August_._3 小时前
【MySQL】触发器、日志、锁机制 深度解析
java·大数据·数据库·人工智能·后端·mysql·青少年编程
Halo_tjn3 小时前
基于 Object 类及包装类的专项实验
java·开发语言·计算机
百锦再3 小时前
第10章 错误处理
java·git·ai·rust·go·错误·pathon
拾忆,想起3 小时前
超时重传 vs 快速重传:TCP双保险如何拯救网络丢包?
java·开发语言·网络·数据库·网络协议·tcp/ip·php
從南走到北3 小时前
JAVA国际版同城外卖跑腿团购到店跑腿多合一APP系统源码支持Android+IOS+H5
android·java·ios·微信小程序·小程序
budingxiaomoli3 小时前
多线程(一)
java·开发语言·jvm·java-ee