code: protected List<HString> viterbi(@NonNull HString source) {
        List<Annotation> tokens = source.tokens();
        int n = tokens.size();
        int maxLen = longestLemma + 1;
        LexiconMatch[] matches = new LexiconMatch[n + 1];
        double[] best = new double[n + 1];
        best[0] = 0;
        for (int end = 1; end <= n; end++) {
           matches[end] = new LexiconMatch(tokens.get(end - 1), 0d, "", null);
           for (int start = end - 1; start >= 0 && start >= (end - maxLen); start--) {
              HString span = HString.union(tokens.subList(start, end));
              LexiconEntry entry = getEntries(span).stream().findFirst().orElse(new LexiconEntry("", 0, null, null));
              LexiconMatch score = new LexiconMatch(span, entry.getProbability(), entry.getLemma(), entry.getTag());
              double segmentScore = score.getScore() + best[start];
              if (segmentScore >= best[end]) {
                 best[end] = segmentScore;
                 matches[end] = score;
              }
           }
        }
        int i = n;
        List<HString> results = new LinkedList<>();
        while (i > 0) {
           LexiconMatch match = matches[i];
           if (match.getScore() > 0) {
              results.add(createFragment(match));
           }
           i = i - matches[i].getSpan().tokenLength();
        }
  
        Collections.reverse(results);
        return results;
     }
docs: Viterbi list.
  
  @param source the source
  @return the list