【备战秋招】每日一题:2023.05-B卷-华为OD机试 - 文件目录大小

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

题目描述

一个文件目录的数据格式为: 目录 i d id id,本目录中文件大小,(子目录 i d id id列表)。

其中目录 i d id id全局唯一,取值范围[ 1 , 200 1,200 1,200],本目录中文件大小范围[ 1 , 1000 1,1000 1,1000],子目录 i d id id列表个数[ 0 , 10 0,10 0,10]例如 : 1 1 1 20 20 20( 2 , 3 2,3 2,3)表示目录 1 1 1中文件总大小是 20 20 20,有两人子目录, i d id id分别是 2 2 2 3 3 3

现在输入一个文件系统中所有目录信息,以及待查询的目录 i d id id,返回这个目录和及该目录所有子目录的大小之和。

输入描述

第一行为两个数字 M M M N N N,分别表示目录的个数和待查询的目录 i d id id,

- 1 ≤ M ≤ 100 1\leq M \leq100 1M100
- 1 ≤ N ≤ 200 1\leq N\leq200 1N200

接下来 M M M行,每行为 1 1 1个目录的数据:

目录id 本目录中文件大小(子目录id列表)

子目录列表中的子目录 i d id id以逗号分隔。

输出描述

待查询目录及其子目录的大小之和。

样例

输入

3 1
3 15 ()
1 20 (2)
2 10 (3)

输出

45

说明

目录 1 1 1大小为 20 20 20,包含一个子目录 2 2 2(大小为 10 10 10),子目录 2 2 2包含一个子目录 3 3 3(大小为 15 15 15),总的大小为 20 + 10 + 15 = 45 20+10+15=45 20+10+15=45

输入

4 2
4 20 ()
5 30 ()
2 10 (4,5)
1 40 ()

输出

60

说明

目录 2 2 2包含 2 2 2个子目录 4 4 4 5 5 5,总的大小为 10 + 20 + 30 = 60 10+20+30=60 10+20+30=60

思路:树的遍历 dfs

这是一道典型的建图加dfs遍历的问题。

当前目录的大小是确定的,当前目录的子目录是有很多级的。

而第 i 级子目录必然是某个第 i-1 级子目录的 1 级子目录。

故求当前目录的所有子目录的大小,等于求其所有 1 级子目录的大小,以及所有 1 级子目录的子目录的大小。

这样就是一个子问题了,故可以递归解决。

d f s ( u ) dfs(u) dfs(u)表示目录 u u u的大小以及目录 u u u的所有子目录的大小之和。

d f s ( u ) = w [ u ] + ∑ v   i s   s o n   o f u d f s ( v ) dfs(u) = w[u] + \sum\limits_{v\ is\ son\ of u} dfs(v) dfs(u)=w[u]+v is son ofudfs(v)

这里的 v v v u u u的儿子,即 v v v u u u的一级子目录。

时间复杂度: O ( n ) O(n) O(n)

类似题目推荐

参考Codefun2000 的 DFS教程

Codefun2000

树形

  1. 蚂蚁 P1154. 2023.04.04-研发岗-第二题-子树
  2. 小红书 P1177. 2023.04.09-春招-第一题-拆分树
  3. 清华大学 P1159. 2022年清华大学(深圳)保研夏令营机试题-第一题-树上计数

LeetCode

拓扑排序

  1. 207. 课程表
  2. 210. 课程表 II

代码

C++

#include <bits/stdc++.h>
using namespace std;

const int N = 1000;

int main()
{
    int m, idx;
    cin >> m >> idx;
    // g[i] 表示目录 i 的所有一级子目录
    vector<vector<int>> g(N + 1);
    // w[i] 表示目录 i 的文件大小
    vector<int> w(N + 1);

    for (int i = 0; i < m; ++i) {
        int x;
        cin >> x;
        cin >> w[x];

        string s;
        cin >> s;

        int len = s.size();
        for (int j = 0; j < len; ++j) {
            // 如果不是数字,说明是分隔符
            if (!isdigit(s[j])) continue;
            int t = 0;
            int k = j;
            while (k < len && isdigit(s[k])) {
                t = t * 10 + (s[k] - '0');
                k += 1;
            }
            // t 是其中一个子目录,如此由 x 指向 t ,构造出一个目录树
            g[x].emplace_back(t);
            j = k - 1;
        }
    }

    function<int(int)> dfs = [&](int u) {
        // 初始化为当前目录的大小
        int res = w[u];
        for (int v: g[u]) {
            // 获取所有子目录的大小
            res += dfs(v);
        }
        return res;
    };

    // 从查询的目录 idx 开始,求出这个目录和其所有子目录的大小
    cout << dfs(idx) << "\n";
    return 0;
}

python

N = 1000

def dfs(u, g, w):
    # 初始化为当前目录的大小
    res = w[u]
    for v in g[u]:
        # 获取所有子目录的大小
        res += dfs(v, g, w)
    return res

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

# g[i] 表示目录 i 的所有一级子目录
g = [[] for _ in range(N + 1)]
# w[i] 表示目录 i 的文件大小
w = [0] * (N + 1)

for i in range(m):
    x, wx, s = input().split()
    x, wx = int(x), int(wx)
    w[x] = wx

    lenS = len(s)
    j = 0
    while j < lenS:
        # 如果不是数字,说明是分隔符
        if not s[j].isdigit():
            j += 1
            continue
        t = 0
        k = j
        while k < lenS and s[k].isdigit():
            t = t * 10 + int(s[k])
            k += 1
        # t 是其中一个子目录,如此由 x 指向 t ,构造出一个目录树
        g[x].append(t)
        j = k

# 从查询的目录 idx 开始,求出这个目录和其所有子目录的大小
print(dfs(idx, g, w))

Java

import java.util.*;

public class Main {
    static final int N = 1000;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int idx = sc.nextInt();

        // g[i] 表示目录 i 的所有一级子目录
        List<List<Integer>> g = new ArrayList<>();
        for (int i = 0; i <= N; i++) {
            g.add(new ArrayList<>());
        }

        // w[i] 表示目录 i 的文件大小
        int[] w = new int[N + 1];

        for (int i = 0; i < m; ++i) {
            int x = sc.nextInt();
            w[x] = sc.nextInt();

            String s = sc.next();

            int len = s.length();
            for (int j = 0; j < len; ++j) {
                // 如果不是数字,说明是分隔符
                if (!Character.isDigit(s.charAt(j))) continue;
                int t = 0;
                int k = j;
                while (k < len && Character.isDigit(s.charAt(k))) {
                    t = t * 10 + (s.charAt(k) - '0');
                    k += 1;
                }
                // t 是其中一个子目录,如此由 x 指向 t ,构造出一个目录树
                g.get(x).add(t);
                j = k - 1;
            }
        }

        // 从查询的目录 idx 开始,求出这个目录和其所有子目录的大小
        System.out.println(dfs(idx, g, w));
    }

    static int dfs(int u, List<List<Integer>> g, int[] w) {
        // 初始化为当前目录的大小
        int res = w[u];
        for (int v : g.get(u)) {
            // 获取所有子目录的大小
            res += dfs(v, g, w);
        }
        return res;
    }
}

Go

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

const N = 1000

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    scanner.Split(bufio.ScanWords)

    scanner.Scan()
    m, _ := strconv.Atoi(scanner.Text())

    scanner.Scan()
    idx, _ := strconv.Atoi(scanner.Text())

    // g[i] 表示目录 i 的所有一级子目录
    g := make([][]int, N+1)
    // w[i] 表示目录 i 的文件大小
    w := make([]int, N+1)

    for i := 0; i < m; i++ {
        scanner.Scan()
        x, _ := strconv.Atoi(scanner.Text())

        scanner.Scan()
        w[x], _ = strconv.Atoi(scanner.Text())

        scanner.Scan()
        s := scanner.Text()

        lenS := len(s)
        for j := 0; j < lenS; j++ {
            // 如果不是数字,说明是分隔符
            if !isDigit(s[j]) {
                continue
            }
            t := 0
            k := j
            for k < lenS && isDigit(s[k]) {
                t = t*10 + int(s[k]-'0')
                k += 1
            }
            // t 是其中一个子目录,如此由 x 指向 t ,构造出一个目录树
            g[x] = append(g[x], t)
            j = k - 1
        }
    }

    // 从查询的目录 idx 开始,求出这个目录和其所有子目录的大小
    fmt.Println(dfs(idx, g, w))
}

func dfs(u int, g [][]int, w []int) int {
    // 初始化为当前目录的大小
    res := w[u]
    for _, v := range g[u] {
        // 获取所有子目录的大小
        res += dfs(v, g, w)
    }
    return res
}

func isDigit(c byte) bool {
    return c >= '0' && c <= '9'
}

Js

process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
    input += data;
    return;
});
process.stdin.on('end', () => {
    const lines = input.trim().split('\n');
    const [m, idx] = lines[0].split(' ').map(Number);

    // g[i] 表示目录 i 的所有一级子目录
    const g = Array.from({ length: N + 1 }, () => []);
    // w[i] 表示目录 i 的文件大小
    const w = Array(N + 1).fill(0);

    for (let i = 1; i <= m; i++) {
        const [x, wx, s] = lines[i].split(' ');
        w[x] = Number(wx);

        const lenS = s.length;
        for (let j = 0; j < lenS; j++) {
            // 如果不是数字,说明是分隔符
            if (!isDigit(s[j])) {
                continue;
            }
            let t = 0;
            let k = j;
            while (k < lenS && isDigit(s[k])) {
                t = t * 10 + (s[k] - '0');
                k += 1;
            }
            // t 是其中一个子目录,如此由 x 指向 t ,构造出一个目录树
            g[x].push(t);
            j = k - 1;
        }
    }

    // 从查询的目录 idx 开始,求出这个目录和其所有子目录的大小
    console.log(dfs(idx, g, w));
});

const N = 1000;

function dfs(u, g, w) {
    // 初始化为当前目录的大小
    let res = w[u];
    for (const v of g[u]) {
        // 获取所有子目录的大小
        res += dfs(v, g, w);
    }
    return res;
}

function isDigit(c) {
    return c >= '0' && c <= '9';
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

塔子哥学算法

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

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

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

打赏作者

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

抵扣说明:

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

余额充值