【备战秋招】每日一题:2023.05.31-华为OD机式-第一题-塔子哥的数据

为了更好的阅读体检,可以查看我的算法学习博客
在线评测链接:P1309

题目内容

塔子哥面临一个挑战,需要从海量的网络数据中筛选出繁忙时段的数据。考虑到数据规模庞大,塔子哥无法对所有数据进行排序,然后选择前 N N N个最大值作为繁忙时段的数据。聪明的塔子哥想到了使用一个固定大小的优先级队列来筛选数据。为了简化场景,我们将海量网络数据表示为一个正整数集合,并且仅需选择 N N N个最大的正整数作为结果。对于每批输入数据,塔子哥将输出一行结果,将这 N N N个正整数按照顺序拼接成一行字符串进行输出。

输入描述

输入第一行为正整数 N N N M M M N N N为忙时个数, M M M为输入的数据行数,( 1 1 1 ≤ \leq N N N ≤ \leq 24 24 24 1 1 1 ≤ \leq M M M ≤ \leq 1000 1000 1000)

接下来输入 M M M行,每行两个正整数 A , B A,B AB,以空格分隔,表示有 A A A个重复的正整数 B B B 1 1 1 ≤ \leq A A A, B B B ≤ \leq 2147483647 2147483647 2147483647

输出描述

输出每增加一批数据对应的队列结果,直接将队列里的所有数据集从大到小拼接成字符串输出.

样例1

输入

24 3
11 5
2 1
18 7

输出

55555555555
5555555555511
777777777777777777555555

解释

保留 24 24 24个忙时数据

第一次输入 11 11 11 5 5 5,则队列输出为 55555555555 55555555555 55555555555

第二次输入 2 2 2 1 1 1,则队列输出为 5555555555511 5555555555511 5555555555511

第三次输入 18 18 18 7 7 7,则队列输出为 777777777777777777555555 777777777777777777555555 777777777777777777555555

思路:大根堆+模拟

给定 M M M 个数据,每个数据为 A A A 个重复的 B B B 。要求每读入一次数据,最多输出当前已读数据中最大的 N N N 个值。

为了能够快速得到最大的值,我们可以使用大根堆来对数据进行存储。

什么是大根堆

其学名是优先队列。具体表现形式(或者说我们自己手动模拟的形式)是一颗二叉树,每个结点最多有两个儿子,且对于任意一个结点,都符合:该结点任意儿子的值,都比该结点的值小。因此,堆顶(或者说二叉树的根节点)就是所有数中最大的值。

对于C++选手来说,刚好有STL能够使用,即priority_queue,其默认是大根堆。比较基础的几个函数分别是:

  1. pop(),弹出堆顶,并返回该元素
  2. push(x),将 x x x 加入到堆中
  3. size(),返回堆中当前元素的个数
  4. clear(),清空堆

其他语言也有相应的封装包,比如python里有heapq。因此如果自己不想动手实现一个优先队列的话,可以直接使用封装包。

由于该题的数据量很小,我们可以直接借助大根堆来模拟这个过程。

具体过程如下:

  1. 读入一行数据,将其加入到大根堆q
  2. 从大根堆不断取出堆顶,进行输出,并将该数据放入到临时队列tmp中,直到输出一共 N N N 个数字
  3. tmp中的数据再重新放回堆中

由于 N N N 很小,最大仅为24,也就是说每次最多输出24个字符,而堆的每次操作都可以近似看作 O ( l o g M ) O(logM) O(logM) 的,最坏情况下每次取出堆中24个数据(每个数据只重复1次)输出再放回去也就是 O ( N l o g M ) O(NlogM) O(NlogM) 的时间复杂度。读入 M M M 行数据,总共要输出 M M M 次,因此总时间复杂度为 O ( N M l o g M ) O(NMlogM) O(NMlogM)

类似题目推荐

代码

C++

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;

int n,m;

struct node{
	int cnt;// 重复多少次 
	int val;// 值 
};

queue<node> tmp;
priority_queue<node> q;

bool operator <(const node a,const node b){// 重载运算符 
	return a.val<b.val;
}

int main(){
	scanf("%d %d",&n,&m);
	node a;
	for(int i=1,rest;i<=m;++i){
		scanf("%d %d",&a.cnt,&a.val);
		q.push(a);
		rest=n;// rest为输出某一字符后,剩余的长度,初始为n 
		while(rest>0){
			if(!q.size()) break;// 大根堆里已经没有字符了,直接break 
			// 取出堆顶 
			a=q.top();
			q.pop();
			// 输出 min(rest,a.cnt) 次 
			for(int i=1;i<=min(rest,a.cnt);++i){
				printf("%d",a.val);
			}
			// 从堆里取出来放到临时队列中 
			tmp.push(a);
			rest-=a.cnt;
		}
		while(tmp.size()){// 将队列中的数据重新放回堆中 
			q.push(tmp.front());
			tmp.pop();
		}
		printf("\n");
	}
	
	
	return 0;
}

python

import heapq

class Node:
    def __init__(self, cnt, val):
        self.cnt = cnt
        self.val = val
    
    def __lt__(self, other):
        return self.val < other.val

n, m = map(int, input().split())

q = []
tmp = []

for _ in range(m):
    cnt, val = map(int, input().split())
    heapq.heappush(q, Node(cnt, val))
    rest = n  # rest为输出某一字符后,剩余的长度,初始为n
    while rest > 0:
        if not q:
            break  # 大根堆里已经没有字符了,直接break
        # 取出堆顶
        a = heapq.heappop(q)
        # 输出 min(rest,a.cnt) 次
        for _ in range(min(rest, a.cnt)):
            print(a.val, end="")
        # 从堆里取出来放到临时队列中
        tmp.append(a)
        rest -= a.cnt
    while tmp:
        # 将队列中的数据重新放回堆中
        heapq.heappush(q, tmp.pop(0))
    print()

Java

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;

class Main {
    static class Node implements Comparable<Node> {
        int cnt; // 重复多少次
        int val; // 值

        public Node(int cnt, int val) {
            this.cnt = cnt;
            this.val = val;
        }

        @Override
        public int compareTo(Node other) {
            return Integer.compare(this.val, other.val);
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        Queue<Node> q = new PriorityQueue<>();
        Queue<Node> tmp = new PriorityQueue<>();

        for (int i = 0; i < m; i++) {
            int cnt = scanner.nextInt();
            int val = scanner.nextInt();
            q.offer(new Node(cnt, val));
            int rest = n; // rest为输出某一字符后,剩余的长度,初始为n
            while (rest > 0) {
                if (q.isEmpty()) break; // 大根堆里已经没有字符了,直接break
                // 取出堆顶
                Node a = q.poll();
                // 输出 min(rest,a.cnt) 次
                for (int j = 0; j < Math.min(rest, a.cnt); j++) {
                    System.out.print(a.val);
                }
                // 从堆里取出来放到临时队列中
                tmp.offer(a);
                rest -= a.cnt;
            }
            while (!tmp.isEmpty()) {
                // 将队列中的数据重新放回堆中
                q.offer(tmp.poll());
            }
            System.out.println();
        }
    }
}

Go

package main

import (
	"container/heap"
	"fmt"
)

type Node struct {
	cnt int // 重复多少次
	val int // 值
}

type PriorityQueue []Node

func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].val < pq[j].val
}
func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}
func (pq *PriorityQueue) Push(x interface{}) {
	item := x.(Node)
	*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

func main() {
	var n, m int
	fmt.Scan(&n, &m)
	q := make(PriorityQueue, 0)
	tmp := make(PriorityQueue, 0)

	for i := 0; i < m; i++ {
		var a Node
		fmt.Scan(&a.cnt, &a.val)
		heap.Push(&q, a)
		rest := n // rest为输出某一字符后,剩余的长度,初始为n
		for rest > 0 {
			if len(q) == 0 {
				break // 大根堆里已经没有字符了,直接break
			}
			// 取出堆顶
			a := heap.Pop(&q).(Node)
			// 输出 min(rest,a.cnt) 次
			for j := 0; j < min(rest, a.cnt); j++ {
				fmt.Print(a.val)
			}
			// 从堆里取出来放到临时队列中
			heap.Push(&tmp, a)
			rest -= a.cnt
		}
		for len(tmp) > 0 {
			// 将队列中的数据重新放回堆中
			heap.Push(&q, heap.Pop(&tmp).(Node))
		}
		fmt.Println()
	}
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

Js

const readline = require('readline');

function min(a, b) {
  return a < b ? a : b;
}

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

let n, m;
const q = [];
const tmp = [];

rl.on('line', (line) => {
  const input = line.split(' ').map(Number);
  if (!n) {
    [n, m] = input;
    return;
  }
  const [cnt, val] = input;
  q.push({ cnt, val });
  let rest = n; // rest为输出某一字符后,剩余的长度,初始为n
  while (rest > 0) {
    if (q.length === 0) break; // 大根堆里已经没有字符了,直接break
    // 取出堆顶
    const a = q.shift();
    // 输出 min(rest,a.cnt) 次
    for (let i = 0; i < min(rest, a.cnt); i++) {
      process.stdout.write(String(a.val));
    }
    // 从堆里取出来放到临时队列中
    tmp.push(a);
    rest -= a.cnt;
  }
  while (tmp.length > 0) {
    // 将队列中的数据重新放回堆中
    q.push(tmp.shift());
  }
  process.stdout.write('\n');
});

题目内容均收集自互联网,如如若此项内容侵犯了原著者的合法权益,可联系我: (CSDN网站注册用户名: 塔子哥学算法) 进行删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
华为OD机试 数大雁是华为公司招聘流程中的其中一项测试环节,用于考察应聘者在编程方面的能力。该笔试主要考察的是计算机基础知识和编程实战能力。 华为OD机试目通常由一系列算法编程组成,其中涵盖了数据结构和算法、字符串操作、动态规划、图论、递归、搜索等各个方面的知识点。考生需要根据目要求,自行设计算法并编写相应的代码,来解决问。 这一环节的目的是为了考察应聘者在编程方面的能力,包括对算法的理解和实现能力、代码质量和效率等方面的评估。编程能力在今天的软件工程领域中十分重要,能够有效地解决实际问,提高代码的可读性和可维护性,是评估一个程序员水平的重要指标。 参加华为OD机试数字大雁,需要具备扎实的计算机基础知识,熟练掌握编程语言和常用的数据结构和算法,并具备理解和分析问的能力。在备战该笔试的过程中,应聘者应该注重对算法的学习和理解,并进行大量的编程实践,深入理解各类算法的原理与应用场景。在解答算法时,可以运用递归、分治、贪心、动态规划等常用思想,将问拆解为更小的子问,从而更好地解决复杂的算法华为OD机试数字大雁是一个对程序员编程能力的一种考察方式,参加者需要通过编写代码解决目,展示自己的编程实力。准备过程中,应聘者应该注意提高自己的算法能力,并进行足够的练习,积累编程经验,从而顺利通过华为OD机试数字大雁。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值