avatarLiu Zuo Lin

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

5855

Abstract

is graph along with a queue to generate every possible chain that exists. We keep track of a queue <code>queue</code>, which contains a bunch of chains to search. We also keep track of a list <code>chains</code> that contains our chains.</p><ol><li>Initialize <code>chains</code> to an empty list.</li><li>Initialize <code>queue</code> to contain a chain of length 1 (a list) for each word</li><li>Remove the first chain from <code>queue</code>, and assign it to <code>current</code></li><li>Find words that are not inside the chain yet</li><li>If there are no such words, this is the end of the chain, and add this chain to <code>chains</code></li><li>If there are words that are not inside the chain yet, construct a new chain containing this additional word, and add it back to <code>queue</code>.</li><li>Repeat steps 3 to 6 until <code>queue</code> is empty</li></ol><p id="5b3e">At this point, <code>chains</code> should contain every possible chain of words.</p><div id="e1c8"><pre>chains = [ [<span class="hljs-string">"element"</span>], [<span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"orange"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>] ]</pre></div><p id="53a4">We can then find the maximum length within the chains, and return a list of chains with this length.</p><h1 id="74c4">The Code Solution</h1><div id="e290"><pre><span class="hljs-keyword">def</span> <span class="hljs-title function_">longests_chain</span>(<span class="hljs-params">words</span>)<span class="hljs-symbol">:</span></pre></div><div id="a4aa"><pre> def build_graph(<span class="hljs-built_in">words</span>): g = {} <span class="hljs-keyword">for</span> <span class="hljs-built_in">word</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">words</span>: g[<span class="hljs-built_in">word</span>] = [] <span class="hljs-keyword">for</span> next <span class="hljs-keyword">in</span> <span class="hljs-built_in">words</span>: <span class="hljs-keyword">if</span> next!=<span class="hljs-built_in">word</span> <span class="hljs-keyword">and</span> <span class="hljs-built_in">word</span>[<span class="hljs-number">-1</span>] == next[<span class="hljs-number">0</span>]: g[<span class="hljs-built_in">word</span>].append(next) <span class="hljs-built_in"> return</span> g</pre></div><div id="823b"><pre> <span class="hljs-attr">g</span> = build_graph(words)</pre></div><div id="44f3"><pre> chains = [] queue = [[<span class="hljs-type">word</span>] <span class="hljs-keyword">for</span> <span class="hljs-type">word</span> in words] <span class="hljs-keyword">while</span> queue: current = queue.<span class="hljs-built_in">pop</span>(<span class="hljs-number">0</span>) valid_neighbours = <span class="hljs-built_in">set</span>(g[current[<span class="hljs-number">-1</span>]]) - <span class="hljs-built_in">set</span>(current)</pre></div><div id="ae66"><pre> <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(valid_neighbours) == <span class="hljs-number">0</span>: chains.<span class="hljs-built_in">append</span>(current)</pre></div><div id="ad76"><pre> <span class="hljs-keyword">else</span>:<span class="hljs-type"></span> <span class="hljs-keyword">for</span> neighbour <span class="hljs-keyword">in</span> valid_neighbours:<span class="hljs-type"></span> <span class="hljs-keyword">new</span> <span class="hljs-type"></span>= current + [neighbour] queue.append(<span class="hljs-keyword">new</span><span class="hljs-type"></span>)</pre></div><div id="05ae"><pre> maxlen = <span class="hljs-built_in">len</span>(<span class="hljs-built_in">max</span>(chains, key=<span class="hljs-built_in">len</span>)) <span class="hljs-literal">return</span> [c <span class="hljs-keyword">for</span> c <span class="hljs-keyword">in</span> chains <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(c)==maxlen]</pre></div><h1 id="5887">A Quick Code Run-Through</h1><div id="8a9f"><pre><span class="hljs-attr">words</span> = [<span class="hljs-string">"apple"</span>, <span class="hljs-string">"orange"</span>, <span class="hljs-string">"pear"</span>, <span class="hljs-string">"element"</span>, <span class="hljs-string">"replica"</span>]</pre></div><p id="4f74">Before the start of iteration:</p><div id="180a"><pre>queue = [ [<span class="hljs-string">"apple"</span>], [<span class="hljs-string">"orange"</span>], [<span class="hljs-string">"pear"</span>], [<span class="hljs-string">"element"</span>], [<span class="hljs-string">"replica"</span>] ]</pre></div><p id="418d">Iteration 1 — <code>["apple"]</code> itself is removed, and <code>["apple", "element"]</code> is added back to the queue.</p><div id="1fb4"><pre>queue = [ [<span class="hljs-string">"orange"</span>], [<span class="hljs-string">"pear"</span>], [<span class="hljs-string">"element"</span>], [<span class="hljs-string">"replica"</span>], [<span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>] ]</pre></div><p id="65b7">Iteration 2 — <code>["orange"]</code> is removed</p><div id="6201"><pre>queue = [ [<span class="hljs-string">"pear"</span>], [<span class="hljs-string">"element"</span>], [<span class="hljs-string">"replica"</span>], [<span class="hljs-string

Options

">"apple"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"orange"</span>, <span class="hljs-string">"element"</span>] ]</pre></div><p id="9e76">Iteration 3</p><div id="f498"><pre>queue = [ [<span class="hljs-string">"element"</span>], [<span class="hljs-string">"replica"</span>], [<span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"orange"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>] ]</pre></div><p id="5cb1">Iteration 4 — <code>["element"]</code> is removed, but since no word begins with <code>t</code>, it is added to <code>chains</code> instead of <code>queue</code>.</p><div id="321c"><pre>queue = [ [<span class="hljs-string">"replica"</span>], [<span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"orange"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>] ]</pre></div><p id="5eb4">Iteration 5</p><div id="399d"><pre>queue = [ [<span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"orange"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>], [<span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>] ]</pre></div><p id="1f0a">Iteration 6 — <code>["apple", "element"]</code> is removed from <code>queue</code>, and since no word begins with <code>t</code>, it is added to <code>chains</code> and not back to <code>queue</code>.</p><div id="4121"><pre>queue = [ [<span class="hljs-string">"orange"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>], [<span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>] ]</pre></div><p id="b656">Iteration 7 — same as iteration 6. <code>["orange", "element"]</code> is added into <code>chains</code> and not back into <code>queue</code>.</p><div id="8ed8"><pre>queue = [ [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>], [<span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>] ]</pre></div><p id="c5fe">Iteration 8</p><div id="8b0a"><pre>queue = [ [<span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>], [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>] ]</pre></div><p id="67cd">Iteration 9</p><div id="4c25"><pre>queue = [ [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>], [<span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>] ]</pre></div><p id="c22c">Iteration 10</p><div id="e37c"><pre>queue = [ [<span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>] ]</pre></div><p id="0e51">Iteration 11</p><div id="0aad"><pre><span class="hljs-attr">queue</span> = [ [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>] ]</pre></div><p id="d2cc">Iteration 12</p><div id="5851"><pre><span class="hljs-attribute">queue</span> <span class="hljs-operator">=</span> []</pre></div><p id="f9cd">At end of all iterations:</p><div id="696f"><pre>chains = [ [<span class="hljs-string">"element"</span>], [<span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"orange"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>], [<span class="hljs-string">"pear"</span>, <span class="hljs-string">"replica"</span>, <span class="hljs-string">"apple"</span>, <span class="hljs-string">"element"</span>] ]</pre></div><p id="296f">And we simply use the max function to select the longest chain. And there we have it, the solution to this riddle.</p><h1 id="a045">Conclusion</h1><p id="e4ee"><i>If this article provided value and you wish to support me, do consider signing up for a Medium membership — It’s $5 a month, and you get unlimited access to articles on Medium. If you sign up using my link below, I’ll earn a tiny commission at zero additional cost to you.</i></p><p id="7126"><a href="https://zl-liu.medium.com/membership"><b><i>Sign up using my link here to read unlimited Medium articles</i></b></a><b><i>.</i></b></p><p id="2877"><i>I write coding articles (once per 1–2 days) that would have probably helped the younger me speed up my learning curve. Do join my email list to get notified whenever I publish.</i></p><p id="b8f8"><i>More content at <a href="https://plainenglish.io/"><b>PlainEnglish.io</b></a>. Sign up for our <a href="http://newsletter.plainenglish.io/"><b>free weekly newsletter</b></a>. Follow us on <a href="https://twitter.com/inPlainEngHQ"><b>Twitter</b></a> and <a href="https://www.linkedin.com/company/inplainenglish/"><b>LinkedIn</b></a>. Join our <a href="https://discord.gg/GtDtUAvyhW"><b>community Discord</b></a>.</i></p></article></body>

Python Riddle — Get the Longest Possible Chains from a List of Words

Given a list of words, find the longest possible chains that can be formed.

Given a list of words, find the longest possible chains that can be formed. In a chain, each word’s starting letter must be equal to the previous word’s ending letter. Let’s say we are given this list of words:

words = ["apple", "orange", "pear", "element", "replica"]

Some examples of chains that can be formed from these words are:

apple -> element
pear -> replica
replica -> apple -> element
pear -> replica -> apple -> element

Notice that in each chain, the last letter of each word is the first letter of the next word (except the first word of course).

Write a function longest_chains(words) that takes in a list of strings words, and returns a list containing the longest possible chains that can be formed using the words inside words. If there is more than 1 longest possible chain with the same length, return all of them.

Case 1

words = ["apple", "orange", "pear", "element", "replica"]
output -> [
    ["pear", "replica", "apple", "element"]
]

Case 2

words = ["apple", "boy", "cage", "doge", "elephant"]
output -> [
    ["apple", "elephant"],
    ["cage", "elephant"],
    ["doge", "elephant"]
]

Case 3

words = ["apple", "elephant", "taboo", "orange", "extra"]
output -> [
    ["apple", "elephant", "taboo", "orange", "extra"],
    ["elephant", "taboo", "orange", "extra", "apple"],
    ["taboo", "orange", "extra", "apple", "elephant"],
    ["orange", "extra", "apple", "elephant", "taboo"],
    ["extra", "apple", "elephant", "taboo", "orange"]
]

In case 3, the words can form a cyclical chain — "extra" can link back to "apple" in the first line, "apple" can link back to "elephant" in the second line and so on.

Solution Below

Do take some time to give this a go before taking a look at the solution below.

The Logic Behind The Solution

Let’s first create an adjacency matrix using our words, each key being each word in our list, and each value being a list of words our key can lead to. (Remember that the last letter of our current word needs to be the same as the first letter of the next word).

words = ["apple", "orange", "pear", "element", "replica"]
# the graph we want
g = {
    "apple": ["element"],
    "orange": ["element"],
    "pear": ["replica"],
    "element": [],
    "replica": ["apple"]
}

After we generate this graph, we can use this graph along with a queue to generate every possible chain that exists. We keep track of a queue queue, which contains a bunch of chains to search. We also keep track of a list chains that contains our chains.

  1. Initialize chains to an empty list.
  2. Initialize queue to contain a chain of length 1 (a list) for each word
  3. Remove the first chain from queue, and assign it to current
  4. Find words that are not inside the chain yet
  5. If there are no such words, this is the end of the chain, and add this chain to chains
  6. If there are words that are not inside the chain yet, construct a new chain containing this additional word, and add it back to queue.
  7. Repeat steps 3 to 6 until queue is empty

At this point, chains should contain every possible chain of words.

chains = [
    ["element"],
    ["apple", "element"],
    ["orange", "element"],
    ["replica", "apple", "element"],
    ["pear", "replica", "apple", "element"]
]

We can then find the maximum length within the chains, and return a list of chains with this length.

The Code Solution

def longests_chain(words):
    def build_graph(words):
        g = {}
        for word in words:
            g[word] = []
            for next in words:
                if next!=word and word[-1] == next[0]:
                    g[word].append(next)
        return g
    g = build_graph(words)
    chains = []
    queue = [[word] for word in words]
    while queue:
        current = queue.pop(0)
        valid_neighbours = set(g[current[-1]]) - set(current)
        if len(valid_neighbours) == 0:
            chains.append(current)
        else:
            for neighbour in valid_neighbours:
                new = current + [neighbour]
                queue.append(new)
    maxlen = len(max(chains, key=len))
    return [c for c in chains if len(c)==maxlen]

A Quick Code Run-Through

words = ["apple", "orange", "pear", "element", "replica"]

Before the start of iteration:

queue = [
    ["apple"],
    ["orange"],
    ["pear"],
    ["element"],
    ["replica"]
]

Iteration 1 — ["apple"] itself is removed, and ["apple", "element"] is added back to the queue.

queue = [
    ["orange"],
    ["pear"],
    ["element"],
    ["replica"],
    ["apple", "element"]
]

Iteration 2 — ["orange"] is removed

queue = [
    ["pear"],
    ["element"],
    ["replica"],
    ["apple", "element"],
    ["orange", "element"]
]

Iteration 3

queue = [
    ["element"],
    ["replica"],
    ["apple", "element"],
    ["orange", "element"],
    ["pear", "replica"]
]

Iteration 4 — ["element"] is removed, but since no word begins with t, it is added to chains instead of queue.

queue = [
    ["replica"],
    ["apple", "element"],
    ["orange", "element"],
    ["pear", "replica"]
]

Iteration 5

queue = [
    ["apple", "element"],
    ["orange", "element"],
    ["pear", "replica"],
    ["replica", "apple"]
]

Iteration 6 — ["apple", "element"] is removed from queue, and since no word begins with t, it is added to chains and not back to queue.

queue = [
    ["orange", "element"],
    ["pear", "replica"],
    ["replica", "apple"]
]

Iteration 7 — same as iteration 6. ["orange", "element"] is added into chains and not back into queue.

queue = [
    ["pear", "replica"],
    ["replica", "apple"]
]

Iteration 8

queue = [
    ["replica", "apple"],
    ["pear", "replica", "apple"]
]

Iteration 9

queue = [
    ["pear", "replica", "apple"],
    ["replica", "apple", "element"]
]

Iteration 10

queue = [
    ["replica", "apple", "element"],
    ["pear", "replica", "apple", "element"]
]

Iteration 11

queue = [
    ["pear", "replica", "apple", "element"]
]

Iteration 12

queue = []

At end of all iterations:

chains = [
    ["element"],
    ["apple", "element"],
    ["orange", "element"],
    ["replica", "apple", "element"],
    ["pear", "replica", "apple", "element"]
]

And we simply use the max function to select the longest chain. And there we have it, the solution to this riddle.

Conclusion

If this article provided value and you wish to support me, do consider signing up for a Medium membership — It’s $5 a month, and you get unlimited access to articles on Medium. If you sign up using my link below, I’ll earn a tiny commission at zero additional cost to you.

Sign up using my link here to read unlimited Medium articles.

I write coding articles (once per 1–2 days) that would have probably helped the younger me speed up my learning curve. Do join my email list to get notified whenever I publish.

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter and LinkedIn. Join our community Discord.

Python
Python Questions
Python Quiz
Graph Search
Recommended from ReadMedium