ラテン語の判断


8

約5秒を超えると何のタスクにも集中できなくなるため、単語をサブストリングに分割することがよくあります。サブストリングはそれぞれ長さが異なり、繰り返し文字が含まれていません。たとえば、「パスタ」という単語を「過去」と「a」、「パス」と「タ」、または「パス」と「スター」に分割すると、画像が表示されます。

ただし、すべての組み合わせを覚えるのは難しいため、通常は1つだけを選択し、最も優れた組み合わせを選択します。最も良い方法は、「スコア」が最も低い方法であると考えています。あなたの仕事は、単語を与えられて、以下の複雑なルールを与えられて、そのスコアを印刷することです。

得点

単語の採点方法の説明:

  • 単語はラテン文字の文字列であり、大文字は同じ小文字の2で置き換える必要があります(したがって、「ボックス」は「bbox」になります)。

  • セグメントは単語の連続した(厳密な)サブストリングであり、文字を2回含めることはできません( "her"、 "re"、 "h"はすべて "Here"( "hhere")の有効なセグメントですが、 "hh"そして「エレ」はそうではありません)

  • セグメンテーションは、長さが異なる一連のセグメントであり、結合すると元の単語を形成し(「tre」と「e」は「tree」を作成)、セグメンテーション内でそれ以上セグメント化できません(つまり、「ba」には単一のセグメンテーション、「ba」、および「alp」と「habet」は、「alphabet」の有効なセグメンテーションではありません。これは、これらのいずれかをさらにセグメント化できるためです(たとえば、現在「a」と「lp」と「habet」)。有効なセグメンテーション(「habet」は、長さ2または1)のセグメントを形成しないとセグメント化できません)))。

  • セグメンテーションのスコアは、元の単語に出現する個別の各文字のスコアの合計です(大文字が置き換えられた後)。

  • キャラクターのスコアリングは以下で説明されています

  • 単語のスコアは、最も良い可能なセグメンテーションのスコアです(スコアが最も低い)。

単語に有効なセグメンテーションが存在しない場合(たとえば、 "Brass"( "bbrass")。最初の "b"と最後の "s"は独自のセグメントになければならないため、セグメント化できません。同じ長さの2つのセグメント)の場合、テキスト「evil」を出力する必要があります。それ以外の場合は、単語のスコアを出力する必要があります。

キャラクター採点

文字のスコアリングは、文字が出現する回数、および出現するセグメントの重み付けに基づいています。セグメントの重み付けは、セグメントの長さと、すべてのセグメントの長さの最小公倍数によって異なります。セグメンテーション。

segment weighting = lowest common multiple of lengths segments / length of segment

「ol」と「ive」に分割され、同じ領域の2つのボックスとして視覚化された「olive」という単語を考えます。1つは重み3の「ol」、もう1つは重み2の「ive」(LCMの6)。

ol
ol ive
ol ive

これは、3つの「ol」から作られた2つのボックスと2つの「ive」から作られた1つのボックスを表すことを意図しています。あるいは、 "o"と "live"(LCM of 4)の場合もあります。

o
o
o
o live

次に、各文字のスコアは、それが表示されるセグメントの重みの合計に、大文字を置き換えた後に表示される回数を掛けたものです(したがって、2回表示される場合は、発声するたびに2倍の料金がかかります)。

character score = character count * sum(segment weights in which character appears)

採点例

「フォール」という言葉を取り上げますが、「ファル」と「l」にしか分割できません。3と1の最小公倍数は3なので、「fal」の重みは1で、「l」の重みは3です。

    l
    l
fal l

各キャラクターを通過する...

  • 「f」は1回出現し、重み「1」のセグメント「fal」にあるため、スコアは1 * 1 = 1です。

  • 「a」も1回だけ出現し、重みの合計が1であるため、スコアは1 * 1 = 1です。

  • 「l」は2回出現し、「fal」(重み1)と「l」(重み3)に出現するため、スコアは2 *(1 + 3)= 8です。

これらの合計は10です(セグメンテーションのスコアと、これが最も優れたセグメンテーションであるため、単語のスコア)。これは、以下の例と同じ形式です。

fall = fal l
2*1 [fa] + 2*(1+3) [ll] = 10

スコアリングの例

これらのスコアリングの例は、役立つ場合とそうでない場合があります。

class -> clas s
3*1 [cla] + 2*(4+1) [ss] = 13

fish -> fis h
3*1 [fis] + 1*3 [h] = 6

eye -> e ye
1*1 [y] + 2*(1+2) [ee] = 7

treasure -> treas u re
3*2 [tas] + 2*2*(2+5) [rree] + 1*10 [u] = 44

Wolf -> w wolf
3*1 [olf] + 2*(1+4) = 13

book
evil

「本」は邪悪な言葉なのでスコアがありません。

「宝物」はいくつかの方法でセグメント化できますが、示されているセグメント化では、長いセグメントで文字(「r」と「e」)が頻繁に使用されることでメリットが得られるため、重みはそれほど大きくありません。セグメンテーション "t"& "re"& "asure"は同じ結果になりますが、 "treas"& "ur"& "e"は影響を受け、 "e"は2 *(1 + 10 + 2 )=単独で24。この観察は、実際には全体の練習の精神です。「宝」の誤ったスコアの例(最も良いセグメンテーションのスコア(最も低いスコアのスコア)から派生していないため、正しくありません):

treasure = treas ur e
3*2 [tas] + 2*(2+5) [rr] + 1*5 [u] + 2*[2+10] = 49

入力

どちらの場合もラテン文字のみを含む単一の文字列(「horse」、「Horse」、および「hOrSe」はすべて有効な入力です)。STDIN、コマンドライン引数、関数引数、または言語が選択は前述のいずれもサポートしません。

出力

0より大きい単一の正の整数である単語のスコア、またはセグメンテーションが存在しない場合は「悪」のいずれかを出力する必要があります。選択した言語がこれらのどちらもサポートしていない場合を除き、出力はSTDOUTまたは関数の戻り引数にする必要があります。その場合、スポーツマン的に動作します。

私はあなたがこのすべてのものを印刷することを期待していません、私が欲しいのは単語のスコア、または出力「悪」、たとえば(入力の後に出力)だけです

eye
7

Eel
evil

a
1

Establishments
595

antidisestablishmentarianism
8557

私はパフォーマンスに関心はありません。賢明な(意図的に曖昧に残された)マシンで1分以内に(大文字を置き換えた後)約15文字の単語をスコア付けできれば、それで十分です。

これはコードゴルフです、最短のコードが勝つかもしれません。

この課題を解決してくれたPeterTaylor、MartinBüttner、SP3000に感謝


4
5秒以上タスクに集中できない場合は、このチャレンジを書くことは、あなたを永遠に連れて行ったに違いありません。
Alex A.

回答:


5

Mathematica、373バイト

If[l=Length;a=Accumulate[l/@#]&;u=Unequal;e=Select;{}==(m=(g=#;Tr[#2Flatten[ConstantArray[#,LCM@@l/@g/l@#]&/@g]~Count~#&@@@Tally@c])&/@e[p=e[c~Internal`PartitionRagged~#&/@Join@@Permutations/@IntegerPartitions[l[c=Characters[s=StringReplace[#,c:"A"~CharacterRange~"Z":>(d=ToLowerCase@c)<>d]]]],u@@l/@#&&And@@u@@@#&],FreeQ[p,l_List/;#!=l&&SubsetQ[a@l,a@#]]&]),"evil",Min@m]&

これはかなり長いです...そして、どちらかと言えば素朴です。文字列を取り、スコアを返す名前のない関数を定義します。処理に約1秒かかる"Establishments"ため、制限時間内です。を使用する少し短いバージョンを持っCombinatorica`SetPartitionsていますが、にはすでに1分かかります"Establishme"

ここに空白があるバージョンがあります:

If[
  l = Length;
  a = Accumulate[l /@ #] &;
  u = Unequal;
  e = Select;
  {} == (
    m = (
      g = #;
      Tr[
        #2 Flatten[
          ConstantArray[
            #, 
            LCM @@ l /@ g/l@#
          ] & /@ g
        ]~Count~# & @@@ Tally@c
      ]
    ) & /@ e[
      p = e[
        c~Internal`PartitionRagged~# & /@ Join @@ Permutations /@ IntegerPartitions[
          l[
            c = Characters[
              s = StringReplace[
                #, 
                c : "A"~CharacterRange~"Z" :> (d = ToLowerCase@c) <> d
              ]
            ]
          ]
        ], 
        u @@ l /@ # && And @@ u @@@ # &
      ], 
      FreeQ[p, l_List /; # != l && SubsetQ[a@l, a@#]] &
    ]
  ),
  "evil",
  Min@m
] &

後でもっと詳しい説明を追加するかもしれません。このコードは、この回答の 2番目のソリューション使用してすべてのパーティションを取得し、このソリューションはそれらがすべて最大限にセグメント化されていることを確認します。


2

Java 8、1510 1485バイト

これは、が長すぎます。組合せ論はJavaでは決して簡単ではありません。それは間違いなくかなり短くすることができます。に電話してくださいa(string)。これは、指数メモリと時間アルゴリズムを使用します。したがって、長い入力に対して機能するとは期待しないでください。処理には約0.5秒かかりますEstablishments。のメモリ不足エラーでクラッシュしますantidisestablishmentarianism

import java.util.*;import java.util.stream.*;void a(String a){a=a.replaceAll("\\p{Upper}","$0$0").toLowerCase();List<List<String>>b=b(a),c;b.removeIf(d->d.stream().anyMatch(e->e.matches(".*(.).*\\1.*")));b.removeIf(d->{for(String e:d)for(String f:d)if(e!=f&e.length()==f.length())return 1>0;return 1<0;});c=new ArrayList(b);for(List<String>d:b)for(List<String>e:b){if(d==e)continue;int f=0,g=0;List h=new ArrayList(),i=new ArrayList();for(String j:d)h.add(f+=j.length());for(String k:e)i.add(g+=k.length());if(i.containsAll(h))c.remove(d);else if(h.containsAll(i))c.remove(e);}b=c;int d=-1;for(List e:b)d=d<0?c(e):Math.min(c(e),d);System.out.println(d<0?"evil":d);}int c(List<String>a){List<Integer>b=a.stream().map(c->c.length()).collect(Collectors.toList()),d;int e=d(b.toArray(new Integer[0])),f=0,g=0,h;d=b.stream().map(A->e/A).collect(Collectors.toList());Map<Character,Integer>i=new HashMap(),j=new HashMap();for(;g<a.size();g++){h=d.get(g);String k=a.get(g);for(char l:k.toCharArray()){i.put(l,i.getOrDefault(l,0)+1);j.put(l,j.getOrDefault(l,0)+h);}}for(char k:i.keySet())f+=i.get(k)*j.get(k);return f;}int d(Integer...a){int b=a.length,c,d,e;if(b<2)return a[0];if(b>2)return d(a[b-1],d(Arrays.copyOf(a,b-1)));c=a[0];d=a[1];for(;d>0;d=c%d,c=e)e=d;return a[0]*a[1]/c;}List b(String a){List<List>b=new ArrayList(),c;for(int i=0;++i<a.length();b.addAll(c)){String d=a.substring(0,i),e=a.substring(i);c=b(e);for(List f:c)f.add(0,d);}b.add(new ArrayList(Arrays.asList(a)));return b;}

ここで試してください

説明でインデント:

void a(String a){
    a = a.replaceAll("\\p{Upper}", "$0$0").toLowerCase();                //Replace all uppercase letters with two lowercase letters

    List<List<String>> b = b(a), c;                                      //Generate partitions
    b.removeIf(d -> d.stream().anyMatch(e -> e.matches(".*(.).*\\1.*")));//Remove partitions that contains duplicate letters

    b.removeIf(d -> {                                                    //Remove partitions that have equal length parts
        for (String e : d)
            for (String f : d)
                if (e != f & e.length() == f.length())
                    return 1 > 0;
        return 1 < 0;
    });

    c = new ArrayList(b);                                                //Remove partitions that can be partitioned further
    for (List<String> d : b)                                             //Uses Martin's technique
        for (List<String> e : b){
            if (d == e)
                continue;
            int f = 0, g = 0;
            List h = new ArrayList(), i = new ArrayList();
            for (String j : d)
                h.add(f += j.length());
            for (String k : e)
                i.add(g += k.length());
            if (i.containsAll(h))
                c.remove(d);
            else if (h.containsAll(i))
                c.remove(e);
        }

    b = c;

    int d = -1;
    for (List e : b)
        d = d < 0 ? c(e) : Math.min(c(e), d);                            //Find nicest partition

    System.out.println(d < 0 ? "evil" : d);
}

int c(List<String> a) {                                                  //Grade a partition
    List<Integer> b = a.stream().map(c->c.length()).collect(Collectors.toList()), d; //Map to length of parts

    int e = d(b.toArray(new Integer[0])), f = 0, g = 0, h;

    d = b.stream().map(A -> e / A).collect(Collectors.toList());         //Figure out the weight of each part

    Map<Character, Integer> i = new HashMap(), j = new HashMap();

    for (; g < a.size(); g++){                                           //Count instances of each character and
        h = d.get(g);                                                    //weight of each character
        String k = a.get(g);
        for (char l : k.toCharArray()){
            i.put(l, i.getOrDefault(l, 0) + 1);
            j.put(l, j.getOrDefault(l, 0) + h);
        }
    }

    for (char k : i.keySet())
        f += i.get(k) * j.get(k);                                        //Sum cost of each character

    return f;
}

int d(Integer... a) {                                                    //Find lcm
    int b = a.length, c, d, e;
    if (b < 2)
        return a[0];
    if (b > 2)
        return d(a[b - 1], d(Arrays.copyOf(a, b - 1)));
    c = a[0];
    d = a[1];
    for (;d > 0;d = c % d, c = e)
        e = d;
    return a[0] * a[1] / c;
}

List b(String a) {                                                       //Find all partitions of a string
    List<List> b = new ArrayList(), c;                                   //Uses recursion
    for (int i = 0; ++i < a.length();b.addAll(c)){
        String d = a.substring(0, i), e = a.substring(i);
        c = b(e);
        for (List f : c)
            f.add(0, d);
    }
    b.add(new ArrayList(Arrays.asList(a)));
    return b;
}

これは、バイト数を減らすためにジェネリックをかなり乱用します。すべてをコンパイルできるようになったことにかなり驚いています。

ありがとうYpnypn :)


わあ、これは印象的です!いくつかのゴルフのメモ:i.put...行とwhileループに余分なスペースがあります。私 while(d!=0)できると思いますwhile(d>0)。とにかく与えるnew ArrayListので、最後に必要はありません。最後のメソッドでは、プレーンとして定義できます。Arrays.asListArrayListbList
Ypnypn 2015年

@Ypnypn提案をありがとうございます:) Arrays.asListは変更ArrayListできないので、を取得せずにそれを使用することはできませんOperationNotSupportedExceptionb単純なリストにすることもできますが、そのcままにする必要がありますList<List<String>>while(d>0)明日動作するかどうか確認します。
TheNumberOne 2015年

2

C#679バイト

このソリューションは、元のテスト実装の構造に大まかに基づいており、当初は単なる書き直しでしたが、その後、すべての関数をインライン化したので、恐ろしいものになりました。それはかなり速く、1秒未満で施設を解決します。これは、入力ワードをARGVの単一のパラメーターとして受け取る完全なプログラムです。

using Q=System.String;class P{static void Main(Q[]A){Q s="";foreach(var c in A[0]){var z=(char)(c|32);if(c<z)s+=z;A[0]=s+=z;}int r=S(A);System.Console.WriteLine(r<1?"evil":""+r);}static int S(Q[]s){int r=0,t,j,k,L=1,Z=s.Length,i=Z,T=0,R=2;for(;i-->0;R=t<1?0:R){t=s[i].Length;k=L;for(j=2;t>1;)if(t%j++<1){t/=--j;if(k%j<1)k/=j;else L*=j;}}foreach(var C in Q.Join("",s))for(i=Z;i-->0;){for(k=s[j=i].Length;j-->0;)R=k==s[j].Length?0:R;j=s[i].IndexOf(C)+1;R=j*R*s[i].IndexOf(C,j)>1?1:R;T+=j>0?L/k:0;}i=R<1?0:Z;for(var U=new Q[Z+1];i-->0;)for(j=s[i].Length;j-->1;r=r<1|((t=S(U))>0&t<r)?t:r)for(U[k=Z]=s[i].Substring(j);k-->0;U[i]=s[i].Substring(0,j))U[k]=s[k];return r<1?R<2?R-1:T:r;}}

このMainメソッドは、大文字が置き換えられた入力のコピーを作成することから始まります。次に、S、「ソルバー」をます。これは、特定のセグメンテーションのスコアを返します(最初のセグメンテーションは、単語全体である単一のセグメントによるものです)。次に、スコアに応じて「悪」またはスコアのいずれかを出力します。

「ソルバー」(S)はすべての興味深いことを実行し、最初は4つのメソッドに分解され、一緒にロールされました。これは、まず現在のセグメンテーションをスコアリングして、それが無効かどうかをメモします(そして、非常に無効であるかどうかを確認します(パフォーマンスのために)それ以上セグメント化しないでください。そうでない場合は、残りの計算をスキップします)。 。次に、スキップされていない場合は、分割可能なすべての場所でセグメンテーションの各セグメントを分割し、これらすべての中で最高のスコアを見つけます(再帰的にS)。最後に、下位のセグメンテーションの最高のスコアを返します。それ以外の場合は独自のスコアを返します。独自のセグメンテーションが無効な場合は無効です。

コメント付きのコード:

using Q=System.String; // this saves no bytes now

class P
{
    // boring
    static void Main(Q[]A)
    {
        // this can surely be shorter
        // replace capitals
        // I refuse to put this in S (would give us a Q, but we'd have to pay for the Action=null)
        Q s="";

        foreach(var c in A[0])
        {
            var z=(char)(c|32); // ugly
            if(c<z)
                s+=z; // ugly
            A[0]=s+=z; // reuse the array
        }

        int r=S(A); // reuse the array
        System.Console.WriteLine(r<1?"evil":""+r);
    }

    // solve
    static int S(Q[]s) // s is current solution
    {        
        int r=0,t,j,k,
        L=1,Z=s.Length,i=Z,
        T=0, // is score for this solution (segmentation)
        R=2; // R is current return value, as such, 0 -> return -1, 1 -> return 0, 2 -> return T

        // score first
        // factorise stuff, L is LCM
        for(;
            i-->0; // for each segment
            R=t<1?0:R) // segment too short (skip)
        {
            t=s[i].Length;

            k=L; // we cut up k as we cut up c, when we can't cut up k, we need to build up L
            for(j=2;t>1;)
                if(t%j++<1) // j goes into t
                {
                    t/=--j; // cut up t
                    if(k%j<1) // j goes into k
                        k/=j; // cut up k
                    else
                        L*=j; // j does not go into k, build up L
                }
        }

        // recycle i, j, k, (t)

        foreach(var C in Q.Join("",s)) // for each character
            for(i=Z;i-->0;) // for each segment
            {
                for(k=s[j=i].Length;
                    j-->0;) // for all the segments that follow
                    R=k==s[j].Length?0:R; // repeat length (skip)

                j=s[i].IndexOf(C)+1;

                // these both check if this segment contains the char (j > 0)
                R=j*R*s[i].IndexOf(C,j)>1?1:R; // duplicate char (allow)

                T+=j>0?L/k:0; // add on the segment weight
            }

        // R is whether we are invalid or not
        // T is our score

        i=R<1?0:Z; // if segmentation invalid and can't be segmented, skip everything (performance)

        // recycle i, j, k, t
        // first use of r=0

        for(var U=new Q[Z+1];
            i-->0;) // for each segment
            for(j=s[i].Length;
                j-->1; // for each place we can split it
                r=r<1|((t=S(U))>0&t<r)?t:r) // solve where we split thing at i at position j, if this score is better than r, replace r with it
                for(U[k=Z]=s[i].Substring(j); // put second half of s[i] in last position (order doesn't matter)
                    k-->0; // for each char in s[i]
                    U[i]=s[i].Substring(0,j)) // put first half of s[i] in p position
                    U[k]=s[k]; // copy across everything else

        return r<1?R<2?R-1:T:r; // if we didn't find a valid solution more segmented than this, return our score (unless we are invalid, in which case, return R-1), else the score for the more segmentation solution
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.