3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

問題

これの

これです。
標題の通り、今回は(自分的には)普通にやります。

説明

入力の中の「文字列と価格」の行の部分、

paiza 16
pizza 1
paizaio 4
paizapoh 2
pizzaio 8

ここをどういうデータ構造で持つかという話ですね。
1文字づつ辿っていくツリー構造にしましょう。ノードは単純です。

Node {
  total: 自身と配下のノードの合計額,
  index: { a: Node, b: Node, ... }
}

indexの要素は存在するパターンのみ

上記入力を例にすると以下のような構造になります。

(※「total」「index」の表記は省略しています)
(※ルール的に空文字がなく、ルートのtotalは使われないので0のままにしてあります)

                  root
               { 0 ,{..} }
                   | p 
               { 31,{..} }
           | a              | i
      { 22,{..} }       { 9,{..} }
           | i              | z
      { 22,{..} }       { 9,{..} }
           | z              | z
      { 22,{..} }       { 9,{..} }
           | a              | a
      { 22,{..} }       { 9,{..} }
      | i       | p         | i
{ 4,{..} }  { 2,{..} }  { 8,{..} }
      | o       | o         | o
{ 4,{..} }  { 2,{..} }  { 8,{..} }
                | h
            { 2,{..} }

こういうのを「トライ木(Wikipedia)」というらしいです。

探索する際は、

  • 「paiza」を p a i z a と辿ると、そこに書いてある22が答え
  • 「pizza」を p i z z a と辿ると、そこに書いてある9が答え
  • 「p」を p と辿ると、そこに書いてある31が答え
  • 「pu」等、途中でノードが見つからなくなる場合は該当なしとして0

となります。

どうやって合計値を作っていくのかというと、
ツリーの構築時、ノードを辿る度に加算していくのですが
これはコードを見ていただいた方が早いかと思います。

コード

word_collection.js
// Copyright © 2024 https://qiita.com/tanin_no_sorani
// Released under the CC0 1.0 Universal license.
'use strict';

let N = null; // 文字列+価格データの個数 (カウンタを兼任)

class Node { total = 0; index = {}; } // index: { a: Node, b: Node, ... }
const root = new Node(); // ツリー構造のルート

require('node:readline').createInterface({ input: process.stdin })
.on('line', line => {
	// 先頭行 文字列+価格データの数 だけ使う
	if (N === null) { N = Number(line.split(' ')[0]); return; }
	
	let node = root; // 探索は常にルートから始める
	
	if (0 < N--) {
		// 登録
		const [word, price] = line.split(' '); // 文字列と価格
		
		// 1文字ずつ索引を作成
		for (const ch of word) {
			// 次のノードへ辿る、なければノードを新規生成する
			const next = node.index[ch];
			if (next) { node = next; } // 次のノードがあればそのまま進む
			else      { node = node.index[ch] = new Node(); } // なければ作成
			
			node.total += Number(price); // 通ったノードには自身の価格を加算
		}
		
	} else {
		// 購入
		
		// 1文字ずつ辿り、ノードが見つからなかったらその時点で抜ける
		for (const ch of line) { if (!(node = node.index[ch])) { break; } }
		
		// 最後までノードがあった場合はtotalが「必要な金額」、見つからなかった場合は0
		console.log(node ? node.total : 0);
	}
});

感想

配列アクセスの方が速いかな?と思って最初はindexを配列にしていましたが、
paizaのテストケースでは差はなかったので、文字のままObjectに突っ込む形にしました。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?