C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で解くセンテンス・スクリーンフィッティング:文章がスクリーンに収まる回数を求める


問題概要

rows × cols のサイズを持つスクリーンと、空でない単語からなるリストで表現された文(センテンス)が与えられます。このとき、与えられた文がスクリーン上に何回完全に収まるかを求めます。この問題には以下の条件があります。

  • 単語が2行にまたがって分割されることはありません。
  • 文中の単語の並び順は変更してはいけません。
  • 隣接する単語の間にはスペースが1つだけ入ります。
  • 文に含まれる単語の総数は100を超えません。
  • 各単語の長さは1以上10未満です。
  • 1 ≤ rows, cols ≤ 20,000 です。

例として、rows = 3、cols = 6、文が ["a", "bcd", "e"] である場合の出力は 2 となります。

解法の考え方

この問題は、各行の開始位置ごとに「その行に何個の単語が入るか」をキャッシュするメモ化を用いることで、効率的に解くことができます。手順は以下の通りです。

  • マップ dp を用意し、ret := 0、n := 文の配列のサイズ とします。
  • row が 0 でない間、以下を繰り返します。
    • start := ret mod n、len := -1、cnt := 0 と初期化します。
    • start が dp に存在しない場合は、次の処理を行います。
      • 「1 + len + sentence[(start + cnt) mod n] の長さ ≤ cols」が成り立つ間、次を繰り返します。
        • len := 1 + len + sentence[(start + cnt) mod n] の長さ と更新する。
        • cnt を 1 増やす。
      • dp[start] := cnt と記録し、ret := ret + cnt とします。
    • それ以外の場合は、すでに計算済みの値を使って ret := ret + dp[start] とします。
    • row を 1 減らします。
  • 最後に ret / n を返します。

開始位置(start)ごとの結果をキャッシュしておけば、同じ開始位置が再び現れた際は O(1) で処理できるため、rows と cols が最大 20,000 に達するような大きな入力でも高速に動作します。

C++での実装例

理解を深めるために、以下の実装例をご覧ください。

#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
    int wordsTyping(vector<string>& sentence, int rows, int cols) {
        unordered_map<int, int> dp;
        int ret = 0;
        int n = sentence.size();
        while(rows--){
            int start = ret % n;
            int len = -1;
            int cnt = 0;
            if(!dp.count(start)){
                while(1 + len + (int)sentence[(start + cnt) % n].size() <= cols){
                    len = 1 + len + sentence[(start + cnt) % n].size();
                    cnt++;
                }
                dp[start] = cnt;
                ret += cnt;
            }
            else{
                ret += dp[start];
            }
        }
        return ret / n;
    }
};
main(){
    vector<string> v = {"a","bcd","e"};
    Solution ob;
    cout << (ob.wordsTyping(v, 3, 6));
}

入力

["a","bcd","e"]
3
6

出力

2
  1. C++のreference_wrapperとは?基本的な使い方をわかりやすく解説

    reference_wrapperとはC++のstd::reference_wrapperは、参照(T&)をコピー構築可能かつコピー代入可能なオブジェクトでラップするクラステンプレートです。<functional>ヘッダーで定義されており、名前空間std内で提供されます。std::reference_wrapperのインスタンスは本質的にはオブジェクトですが、暗黙的にT&へ変換することが可能です。そのため、基となる型を参照引数として受け取る関数に対して、通常のオブジェクトと同じように渡すことができます。主な特徴コピー構築・コピー代入が可能な「参照のような」振る舞いを

  2. C++で再帰を使って文字列(文)を反転表示する方法

    文字列とは、NULL文字(\0)で終端される1次元の文字配列のことです。文字列の反転とは、同じ文字列を逆順に並べたものを指します。例えば以下のようになります。 元の文字列: Apple is red 反転後の文字列: der si elppA ここでは、再帰(リカーション)を利用して、文字列として与えられた文を反転して表示するC++プログラムを紹介します。 プログラム例 #include <iostream> using namespace std; void reverse(char *str) { if(*str == \0) return;