Hợp chất tiếng anh


28

Một từ ghép là một từ có chứa 2 hoặc nhiều từ trong đó. Chúng tôi có thể làm tốt hơn thế, mặc dù. Chúng tôi cần bạn tạo 1 từ (vô nghĩa) có chứa mọi từ .

Tuy nhiên, chúng tôi muốn từ này càng ngắn càng tốt. Chúng ta có thể sử dụng các chữ cái chồng chéo để đạt được điều này.

Ví dụ: nếu danh sách từ của bạn là ["cat", "atom", "a"], bạn sẽ muốn quay lại "catom".

Đầu ra đầu vào

Chương trình của bạn sẽ cần lấy một danh sách các từ làm đầu vào và trả về một từ ghép làm đầu ra.

Danh sách từ bạn sẽ sử dụng là 10000 từ tiếng Anh hàng đầu , theo Google (Nếu danh sách này quá dễ, tôi có thể thay đổi nó thành một từ dài hơn). Để tham khảo, chỉ cần nối thêm mỗi từ sẽ cho bạn số điểm 65888.

Điểm của bạn là số chữ cái trong từ cuối cùng của bạn, thấp hơn là tốt hơn. Tie breaker đi đến poster đầu tiên.



1
@Loovjo thì không, nhưng nếu kết thúc là bruteforcing đủ nhanh để chạy, thì tôi sẽ thay đổi danh sách từ để làm cho nó dài hơn.
Nathan Merrill

1
@PatrickRoberts Nếu nó phù hợp với câu trả lời của bạn, đạo cụ cho bạn :) Một liên kết pastebin / gist sẽ rất tuyệt, nhưng không bắt buộc.
Nathan Merrill

1
Hmm, ai biết một người bán hàng du lịch bất đối xứng giỏi heuristic?
Dave

2
Không có gói, và có để xác định.
Nathan Merrill

Câu trả lời:


26

C ++, độ dài từ cuối cùng: 38272

(phiên bản tối ưu hóa mất khoảng 20 phút)

#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;
}

Xác minh bash one-liner:

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

Nó cũng tạo ra một số từ trong tiến trình khá mát mẻ. Đây là một vài sở thích của ôti:

  • polyesterday (nỗi nhớ tổng hợp)
  • af Afghanistanistanbul (điều gì đó [chèn chính trị gia mà bạn không thích] sẽ nói)
  • togethernet (internet thân thiện)
  • voi ma (một con ma lớn)
  • chống sấm sét (như trong "Tôi không biết tại sao họ cảm thấy cần phải làm cho nó chống sét, nhưng nó làm tôi lo lắng")

Và:

  • mã mô tả (có thể là một thách thức sắp tới trên trang web này?)

Đầu ra cuối cùng là trên pastebin tại đây: http://pastebin.com/j3qYb65b


2
Một quan sát có thể hữu ích cho những người khác đang tìm kiếm giải pháp tối ưu: vấn đề có thể được giảm xuống thành vấn đề nhân viên bán hàng du lịch không đối xứng, không đối xứng: xác định ma trận trong đó phần tử i, j = max_word_length - overlap(word[i], word[j])(trong đó overlapkiểm tra sự chồng chéo từ bên phải của đối số đầu tiên bên trái của thứ hai). Giải quyết điều này (chúc may mắn!) Sau đó cắt vòng lặp kết quả với chi phí cao nhất (chồng chéo thấp nhất) sẽ đưa ra một danh sách các từ có thể được hợp nhất để đưa ra một giải pháp tối ưu.
Dave

Ấn tượng. Đây có phải là kiểm tra từng từ trong danh sách hiện tại so với nhau, mỗi lần thông qua? Tôi đã xem xét điều này nhưng cho rằng tôi chỉ cần kiểm tra một mẫu ngẫu nhiên để làm cho nó chạy trong một thời gian hợp lý.
trichoplax

1
@ValueInk có bộ nhớ đệm sẽ là một hiệu suất lớn. Một phiên bản trước đó có điều đó, nhưng nó thêm rất nhiều phức tạp, vì vậy khi tôi điều chỉnh một số logic tôi đã phải viết lại rất nhiều. Thay vào đó tôi chọn bỏ bộ nhớ đệm. Cũng không, điều này không hoàn toàn tối ưu. Đó là một thuật toán tham lam để nó không thể đánh giá sự đánh đổi và không thể lựa chọn giữa các tùy chọn "tốt như nhau". Xem bình luận TSP của tôi để biết giải pháp tối ưu (NP-Hard).
Dave

1
@trichoplax yup, đó là những gì nó đang làm. Thời gian chạy là O (n ^ 3), không quá tệ đối với cỡ mẫu này. Với bộ nhớ đệm, nó có thể được giảm xuống O (n ^ 2). Kiểm tra bên trong cũng rất song song, vì vậy ngay cả đối với các mẫu lớn hơn, nó có thể chạy trong thời gian hợp lý với tính toán phân luồng / phân tán. Ngoài ra, điều này còn giúp tăng tốc độ lớn từ việc biết phạm vi độ rộng chồng chéo có thể có cho mỗi bước, giúp cắt thời gian chạy theo hệ số 10.
Dave

2
Điều này có thể không khó như TSP chung, bởi vì chúng ta có các ràng buộc buồn cười chồng chéo (a, b) ≥ min {chồng chéo (a, d), chồng chéo (c, d), chồng chéo (c, b)} cho tất cả a , b, c, d.
Anders Kaseorg

21

C ++ 11, 38272 chữ cái, đã được chứng minh tối ưu

Thuật toán này được đảm bảo để cung cấp một giới hạn thấp hơn về giải pháp. Trong trường hợp này, nó có thể đạt được giới hạn dưới và đưa ra một giải pháp chữ cái 38272 tối ưu. (Điều này phù hợp với giải pháp được tìm thấy bởi thuật toán tham lam của Dave. Tôi đã ngạc nhiên và hơi thất vọng khi phát hiện ra rằng nó tối ưu, nhưng, chúng ta đang ở đó.)

Nó hoạt động bằng cách giải quyết vấn đề dòng chi phí tối thiểu trên mạng được xây dựng như sau.

  • Đầu tiên, bất kỳ từ nào có trong các từ khác là dư thừa; loại bỏ chúng
  • Với mỗi từ w , hãy vẽ hai nút w _0 và w _1, trong đó w _0 là nguồn có công suất 1 và w _1 là một bồn có công suất 1.
  • Với mỗi tiền tố (nghiêm ngặt) hoặc hậu tố a của bất kỳ từ nào, hãy vẽ một nút a .
  • Với mỗi hậu tố a của w , vẽ một cung từ w _0 đến a có công suất 1 và chi phí 0.
  • Với mỗi tiền tố a của w , hãy vẽ một cung từ a đến w _1 với công suất 1 và chiều dài chi phí ( w ) - chiều dài ( a ).

Bất kỳ chuỗi có độ dài n chứa mỗi từ đều có thể được chuyển đổi thành luồng trên mạng này với chi phí tối đa là n . Do đó, luồng chi phí tối thiểu trên mạng này là giới hạn thấp hơn về độ dài của chuỗi ngắn nhất như vậy.

Nếu chúng ta may mắn và trong trường hợp này, chúng ta là một người may mắn thì sau khi chúng ta chuyển hướng dòng chảy vào w _1 trở lại từ w _0, chúng ta sẽ tìm thấy một luồng tối ưu chỉ có một thành phần được kết nối và đi qua nút cho trống chuỗi. Nếu vậy, nó sẽ chứa một mạch Euler bắt đầu và kết thúc ở đó. Một mạch Euler như vậy có thể được đọc lại dưới dạng một chuỗi có độ dài tối ưu.

Nếu chúng ta không may mắn, hãy thêm một số cung tròn giữa chuỗi trống và chuỗi ngắn nhất trong các thành phần được kết nối khác để đảm bảo rằng mạch Euler tồn tại. Chuỗi sẽ không còn nhất thiết phải là tối ưu trong trường hợp đó.

Tôi sử dụng thư viện LEMON cho dòng chảy chi phí tối thiểu và thuật toán mạch Euler. (Đây là lần đầu tiên tôi sử dụng thư viện này và tôi rất ấn tượng. Tôi chắc chắn sẽ sử dụng lại nó cho nhu cầu thuật toán đồ thị trong tương lai.) LEMON đi kèm với bốn thuật toán dòng chi phí tối thiểu khác nhau; bạn có thể thử chúng ở đây với --net, --cost, --cap, và --cycle(mặc định).

Chương trình chạy trong 0,5 giây , tạo ra chuỗi đầu ra này .

#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;
}

Mặc dù tôi không thể yêu cầu hiểu cách thức hoạt động của dòng chảy tối thiểu, nhưng điều này thực sự là tối ưu, được thực hiện tốt!
Nathan Merrill

1
Xin lỗi để thất vọng: PI đã không nghĩ về một mạng lưới dòng chảy; đó là khá thanh lịch. Mất một lúc để hiểu cách bạn liên kết các từ với nhau trong mạng của mình trước khi cuối cùng tôi nhận ra "Với mỗi tiền tố (nghiêm ngặt) hoặc hậu tố của bất kỳ từ nào, hãy vẽ một nút" có nghĩa là các nút "a" có thể được chia sẻ giữa nhiều từ.
Dave

1
Ngoài ra giải pháp của bạn là nhanh hơn khoảng 2.000 lần so với của tôi!
Dave

1
Có thể giúp anh chàng này ( cs.cmu.edu/~tom7/portmantout ) với nỗ lực của mình trong một điều tương tự?
Oliver Daugherty-Long

2
@ OliverDaugherty- Đã xong ! (Trong thời gian thực này.) Các giới hạn được biết đến trước đây là 520732 chiều dài tối ưu ≤ 537136 và tôi tin rằng tôi đã cải thiện cả hai giới hạn thành 536186.
Anders Kaseorg

13

Java 8, ~ 5 phút, Độ dài 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);
        }
    }

}

Đầu vào:

  • một tệp có tên 'words.txt' trong thư mục làm việc, có định dạng chính xác giống như tệp trong bài đăng chính

Đầu ra:

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

2
FGITW và trong Java không hơn không kém. Bạn có phiếu bầu của tôi.
Patrick Roberts

2
Tốt đẹp! Bạn đã thoát khỏi các 26,609nhân vật.
R. Kap

@ R.Kap đi con số! Tôi thậm chí đã không nghĩ đến việc tính toán rằng ... Phải có một thuật toán thông minh hơn, đây chỉ là điều đầu tiên xuất hiện trong đầu ...
Socratic Phoenix

7

Python 2, 39254 ký tự

Mất 1-2 phút để chạy trên máy của tôi, hoạt động bằng cách lấy từ dài nhất và sau đó luôn thêm từ vào chuỗi kết quả có nhiều chuỗi chung nhất. (Trước đó, tất cả các từ là chuỗi con của các từ khác sẽ bị xóa để tránh thêm chuỗi không cần thiết vào chuỗi.)

Cập nhật: Đã thử nhìn theo cả hai hướng, nhưng điều đó không làm gì tốt hơn. (có thể đó là sử dụng các từ có thể được sử dụng tốt hơn sau này?)

Liên kết với các từ trên pastebin.

100 ký tự đầu tiên:

telecommunicationsawayneillegallynnbabyenbcjrxltdxmlbsrcwvtxxxboxespnycdsriconsentencessexyrsslipodc

Mã số:

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
Welp, tôi đã bị đánh bại bởi 25 ký tự ... +1 cho điều đó
Socratic Phoenix

Công việc tốt đẹp! Tôi đã có một ý tưởng tương tự nhưng bạn đã có một câu trả lời lên. Phiên bản của tôi bắt đầu bằng một từ nhỏ thay vì một từ lớn, cộng với một số cách cắt tỉa khác khiến nó mất đi đáng kể yếu tố thời gian, mất tới 3 lần thời gian để chạy.
Mực giá trị

5

Ruby, 39222 ký tự

Sử dụng một cách tiếp cận tương tự với @KarlKastor trong câu trả lời Python của mình, nhưng chuỗi bắt đầu là một trong những từ nhỏ nhất thay vì lớn nhất. Một tối ưu hóa khác (tôi không biết nó giúp được bao nhiêu) là ở giữa mỗi lần thêm, nó cắt xén bất kỳ từ nào có thể đã được đưa vào chuỗi do các từ chồng chéo.

Chạy trong hơn 4 phút trên máy của tôi, không tính yêu cầu web để lấy danh sách các từ, nhưng không hoàn toàn 4:20.

Từ trên 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 ký tự

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

Lấy đầu vào dưới dạng một danh sách, biến nó thành một ArrayList (để chúng ta có thể thao tác nó). Chúng sortnó bằng lengthtrong -descending trật tự. Sau đó, whilechúng ta vẫn có các từ trong mảng đầu vào, thực hiện một vòng lặp. Mỗi lần lặp, đặt trình trợ giúp $xbằng với số lượng chúng ta còn lại, giải quyết mục tiếp theo trong danh sách cho đầu ra của chúng ta $o, và sau đó lướt qua mọi thứ vẫn còn trong danh sách của chúng ta. Nếu .IndexOfkhông bằng -1(nghĩa là từ đã được tìm thấy ở đâu đó trong $o), chúng tôi sẽ xóa từ đó khỏi danh sách các từ còn lại. Cuối cùng, ở cuối, đầu ra $o.

Tôi không có quyền truy cập vào Pastebin hoặc tương tự, vì vậy đây là phần đầu và phần cuối của từ tạm thời - telecommunicationscharacterizationresponsibilitiessublimedirectory...fcmxvtwvfxwujmjsuhjjrxjdbkdxqc. Mà tôi đoán đã loại bỏ khoảng 20.000 ký tự khỏi đầu vào, vì vậy không tệ, tôi cho rằng.

Tôi đang làm việc trên các sàng lọc.


0

PHP 46612 ký tự

Đây chỉ là một sự khởi đầu. Tôi hy vọng sẽ cải thiện nó. Tất cả những gì tôi đã làm cho đến nay là loại bỏ bất kỳ từ nào là chuỗi con của một từ khác. Tôi đang làm việc trên 3 bản sao của mảng, nhưng bộ nhớ dường như không phải là vấn đề.

<?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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.