备战秋招】每日一题:2022年9月23日-华为OD机试(第二题)-DNS本地缓存

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

题目内容

塔子哥是一名软件工程师,他正在开发一个 D N S DNS DNS本地缓存系统。在互联网中, D N S DNS DNS D o m a i n N a m e S y s t e m Domain Name System DomainNameSystem)用于将域名(例如www.example.com)解析为IP地址,以便将请求发送到正确的服务器上。通常情况下, D N S DNS DNS请求会发送到互联网上的某个 D N S DNS DNS服务器,这会造成一定的网络延迟和负载。为了解决这个问题,塔子哥想要开发一个本地 D N S DNS DNS缓存系统,可以在本地缓存一部分 D N S DNS DNS请求的结果,以提高性能和减轻网络负载。

塔子哥的这个 D N S DNS DNS本地缓存系统有功能如下:

  1. 系统初始状态无存储记录,最大可缓存N条记录;
  2. 系统每 1 1 1秒能解析 1 1 1 U R L URL URL地址,先从本地 D N S DNS DNS上查找,如果本地缓存中能查到就直接返回 f r o m from from_ c a c h e cache cache;
  3. 如果本地 D N S DNS DNS.上没有该地址,返回 f r o m from from_ i n t e r n e t internet internet, 并从 U R L URL URL的属性列表 t l s tls tls上,读取该 U R L URL URL T T L TTL TTL( T i m e Time Time T o To To L i v e Live Live代表该 U R UR URL的生存时长,即能够保存到缓存系统中的时长),并将 U R L URL URL存入缓存系统中;如果在 t s ts ts上未能读到该 U R L URL URL T T L TTL TTL,设置默认 T T L TTL TTL 5 s 5s 5s;
  4. 本地缓存系统中 U R L URL URL地址的 T T L TTL TTL每秒减 1 1 1,当 T T L = 0 TTL=0 TTL=0时,将该 U R L URL URL地址从缓存系统中移除;
  5. 在系统空间装满后,如果还有新的 U R L URL URL要录入,则将TTL最小的一个 U R L URL URL移除,如果TTL最小 U R L URL URL存在多个,按照先进先出的方式移除 1 1 1 U R L URL URL.

现在每 1 1 1秒输入一个 U R L URL URL地址,求每个 U R L URL URL地址的解析方式( f r o m from from c a c h e cache cache 还是 f r o m from from i n t e r n e t internet internet)。

输入描述

第一行两个整数 N   X N\ X N X , 代表 D N S DNS DNS的缓存空间以及待请求的 U R L URL URL的数量

接下来一行 X X X个整数,分别代表对应的 u r l url url , 形如: u r l 1 , u r l 2 , u r l 3 , . . . , u r l X url_1 ,url_2 , url_3 , ... ,url_X url1,url2,url3,...,urlX , 元素允许重复

接下来一行整数 Y Y Y , 代表 U R L URL URL的属性列表 t l s tls tls长度.

接下来 Y Y Y行,每行两个整数, u r l i url_i urli t t l i ttl_i ttli .

数据范围说明:

0 < N , X , Y ≤ 65535 , N , X , Y 0 < N, X, Y \leq 65535,N,X,Y 0<N,X,Y65535,N,X,Y为正整数

0 ≤ u r l i , t t l i ≤ 65535 , u r l i , t t l i 0 \leq url_i , ttl_i \leq 65535 , url_i , ttl_i 0urli,ttli65535,urli,ttli为整数

输出描述

每秒中url的解析方式列表( 0 : 0: 0: f r o m from from_ c a c h e cache cache, 1 : f r o m 1: from 1:from_ i n t e r n e t internet internet)

样例

输入

5 5
3 1 2 1 2
2
1 4
2 2

输出

1 1 1 0 1
样例2

输入

10 15
11 14 10 5 8 3 8 13 12 9 12 15 15 7 7
8
11 2
14 11
10 9
5 7
8 1
13 10
9 10
15 8

输出

1 1 1 1 1 1 1 1 1 1 0 1 0 1 0

思路

优先队列 + 模拟

按题意模拟即可。需要想到使用优先队列维护本地 D N S DNS DNS 缓存。这里注意不要直接使用 T T L TTL TTL 存储而是直接存储一个 U R L URL URL 的生存周期结束时间,这样利于优先队列排序和删除处理。

更多的细节可以见代码的逐行注释。

类似题目推荐

LeetCode

1.239. 滑动窗口最大值 - 优先队列入门

2.264. 丑数 II

3.621. 任务调度器

4.857. 雇佣 K 名工人的最低成本

CodeFun2000

1.P1211 塔子大厂真题模拟赛-第一题-魔法石(Ⅰ)

2.P1057 华为od 2022.11.17-分奖金

3.P1052 华东师范大学保研机试-2022-乘法

代码

CPP

#include <bits/stdc++.h>
using namespace std;
const int N = 65536;
struct Node		//维护一个URL的信息
{
	int edt, stt, id;		//edt代表生存周期结束时间,stt代表开始时间
	bool operator<(const Node& b) const		//为了使用优先队列存储要重载运算符<
	{	//优先队列应该要将待删除的数放在队列顶,而优先队列默认为大堆顶,所以要将优先删除的 TTL最小的,即结束时间最小的定为最"大"的值,相等时按先进先出原则,按开始时间排序。
		if(edt == b.edt) return stt > b.stt;
		return edt > b.edt;
	}
};
priority_queue<Node> que;	//优先队列定义
int n, x, y;
int q[N];			//询问数组
int ttls[N];		//每个URL的ttl
bool f[N];			//记录当前队列中有没有某个URL
int main()
{
	cin >> n >> x;
	for(int i = 1 ; i <= x ; i ++) {		//输入待处理的YLRL
		cin >> q[i];
	}
	for(int &t:ttls) {	//将所有的ttl初始化为5
		t = 5;
	}
	cin >> y;
	while(y--) {		//循环y次
		int url, ttl;
		cin >> url >> ttl;
		ttls[url] = ttl;		//更新这些URL的ttl
	}
	for(int i = 1 ; i <= x ; i++) {
		while(que.size() && que.top().edt <= i) {		//删除所有结束时间在i之前的本地缓存
			f[que.top().id] = 0;
			que.pop();
		}
		if(f[q[i]]) {		//如果本地缓存中有输出0
			cout << 0 << " \n"[i==x];
		} else {
			cout << 1 << " \n"[i==x];	//没有则输出1,然后添加到本地缓存中
			if(que.size() == n) {		//如果满了删除队列顶一个元素
				f[que.top().id] = 0;
				que.pop();
			}
			f[q[i]] = 1;
			que.push({i+ttls[q[i]], i, q[i]});//将当前的URL放入队列
		}
	}
}

python

import copy
from queue import PriorityQueue

N, X = map(int, input().strip().split()) # 输入 DNS 缓存上限和 TTL 上限
askurls = list(map(int, input().strip().split())) # 多次 DNS 查询的 URL 序列 
urltmap = {} 
Y = int(input().strip())
for i in range(Y):
    url, ttl = map(int, input().strip().split()) # 输入 DNS 地址以及相应的生存周期 TTL
    urltmap[url] = ttl # 将 URL 和 TTL 存储在字典 urltmap 中
ans = ""
fn = [False] * 65536 # 初始化布尔数组 fn,用于判断某个 URL 是否已经被缓存
pq = PriorityQueue() # 初始化优先队列 pq,用于维护本地 DNS 缓存
for i in range(len(askurls)):
    while not pq.empty() and pq.queue[0][0] <= i:
        # 找到优先队列中已过期的生存周期的 URL,进行删除处理
        cur = pq.get() 
        fn[cur[2]] = False 
    # 如果当前 URL 已经被缓存,则将结果字符串连接 "0 "
    if fn[askurls[i]]: 
        ans += "0 "
    else: # 否则当前 URL 还未被缓存,则将结果字符串连接 "1 "
        ans += "1 "
        if len(pq.queue) >= N: # 如果已缓存的 URL 数量达到 DNS 缓存上限 N,则进行删除处理
            cur = pq.get() # 取出优先级最高的 URL,进行删除处理
            fn[cur[2]] = False # 将被删除的 URL 对应的缓存状态设置为 False
        pq.put((i+urltmap.get(askurls[i], 5), i, askurls[i])) # 将当前 URL 存储在优先队列中,并根据 TTL 计算其生存周期结束时间
        fn[askurls[i]] = True # 将当前 URL 对应的缓存状态设置为 True,表示已被缓存
print(ans[:-1]) # 输出结果字符串

Java

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int n= scanner.nextInt(),x= scanner.nextInt();
        int[] url=new int[x];
        int max=0;
        for (int i = 0; i < x; i++) {
            url[i]= scanner.nextInt();
        }
        int y= scanner.nextInt();
        Map<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<y;i++){
            map.put(scanner.nextInt(),scanner.nextInt());
        }
        PriorityQueue<int[]> pq=new PriorityQueue<>((o1, o2) -> o1[1]==o2[1]?o1[0]-o2[0]:o1[1]-o2[1]);
        Map<Integer,int[]> cache=new HashMap<>();
        int[] ans=new int[x];
        for(int i=0;i<x;i++){
            //先删除持续时间结束的
            while(pq.size()>0&&pq.peek()[1]<=i){
                    int[] rem=pq.poll();
                    cache.remove(rem[2]);
                }
            if(cache.containsKey(url[i])){
                ans[i]=0;
            }else {
                ans[i]=1;
                //如果优先队列的第一个元素的结束时间小于当前时间
                if(pq.size()==n){
                    int[] rem=pq.poll();
                    cache.remove(rem[2]);
                }
                //开始时间 结束时间 url
                int[] add=new int[]{i,i+map.getOrDefault(url[i],5),url[i]};
                pq.offer(add);
                cache.put(url[i],add);
            }
        }
        for(int i=0;i<x;i++){
            System.out.print(ans[i]+" ");
        }
    }
}
// by 月与海

Go

package main

import (
	"fmt"
)

const N = 70000

var n, x, y, idx int
var urls, tls map[int]int //urls: key url,value ttl
var q, ans, seq []int     //seq记录url进入的时机

func getMin() int {
	//选择缓存中ttl最小的删除
	var res int = -1
	minTtl := N
	for url, ttl := range urls {
		if ttl < minTtl {
			minTtl = ttl
			res = url
		} else if ttl == minTtl {
			if seq[url] < seq[res] {
				res = url
			}
		}
	}
	return res
}

func main() {
	//初始化所有slice和map
	q = make([]int, N)
	ans = make([]int, N)
	seq = make([]int, N)
	urls, tls = make(map[int]int), make(map[int]int)
	fmt.Scan(&n, &x)
	for i := 0; i < x; i++ {
		fmt.Scan(&q[i])
	}
	fmt.Scan(&y)
	for i := 0; i < y; i++ {
		//初始化urls序列
		var url, ttl int
		fmt.Scan(&url, &ttl)
		tls[url] = ttl
	}
	//每1秒输入一个URL地址 那么x有个暗含的意思就是处理时间
	for i := 0; i < x; i++ {
		//先从本地DNS上查找,如果本地缓存中能查到就直接返回from_cache -> 0
		if _, ok := urls[q[i]]; ok {
			ans[i] = 0
		} else {
			//本地缓存中查不到 -> from_internet 1
			ans[i] = 1
			//将这条url加入 urls中 先判断有没有装满 如果装满了就ttl最小的移除 如果ttl一样 就将入队时间早的移除
			if len(urls) == n {
				delete(urls, getMin())
			}
			//将url 放入urls 从URL的属性列表tls上,读取该URL的TTL 并将URL存入缓存系统中;如果在ts上未能读到该URL的TTL,设置默认TTL为5s;
			if _, ok := tls[q[i]]; ok {
				urls[q[i]] = tls[q[i]]
			} else {
				urls[q[i]] = 5
			}
			seq[q[i]] = idx
			idx++
		}
		//一秒结束了 URL地址的TTL每秒减1,当TTL=0时,将该URL地址从缓存系统中移除;
		for url := range urls {
			urls[url]--
			if urls[url] == 0 {
				delete(urls, url)
			}
		}
	}
	for i := 0; i < x; i++ {
		fmt.Printf("%d", ans[i])
		if i != x-1 {
			fmt.Printf(" ")
		}
	}
}
// by xchen

Js

// 设置 stdin 接收输入数据
process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
  input += data;
  return;
});

process.stdin.on('end', () => {
  // input 数组以字符串形式存储了所有输入内容。input[i] 存储第i行的所有内容.
  input = input.split('\n');

  // 获取输入参数
  const param0 = input[0].split(' ')
  const N = Number(param0[0]) // 缓存容量
  const X = Number(param0[1]) // 请求个数

  const urlList = new Array() // url 请求列表
  const param1 = input[1].split(' ')
  for (let m = 0; m < X; m++) {
    urlList.push(Number(param1[m]))
  }

  const Y = Number(input[2]) 
  const tls = new Map() 
  for (let i = 0; i < Y; i++) {
    let tmp = input[3+i].split(' ')
    tls.set(Number(tmp[0]), Number(tmp[1]))
  }

  const cache = new Array() // 缓存
  const set = new Set() // 缓存中 url 集合

  // 添加 url 到缓存
  function add(url){
    if(cache.length < N){
      cache.push([url, tls.get(url) || 5])
      set.add(url)
    } else {
      if(set.has(url)){
        // 当前 url 已经存在于缓存中,不需要进行任何操作
      } else {
        // 缓存已满,删除缓存中生命周期最短的 url ,并将新的 url 添加到缓存中
        cache.sort((a, b) => a[1]-b[1])
        set.delete(cache[0][0])
        cache.shift()
        cache.push([url, tls.get(url) || 5])
        set.add(url)
      }
    }
  }

  // 更新缓存中 url 的 TTL
  function TTL() {
    for(let i = 0; i < cache.length; i++){
      cache[i][1] -= 1
      let urlTTL = cache[i][1]
      if(urlTTL === 0){
        set.delete(cache[i][0])
        cache.splice(i,1)
        i--
      }
    }
  }

  let result = new Array()
  for (let i = 0; i < X; i++) {
    // 更新缓存中 url 的 TTL
    TTL()
    if(set.has(urlList[i])){
      // url 存在于缓存中
      result.push('0')
    }else{
      // url 不存在于缓存中,将其添加至缓存中
      result.push('1')
      add(urlList[i])
    }
  }

  let ans = ''
  for(let i = 0; i < result.length - 1; i++){
    ans += result[i] + ' '
  }
  ans += result[result.length-1]
  console.log(ans)
})

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

塔子哥学算法

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

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

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

打赏作者

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

抵扣说明:

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

余额充值