public List<ScoredPhrasePairForSentence> decode(List<String> sentence) {
    numSentences++;
    long startTime = System.nanoTime();

    int length = sentence.size();
    System.out.println(String.format("Sentence no: %d Length: %d", numSentences, length));

    PhraseTableForSentence phraseTableForSentence = phraseTable.initialize(sentence);

    List<HashMap<DecoderState, BackPointerElement>> backPointersList = new ArrayList<>(length + 1);
    initializeBackPointersList(backPointersList, length);

    List<MinPriorityDecoderQueue<DecoderState>> decoderStateQueues = new ArrayList<>(length + 1);
    initializeStateQueues(decoderStateQueues, length);

    DecoderState bestState = null;

    int counter = 0;
    for (int i = 0; i <= length; ++i) {
      MinPriorityDecoderQueue<DecoderState> decoderStateQueue = decoderStateQueues.get(i);

      while (decoderStateQueue.hasNext()) {
        counter = i;
        DecoderState state = decoderStateQueue.removeMin();
        bestState = state;

        List<ScoredPhrasePairForSentence> phrases =
            decoderModel.getPossiblePhrases(state, sentence, phraseTableForSentence);

        for (ScoredPhrasePairForSentence phrase : phrases) {
          DecoderState nextState = decoderModel.getNextState(state, phrase, sentence);
          if (nextState != null) {
            int nextLength = decoderModel.getDecodedLength(nextState);
            MinPriorityDecoderQueue<DecoderState> nextDecoderStateQueue =
                decoderStateQueues.get(nextLength);
            HashMap<DecoderState, BackPointerElement> nextBackPointers =
                backPointersList.get(nextLength);
            UpdateStateQueue(nextDecoderStateQueue, nextState, state, phrase, nextBackPointers);
          }
        }
      }
    }

    List<ScoredPhrasePairForSentence> finalPhrasePairs =
        readBackPointers(bestState, backPointersList, counter, length);

    long timeDuration = System.nanoTime() - startTime;
    double timeDurationInSeconds = (double) timeDuration / 1000000000;
    System.out.println(String.format("Time taken: %.2f seconds", timeDurationInSeconds));

    return finalPhrasePairs;
  }
  private List<ScoredPhrasePairForSentence> readBackPointers(
      DecoderState state,
      List<HashMap<DecoderState, BackPointerElement>> backPointersList,
      int startLength,
      int sentenceLength) {
    DecoderState curState = state;
    DecoderState startState = getStartState(sentenceLength);

    int curLength = startLength;

    List<ScoredPhrasePairForSentence> phrases = new ArrayList<>();
    while (!curState.equals(startState)) {
      BackPointerElement backPointer = backPointersList.get(curLength).get(curState);
      phrases.add(0, backPointer.getPhrase());
      curState = backPointer.getState();
      curLength = decoderModel.getDecodedLength(curState);
    }

    return phrases;
  }