Bahasa Inggris majemuk


28

Kata majemuk adalah kata yang mengandung 2 atau lebih kata di dalamnya. Kita bisa melakukan lebih baik dari itu. Kami membutuhkan Anda untuk membuat 1 kata (tidak masuk akal) yang berisi setiap kata .

Namun, kami ingin kata ini sesingkat mungkin. Kita dapat menggunakan huruf yang tumpang tindih untuk mencapai ini.

Misalnya, jika daftar kata Anda adalah ["cat", "atom", "a"], Anda ingin kembali "catom".

Input output

Program Anda perlu mengambil daftar kata sebagai input, dan mengembalikan kata majemuk sebagai output.

Daftar kata yang akan Anda gunakan adalah 10.000 kata teratas dalam bahasa Inggris, menurut Google (Jika daftar ini ternyata terlalu mudah, saya dapat mengubahnya menjadi lebih panjang). Sebagai referensi, cukup menambahkan setiap kata memberi Anda skor 65888.

Skor Anda adalah jumlah huruf dalam kata akhir Anda, lebih rendah lebih baik. Tie breaker menuju ke poster pertama.



1
@Loovjo tidak, tetapi jika berakhir dengan bruteforcing cukup cepat untuk dijalankan, maka saya akan mengubah daftar kata untuk membuatnya lebih lama.
Nathan Merrill

1
@ PatrickRoberts Jika cocok dengan jawaban Anda, alat bantu untuk Anda :) Tautan pastebin / inti akan bagus, tetapi tidak diperlukan.
Nathan Merrill

1
Hmm, siapa yang kenal heuristik salesman keliling asimetris yang baik?
Dave

2
Tidak ada pembungkus, dan ya untuk deterministik.
Nathan Merrill

Jawaban:


26

C ++, panjang kata terakhir: 38272

(versi yang dioptimalkan memakan waktu sekitar 20 menit)

#include <iostream>
#include <string>
#include <vector>

std::size_t calcOverlap(const std::string &a, const std::string &b, std::size_t limit, std::size_t minimal) {
    std::size_t la = a.size();
    for(std::size_t p = std::min(std::min(la, b.size()), limit + 1); -- p > minimal; ) {
        if(a.compare(la - p, p, b, 0, p) == 0) {
            return p;
        }
    }
    return 0;
}

int main() {
    std::vector<std::string> words;

    // Load all words from input
    while(true) {
        std::string word;
        std::getline(std::cin, word);
        if(word.empty()) {
            break;
        }
        words.push_back(word);
    }

    std::cerr
        << "Input word count: " << words.size() << std::endl;

    // Remove all fully subsumed words

    for(auto p = words.begin(); p != words.end(); ) {
        bool subsumed = false;
        for(auto i = words.begin(); i != words.end(); ++ i) {
            if(i == p) {
                continue;
            }
            if(i->find(*p) != std::string::npos) {
                subsumed = true;
                break;
            }
        }
        if(subsumed) {
            p = words.erase(p);
        } else {
            ++ p;
        }
    }

    std::cerr
        << "After subsuming checks: " << words.size()
        << std::endl;

    // Sort words longest-to-shortest (not necessary but doesn't hurt. Makes finding maxlen a tiny bit easier)
    std::sort(words.begin(), words.end(), [](const std::string &a, const std::string &b) {
        return a.size() > b.size();
    });

    std::size_t maxlen = words.front().size();

    // Repeatedly combine most-compatible words until there is only one left
    std::size_t bestPossible = maxlen - 1;
    while(words.size() > 1) {
        auto bestA = words.begin();
        auto bestB = -- words.end();
        std::size_t bestOverlap = 0;
        for(auto p = ++ words.begin(), e = words.end(); p != e; ++ p) {
            if(p->size() - 1 <= bestOverlap) {
                continue;
            }
            for(auto q = words.begin(); q != p; ++ q) {
                std::size_t overlap = calcOverlap(*p, *q, bestPossible, bestOverlap);
                if(overlap > bestOverlap) {
                    bestA = p;
                    bestB = q;
                    bestOverlap = overlap;
                }
                overlap = calcOverlap(*q, *p, bestPossible, bestOverlap);
                if(overlap > bestOverlap) {
                    bestA = q;
                    bestB = p;
                    bestOverlap = overlap;
                }
            }
            if(bestOverlap == bestPossible) {
                break;
            }
        }
        std::string newStr = std::move(*bestA);
        newStr.append(*bestB, bestOverlap, std::string::npos);

        if(bestA == -- words.end()) {
            words.pop_back();
            *bestB = std::move(words.back());
            words.pop_back();
        } else {
            *bestB = std::move(words.back());
            words.pop_back();
            *bestA = std::move(words.back());
            words.pop_back();
        }

        // Remove any words which are now in the result
        for(auto p = words.begin(); p != words.end(); ) {
            if(newStr.find(*p) != std::string::npos) {
                std::cerr << "Now subsumes: " << *p << std::endl;
                p = words.erase(p);
            } else {
                ++ p;
            }
        }

        std::cerr
            << "Words remaining: " << (words.size() + 1)
            << " Latest combination: (" << bestOverlap << ") " << newStr
            << std::endl;

        words.push_back(std::move(newStr));
        bestPossible = bestOverlap; // Merging existing words will never make longer merges possible
    }

    std::string result = words.front();

    std::cout
        << result
        << std::endl;
    std::cerr
        << "Word size: " << result.size()
        << std::endl;
    return 0;
}

Verifikasi bash satu baris:

cat commonwords.txt | while read p; do grep "$p" merged.txt >/dev/null || echo "Not found: $p"; done

Itu juga menghasilkan beberapa kata dalam proses yang cukup keren. Inilah beberapa favorit saya:

  • poly Kemarin (nostalgia sintetis)
  • afghanistanbul (sesuatu [masukkan politisi yang Anda sukai] akan katakan)
  • togethernet (internet yang ramah)
  • elephantom (hantu besar)
  • thundergroundwaterproof (seperti pada "Saya tidak tahu mengapa mereka merasa perlu untuk membuatnya thundergroundwaterproof, tapi itu membuat saya gugup")

Dan:

  • codescribingo (mungkin tantangan yang akan datang di situs ini?)

Hasil akhirnya adalah pastebin di sini: http://pastebin.com/j3qYb65b


2
Pengamatan yang mungkin berguna bagi orang lain yang mencari untuk mendapatkan solusi optimal: masalahnya dapat dikurangi menjadi non-euclidean, masalah salesman keliling yang asimetris: mendefinisikan matriks di mana elemen i, j = max_word_length - overlap(word[i], word[j])(di mana overlapmemeriksa tumpang tindih dari kanan argumen pertama di sebelah kiri yang kedua). Memecahkan ini (semoga berhasil!) Kemudian memotong loop yang dihasilkan dengan biaya tertinggi (tumpang tindih terendah) akan memberikan daftar kata yang terurut yang dapat digabungkan untuk memberikan solusi yang optimal.
Dave

Impresif. Apakah ini memeriksa setiap kata dalam daftar saat ini terhadap satu sama lain, setiap kali lewat? Saya sedang mempertimbangkan ini tetapi berasumsi bahwa saya perlu memeriksa sampel acak untuk membuatnya berjalan dalam waktu yang wajar.
trichoplax

1
@ ValueInk ya, caching akan menjadi pendorong kinerja besar. Versi sebelumnya memiliki itu, tetapi itu menambah banyak kompleksitas, jadi ketika saya mengadaptasi beberapa logika saya harus menulis ulang lot. Sebaliknya saya memilih untuk menghentikan caching. Juga tidak, ini tidak sepenuhnya optimal. Ini adalah algoritma serakah sehingga tidak bisa menilai pertukaran, dan tidak dapat memilih antara opsi "sama bagusnya". Lihat komentar TSP saya untuk solusi optimal (NP-Hard).
Dave

1
@trichoplax ya, itu yang dilakukannya. Waktu berjalan adalah O (n ^ 3), yang tidak terlalu buruk untuk ukuran sampel ini. Dengan caching dapat dikurangi menjadi O (n ^ 2). Pemeriksaan dalam juga sangat paralel, sehingga bahkan untuk sampel yang lebih besar dapat berjalan dalam waktu yang wajar dengan perhitungan threading / distribusi. Juga ini mendapat dorongan kecepatan besar dari mengetahui kisaran lebar yang mungkin tumpang tindih untuk setiap langkah, yang memotong runtime dengan faktor 10.
Dave

2
Ini mungkin tidak sesulit TSP umum, karena kami memiliki kendala lucu yang tumpang tindih (a, b) ≥ min {tumpang tindih (a, d), tumpang tindih (c, d), tumpang tindih (c, b)} untuk semua , b, c, d.
Anders Kaseorg

21

C ++ 11, 38272 huruf, terbukti optimal

Algoritma ini dijamin untuk memberikan batas bawah pada solusi. Dalam hal ini, ia mampu mencapai batas bawah dan menghasilkan solusi 38272 huruf yang optimal. (Ini cocok dengan solusi yang ditemukan oleh algoritma serakah Dave. Saya terkejut dan sedikit kecewa menemukan bahwa itu optimal, tetapi, di sinilah kita.)

Ia bekerja dengan memecahkan masalah aliran biaya minimum pada jaringan yang dibangun sebagai berikut.

  • Pertama, setiap kata yang terkandung dalam kata-kata lain berlebihan; Buang mereka.
  • Untuk setiap kata w , gambar dua simpul w _0 dan w _1, di mana w _0 adalah sumber dengan kapasitas 1 dan w _1 adalah wastafel dengan kapasitas 1.
  • Untuk setiap (ketat) awalan atau akhiran suatu kata apapun, menggambar simpul a .
  • Untuk setiap sufiks a dari w , gambarlah sebuah busur dari w _0 ke a dengan kapasitas 1 dan biaya 0.
  • Untuk setiap awalan a dari w , gambarlah busur dari a ke w _1 dengan kapasitas 1 dan panjang biaya ( w ) - panjang ( a ).

Setiap string dengan panjang n yang berisi setiap kata dapat dikonversi menjadi aliran di jaringan ini dengan biaya paling banyak n . Oleh karena itu, aliran biaya minimum pada jaringan ini adalah batas bawah pada panjang string tersingkat tersebut.

Jika kita beruntung — dan dalam hal ini kita adalah — maka setelah kita mengarahkan kembali aliran ke w _1 kembali dari w _0, kita akan menemukan aliran optimal yang hanya memiliki satu komponen yang terhubung dan yang melewati node untuk kosong tali. Jika demikian, ini akan berisi sirkuit Euler mulai dan berakhir di sana. Sirkuit Euler seperti itu dapat dibaca kembali sebagai string dengan panjang optimal.

Jika kita tidak beruntung, tambahkan beberapa busur tambahan antara string kosong dan string terpendek di komponen yang terhubung lainnya untuk memastikan bahwa ada sirkuit Euler. String tidak lagi optimal dalam hal ini.

Saya menggunakan perpustakaan LEMON untuk aliran min-cost dan algoritma sirkuit Eulerian. (Ini adalah pertama kalinya saya menggunakan perpustakaan ini, dan saya terkesan — saya pasti akan menggunakannya lagi untuk kebutuhan algoritma grafik di masa depan.) LEMON hadir dengan empat algoritma aliran biaya minimum yang berbeda; Anda bisa mencobanya di sini dengan --net, --cost, --cap, dan --cycle(default).

Program berjalan dalam 0,5 detik , menghasilkan string keluaran ini .

#include <iostream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <lemon/core.h>
#include <lemon/connectivity.h>
#include <lemon/euler.h>
#include <lemon/maps.h>
#include <lemon/list_graph.h>
#include <lemon/network_simplex.h>
#include <lemon/cost_scaling.h>
#include <lemon/capacity_scaling.h>
#include <lemon/cycle_canceling.h>

using namespace std;

typedef lemon::ListDigraph G;

struct Word {
    G::Node suffix, prefix;
    G::Node tour_node;
};

struct Edge {
    unordered_map<string, Word>::iterator w;
    G::Arc arc;
};

struct Affix {
    vector<Edge> suffix, prefix;
    G::Node node;
    G::Node tour_node;
};

template<class MCF>
bool solve(const G &net, const G::ArcMap<int> &lowerMap, const G::ArcMap<int> &upperMap, const G::ArcMap<int> &costMap, const G::NodeMap<int> &supplyMap, int &totalCost, G::ArcMap<int> &flowMap)
{
    MCF mcf(net);
    if (mcf.lowerMap(lowerMap).upperMap(upperMap).costMap(costMap).supplyMap(supplyMap).run() != mcf.OPTIMAL)
        return false;
    totalCost = mcf.totalCost();
    mcf.flowMap(flowMap);
    return true;
}

int main(int argc, char **argv)
{
    clog << "Reading dictionary from stdin" << endl;
    unordered_map<string, Affix> affixes;
    unordered_map<string, Word> words;
    unordered_set<string> subwords;
    G net, tour;
    G::ArcMap<int> lowerMap(net), upperMap(net), costMap(net);
    G::NodeMap<int> supplyMap(net);
    string new_word;
    while (getline(cin, new_word)) {
        if (subwords.find(new_word) != subwords.end())
            continue;
        for (auto i = new_word.begin(); i != new_word.end(); ++i) {
            for (auto j = new_word.end(); j != i; --j) {
                string s(i, j);
                words.erase(s);
                subwords.insert(s);
            }
        }
        words.emplace(new_word, Word());
    }
    for (auto w = words.begin(); w != words.end(); ++w) {
        w->second.suffix = net.addNode();
        supplyMap.set(w->second.suffix, 1);
        w->second.prefix = net.addNode();
        supplyMap.set(w->second.prefix, -1);
        for (auto i = w->first.begin(); ; ++i) {
            affixes.emplace(string(w->first.begin(), i), Affix()).first->second.prefix.push_back(Edge {w});
            affixes.emplace(string(i, w->first.end()), Affix()).first->second.suffix.push_back(Edge {w});
            if (i == w->first.end())
                break;
        }
        w->second.tour_node = tour.addNode();
    }
    for (auto a = affixes.begin(); a != affixes.end();) {
        if (a->second.suffix.empty() || a->second.prefix.empty() ||
            (a->second.suffix.size() == 1 && a->second.prefix.size() == 1 &&
             a->second.suffix.begin()->w == a->second.prefix.begin()->w)) {
            affixes.erase(a++);
        } else {
            a->second.node = net.addNode();
            supplyMap.set(a->second.node, 0);
            for (auto &e : a->second.suffix) {
                e.arc = net.addArc(e.w->second.suffix, a->second.node);
                lowerMap.set(e.arc, 0);
                upperMap.set(e.arc, 1);
                costMap.set(e.arc, 0);
            }
            for (auto &e : a->second.prefix) {
                e.arc = net.addArc(a->second.node, e.w->second.prefix);
                lowerMap.set(e.arc, 0);
                upperMap.set(e.arc, 1);
                costMap.set(e.arc, e.w->first.length() - a->first.length());
            }
            a->second.tour_node = lemon::INVALID;
            ++a;
        }
    }

    clog << "Read " << words.size() << " words and found " << affixes.size() << " affixes; ";
    clog << "created network with " << countNodes(net) << " nodes and " << countArcs(net) << " arcs" << endl;

    int totalCost;
    G::ArcMap<int> flowMap(net);
    bool solved;
    if (argc > 1 && string(argv[1]) == "--net") {
        clog << "Using network simplex algorithm" << endl;
        solved = solve<lemon::NetworkSimplex<G>>(net, lowerMap, upperMap, costMap, supplyMap, totalCost, flowMap);
    } else if (argc > 1 && string(argv[1]) == "--cost") {
        clog << "Using cost scaling algorithm" << endl;
        solved = solve<lemon::CostScaling<G>>(net, lowerMap, upperMap, costMap, supplyMap, totalCost, flowMap);
    } else if (argc > 1 && string(argv[1]) == "--cap") {
        clog << "Using capacity scaling algorithm" << endl;
        solved = solve<lemon::CapacityScaling<G>>(net, lowerMap, upperMap, costMap, supplyMap, totalCost, flowMap);
    } else if ((argc > 1 && string(argv[1]) == "--cycle") || true) {
        clog << "Using cycle canceling algorithm" << endl;
        solved = solve<lemon::CycleCanceling<G>>(net, lowerMap, upperMap, costMap, supplyMap, totalCost, flowMap);
    }

    if (!solved) {
        clog << "error: no solution found" << endl;
        return 1;
    }
    clog << "Lower bound: " << totalCost << endl;

    G::ArcMap<string> arcLabel(tour);
    G::Node empty = tour.addNode();
    affixes.find("")->second.tour_node = empty;
    for (auto &a : affixes) {
        for (auto &e : a.second.suffix) {
            if (flowMap[e.arc]) {
                if (a.second.tour_node == lemon::INVALID)
                    a.second.tour_node = tour.addNode();
                arcLabel.set(tour.addArc(e.w->second.tour_node, a.second.tour_node), "");
            }
        }
        for (auto &e : a.second.prefix) {
            if (flowMap[e.arc]) {
                if (a.second.tour_node == lemon::INVALID)
                    a.second.tour_node = tour.addNode();
                arcLabel.set(tour.addArc(a.second.tour_node, e.w->second.tour_node), e.w->first.substr(a.first.length()));
            }
        }
    }

    clog << "Created tour graph with " << countNodes(tour) << " nodes and " << countArcs(tour) << " arcs" << endl;

    G::NodeMap<int> compMap(tour);
    int components = lemon::stronglyConnectedComponents(tour, compMap);
    if (components != 1) {
        vector<unordered_map<string, Affix>::iterator> breaks(components, affixes.end());
        for (auto a = affixes.begin(); a != affixes.end(); ++a) {
            if (a->second.tour_node == lemon::INVALID)
                continue;
            int c = compMap[a->second.tour_node];
            if (c == compMap[empty])
                continue;
            auto &b = breaks[compMap[a->second.tour_node]];
            if (b == affixes.end() || b->first.length() > a->first.length())
                b = a;
        }
        int offset = 0;
        for (auto &b : breaks) {
            if (b != affixes.end()) {
                arcLabel.set(tour.addArc(empty, b->second.tour_node), b->first);
                arcLabel.set(tour.addArc(b->second.tour_node, empty), "");
                offset += b->first.length();
            }
        }
        clog << "warning: Found " << components << " components; solution may be suboptimal by up to " << offset << " letters" << endl;
    }

    if (!lemon::eulerian(tour)) {
        clog << "error: failed to make tour graph Eulerian" << endl;
        return 1;
    }

    for (lemon::DiEulerIt<G> e(tour, empty); e != lemon::INVALID; ++e)
        cout << arcLabel[e];
    cout << endl;

    return 0;
}

Meskipun saya tidak dapat mengklaim untuk memahami cara kerja min flow, jika ini benar-benar optimal, dilakukan dengan baik!
Nathan Merrill

1
Maaf mengecewakan: PI tidak memikirkan jaringan aliran; itu cukup elegan. Butuh beberapa saat untuk memahami bagaimana Anda menghubungkan kata-kata bersama-sama di jaringan Anda sebelum saya akhirnya menyadari "Untuk setiap awalan (ketat) atau akhiran kata apa pun, gambarkan sebuah simpul" yang berarti bahwa simpul "a" dapat dibagi antara banyak kata.
Dave

1
Solusi Anda juga sekitar 2.000 kali lebih cepat daripada solusi saya!
Dave

1
Mungkin membantu orang ini ( cs.cmu.edu/~tom7/portmantout ) dengan upayanya dalam hal serupa?
Oliver Daugherty-Long

2
@ OliverDaugherty-Long Done ! (Untuk real time ini.) Batas yang paling dikenal sebelumnya adalah 520732 ≤ panjang optimal ≤ 537136, dan saya percaya saya telah meningkatkan kedua batas menjadi 536186.
Anders Kaseorg

13

Java 8, ~ 5 Menit, Panjang 39.279

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

public class Words {

    public static void main(String[] args) throws Throwable {
        File file = new File("words.txt");
        List<String> wordsList = new ArrayList<>();
        BufferedReader reader = new BufferedReader(new FileReader(file));
        String line;
        while ((line = reader.readLine()) != null) {
            wordsList.add(line);
        }
        reader.close();

        Set<String> words = new HashSet<>();

        System.out.println("Finished I/O");

        for (int i = 0; i < wordsList.size(); i++) { //Step 1: remove any words that occur in other words
            boolean in = false;
            for (int j = 0; j < wordsList.size(); j++) {
                if (i != j && wordsList.get(j).contains(wordsList.get(i))) {
                    in = true;
                    break;
                }
            }
            if (!in) {
                words.add(wordsList.get(i));
            }
        }

        System.out.println("Removed direct containers");

        List<String> working = words.stream().sorted((c, b) -> Integer.compare(c.length(), b.length())).collect(Collectors.toList()); //Sort by length, shortest first
        StringBuilder result = new StringBuilder();
        result.append(working.get(0));
        while (!working.isEmpty()) {
            Optional<String> target = working.stream().sorted((c, b) -> Integer.compare(firstLastCommonality(result.toString(), b), firstLastCommonality(result.toString(), c))).findFirst(); //Find the string that has the greatest in common with the end of 'result'
            if(target.isPresent()) { //It really should be present, but just in case
                String s = target.get();
                working.remove(s);
                int commonality = firstLastCommonality(result.toString(), s);
                s = s.substring(commonality);
                result.append(s);
            }
        }

        System.out.println("Finished algorithm");

        String r = result.toString();
        System.out.println("The string: \n" + r);
        System.out.println("Length: \n" + r.length());
        System.out.println("Verified: \n" + !wordsList.stream().filter(s -> !r.contains(s)).findFirst().isPresent());
    }

    private static int firstLastCommonality(String a, String b) {
        int count = 0;
        int len = b.length();
        while (!a.endsWith(b) && !b.equals("")) {
            b = cutLastChar(b);
            count++;
        }
        return len - count;
    }

    private static String cutLastChar(String string) {
        if (string.length() - 1 < 0) {
            return string;
        } else {
            return string.substring(0, string.length() - 1);
        }
    }

}

Memasukkan:

  • sebuah file bernama 'words.txt' di direktori kerja, dalam format yang sama persis dengan file di postingan utama

Keluaran:

Finished I/O
Removed direct containers
Finished algorithm
The string: 
[Moved to pastebin](http://pastebin.com/iygyR3zL)
Length: 
39279
Verified: 
true

2
FGITW, dan di Jawa tidak kurang. Tuan, saya pilih saya.
Patrick Roberts

2
Bagus! Anda menyingkirkan 26,609karakter.
R. Kap

@ R.Kaplah sosok! Saya bahkan tidak berpikir untuk menghitung bahwa ... Pasti ada algoritma yang lebih cerdas, ini hanya hal pertama yang terlintas dalam pikiran ...
Socratic Phoenix

7

Python 2, 39254 karakter

Butuh 1-2 menit untuk berjalan di mesin saya, bekerja dengan mengambil kata terpanjang dan kemudian selalu menambahkan kata ke string hasil yang memiliki string paling umum. (Sebelum itu semua kata yang merupakan substring dari kata lain dihapus untuk mencegah penambahan yang tidak perlu ke string.)

Pembaruan: Mencoba melihat ke dua arah, tetapi itu tidak lebih baik. (mungkin menggunakan kata-kata yang bisa digunakan lebih baik nanti?)

Tautan ke kata di pastebin.

100 karakter pertama:

telecommunicationsawayneillegallynnbabyenbcjrxltdxmlbsrcwvtxxxboxespnycdsriconsentencessexyrsslipodc

Kode:

import re
import urllib

def suffix_dist(w1,w2):
    for i in range(min(map(len,[w1,w2])))[::-1]:
        if w1[-i:]==w2[:i]:
            return i
    return 0

url="https://raw.githubusercontent.com/first20hours/google-10000-english/master/google-10000-english.txt"
s=urllib.urlopen(url).read()
words=s.split()
words.sort(key=len,reverse=True)

## remove words that are substrings of other words anyway
for i in range(len(words))[::-1]:
    if any(words[i] in w for w in words[:i]):
        words.pop(i)

print len(words)

words.sort(key=len)
w1=words.pop(-1)
result=w1
while words:
    ## get the word with longest shared suffix/prefix
    w2=max(words,key=lambda x:suffix_dist(w1,x))
    print w2
    words.pop(words.index(w2))
    if w2 in result:
        break
    result+=w2[suffix_dist(w1,w2):]
    w1=w2


print result[:100]
print len(result)
print "Test:", all(w in result for w in s.split())

2
Sial, saya sudah dikalahkan oleh 25 karakter ... +1 untuk itu
Socratic Phoenix

Kerja bagus! Saya punya ide yang sama tetapi Anda sudah memiliki jawabannya. Versi saya dimulai dengan kata kecil, bukan kata besar, ditambah beberapa pemangkasan lain yang menyebabkannya kehilangan faktor waktu secara drastis, menghabiskan hingga 3x jumlah waktu untuk berjalan.
Value Ink

5

Ruby, 39222 karakter

Menggunakan pendekatan yang mirip dengan @KarlKastor dalam jawaban Python-nya, tetapi string awal adalah salah satu kata terkecil dan bukan yang terbesar. Pengoptimalan lain (saya tidak tahu seberapa besar manfaatnya) adalah bahwa di antara setiap penambahan, ia memangkas setiap kata yang mungkin telah dimasukkan dalam string karena kata-kata yang tumpang tindih.

Berjalan dalam waktu kurang lebih 4 menit pada mesin saya, tidak termasuk permintaan web untuk mengambil daftar kata-kata, tetapi tidak cukup 4:20.

Kata di Pastebin.

require 'net/http'

puts "Obtaining word list..."
data = Net::HTTP.get(URI'https://raw.githubusercontent.com/first20hours/google-10000-english/master/google-10000-english.txt')
puts "Word list obtained!"

puts "Starting calculation..."
time = Time.now

words = data.split.sort_by(&:size)
words.reject!{|w| words.find{|x| w!=x && x.include?(w)}}

string = words.shift

def merge_dist(prefix, suffix)
    [prefix.size,suffix.size].min.downto(0).find{|i| prefix.end_with?(suffix[0,i])}
end

while words.length > 0
    suffix = words.max_by{|w| merge_dist string, w}
    string += suffix[merge_dist(string, suffix)..-1]
    words.reject!{|w| string.include? w}
end

delta = Time.now - time

puts "Calculation completed in #{delta} seconds!"
puts "Word is #{string.size} chars long."

open("word.txt", 'w') << string

puts "Word saved to word.txt"

3

PowerShell v2 +, 46152 karakter

param([System.Collections.ArrayList]$n)$n=$n|sort length -des;while($n){$x=$n.Count;$o+=$n[0];0..$x|%{if($o.IndexOf($n[$_])-ge0){$n.RemoveAt($_)}}}$o

Mengambil input sebagai daftar, melemparkannya ke dalam ArrayList (jadi kita dapat memanipulasinya). Kami sortdengan lengthdi -descending rangka. Kemudian, whilekita masih memiliki kata-kata dalam larik input kita, lakukan perulangan. Setiap iterasi, atur helper $xmenjadi sama dengan berapa banyak yang tersisa, tempelkan item berikutnya dalam daftar ke output kita $o, dan kemudian tarik semua yang masih ada dalam daftar kita. Jika .IndexOftidak sama dengan -1(yaitu, kata itu ditemukan di suatu tempat di $o), kami menghapus kata itu dari daftar kata yang tersisa. Akhirnya, pada akhirnya, output $o.

Saya tidak memiliki akses ke Pastebin atau yang serupa, jadi inilah awal dan akhir kata untuk sementara - telecommunicationscharacterizationresponsibilitiessublimedirectory...fcmxvtwvfxwujmjsuhjjrxjdbkdxqc. Yang saya kira telah mencukur sekitar 20.000 karakter dari input, jadi tidak terlalu buruk, saya kira.

Saya sedang mengerjakan perbaikan.


0

PHP 46612 karakter

Ini baru permulaan. Saya berharap untuk memperbaikinya. Yang saya lakukan sejauh ini adalah menghapus kata apa pun yang merupakan sub-string dari kata lain. Saya sedang mengerjakan 3 salinan array, tetapi memori sepertinya tidak menjadi masalah.

<?php
set_time_limit(3000);

$words=file('https://raw.githubusercontent.com/first20hours/google-10000-english/master/google-10000-english.txt');
$words = array_map('trim', $words);

usort($words, function ($a, $b)
{
    if (strlen($a) == strlen($b) ){
        return 0;
    }
    return ( strlen($a) < strlen($b) )? -1 : 1;
});

$final_array=$words;
$comparison_array=$words;


  foreach($words as $key => $word){
    echo $word."<br>\n";
      foreach($comparison_array as $nestedKey => $nestedWord){
          if (strlen($nestedWord) <= strlen($word)) {
            unset($comparison_array[$nestedKey]);
            continue;
          }
          if( strpos($nestedWord,$word) !== FALSE ){
              unset($final_array[$key]);
              $restart=true;
              break;
          } 
      }    
  }


sort($final_array);
$compound='';
$compound = implode($final_array);
echo $compound;
echo "  <br><br>\n\n". strlen($compound);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.