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 void UpdateStateQueue(
      MinPriorityDecoderQueue<DecoderState> minPriorityDecoderQueue,
      DecoderState curState,
      DecoderState prevState,
      ScoredPhrasePairForSentence phrase,
      HashMap<DecoderState, BackPointerElement> backPointers) {
    BackPointerElement elem = backPointers.get(curState);

    if (elem == null || elem.getState().getScore() < curState.getScore()) {
      minPriorityDecoderQueue.insert(curState, curState.getScore());

      if (elem == null) {
        backPointers.put(curState, new BackPointerElement(prevState, phrase));
      } else {
        elem.setState(prevState);
        elem.setPhrase(phrase);
      }
    }
  }