For the question, I had a pretty messy solution so I would like some advice on how to better use Java to make the code a bit cleaner.
Also, a semi-hack that I did that I'm not proud of is checking if
words.length == 0
at the beginning and returning0
if so, so that I can initializeint longestSeen = 1
(if there exists a word, the smallest chain must be at least 1).In reality, if we haven't processed the graph to find the longest chain, we should have
int longestSeen = 0
. My solution only adds to the adjacency listadjList
if there exists a relation (e.g. 'ab' -> 'abc'), so for the case where there are no chains and every word is a lone island, I'm not checking for the longest chain length at all and am basically just straight up returning1
. This makes sense and would be more time efficient than initializing theadjList
with all the words, but it feels hack-y to me.I had
int[] longestChain
outside of the longestStrChain method and I'm not sure how to get around this.
Problem:https://leetcode.com/problems/longest-string-chain/
Given a list of words, each word consists of English lowercase letters.
Let's say word1
is a predecessor of word2
if and only if we can add exactly one letter anywhere in word1
to make it equal to word2.
For example, "abc"
is a predecessor of "abac".
A word chain is a sequence of words [word_1, word_2, ..., word_k]
with k >= 1
, where word_1
is a predecessor of word_2
, word_2
is a predecessor of word_3
, and so on.
Return the longest possible length of a word chain with words chosen from the given list of words
.
Example:
Input: ["a","b","ba","bca","bda","bdca"] Output: 4 Explanation: one of the longest word chain is "a","ba","bda","bdca".
Solution:
class Solution { int[] longestChain; // memoization for longest chain length for fromKey vertex public int longestStrChain(String[] words) { if (words.length == 0) { return 0; } Map<String, Integer> wordToIndex = new HashMap<>(words.length); Map<Integer, List<Integer>> adjList = new HashMap<>(words.length); longestChain = new int[words.length]; for (int i = 0; i < words.length; i++) { wordToIndex.put(words[i], i); } for (String word : wordToIndex.keySet()) { for (int i = 0; i < word.length(); i++) { String curr = word.substring(0, i) + word.substring(i+1, word.length()); // take one char out at a time for each word and see if it's part of words[] if (wordToIndex.keySet().contains(curr)) { int fromKey = wordToIndex.get(curr); int toKey = wordToIndex.get(word); if (adjList.keySet().contains(fromKey)) { List<Integer> vertices = adjList.get(fromKey); vertices.add(toKey); adjList.replace(fromKey, vertices); } else { adjList.put(fromKey, new ArrayList<Integer>(Arrays.asList(toKey))); } } } } int longestSeen = 1; // longest string chain so far for (Integer fromVertexIdx : adjList.keySet()) { longestSeen = Math.max(longestSeen, getChainLength(fromVertexIdx, adjList)); } return longestSeen; } private int getChainLength(int fromVertexIdx, Map<Integer, List<Integer>> adjList) { if (longestChain[fromVertexIdx] > 0) { return longestChain[fromVertexIdx]; } longestChain[fromVertexIdx] = 1; // min string length is 1 (vertex contains no edges) if (adjList.keySet().contains(fromVertexIdx)) { for (Integer edge : adjList.get(fromVertexIdx)) { longestChain[fromVertexIdx] = Math.max(longestChain[fromVertexIdx], getChainLength(edge, adjList)+1); } } return longestChain[fromVertexIdx]; } }
Arrays.asList(toKey)
...\$\endgroup\$