1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめての記事投稿
Qiita Engineer Festa20242024年7月17日まで開催中!

bufio で string を取ろうとして詰まった話

Last updated at Posted at 2024-06-16

RE?

Atcoder で https://atcoder.jp/contests/abc237/tasks/abc237_d を解いていて、
テストケースのうち数ケースのみ RE ( Runtime Error ) になってしまった。

image.png

原因

自分の実装

bufio の scanner をこんな感じで使っていたのが原因

var sc = bufio.NewScanner(os.Stdin)

func main(){
    sc.Split(bufio.ScanWords)
    s:=scanString()
}

func scanString() (s string) {
	sc.Scan()
	s = sc.Text()
	return
}

ソースコード

定数

const (
	// MaxScanTokenSize is the maximum size used to buffer a token
	// unless the user provides an explicit buffer with [Scanner.Buffer].
	// The actual maximum token size may be smaller as the buffer
	// may need to include, for instance, a newline.
	MaxScanTokenSize = 64 * 1024

	startBufSize = 4096 // Size of initial allocation for buffer.
)

MaxScanTokenSize を最大のバッファサイズ
startBufSize をはじめに確保されるバッファのサイズ
として定義されている

bufio.NewScanner の実装

func NewScanner(r io.Reader) *Scanner {
	return &Scanner{
		r:            r,
		split:        ScanLines,
		maxTokenSize: MaxScanTokenSize,
	}
}

bufio.NewScanner を呼ぶと、Scanner に対して maxTokenSize が設定される

func (s *Scanner) Scan() bool の実装

func (s *Scanner) Scan() bool {
    
    // 省略
    ...
    
    // バッファサイズが最大トークンサイズを超えていないかチェック
    if len(s.buf) >= s.maxTokenSize || len(s.buf) > maxInt/2 {
        s.setErr(ErrTooLong)
        return false
    }
    
    ...
    // 省略
    ...
    
    // バッファサイズの初期化
    if newSize == 0 {
        newSize = startBufSize
    }
    
    ...
    // 省略
}

上のチェックの部分は、今回のエラーの原因であると考えられる
下の部分で、バッファが確保されていない場合 ( 初期の状態 ) 、startBufSize の 4096 bytes が指定される

解決

今回の Atcoder の問題では、入力される string のサイズの制約が

1\le n \le5×10^5

となっていたので デフォルトのバッファサイズの最大値である 64 * 1024 = 65,536 を超えてしまった
以下のコードを Scan() を行う前に記述することで解決した

sc.Buffer(make([]byte, 64*1024), 1e6)

これは、scanner が使用するバッファを指定するもの

  • 第 1 引数の []byte は初期バッファ
    今回は、デフォルトの最大 64 * 1024 = 65,536 を超えることがわかっていたので、初めから 64 * 1024 のサイズを確保した

  • 第 2 引数の 1e6 は最大バッファサイズ
    最大 1*10^6 文字と少し多めにとっている
    開発に使用するなら、2 の累乗単位で取るべきなのかもしれないが、今回は競技プログラミングなので深く考えなかった

まとめ

競技プログラミングで bufio パッケージを使用するときは、適切なバッファサイズの設定が重要。
特に大量のデータを扱う場合には、事前に適切なサイズを確保する。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?