Back to all solutions

#2030 - Smallest K-Length Subsequence With Occurrences of a Letter

Problem Description

You are given a string s, an integer k, a letter letter, and an integer repetition.

Return the lexicographically smallest subsequence of s of length k that has the letter letter appear at least repetition times. The test cases are generated so that the letter appears in s at least repetition times.

A subsequence is a string that can be derived from another string by deleting some or no characters without changing the order of the remaining characters.

A string a is lexicographically smaller than a string b if in the first position where a and b differ, string a has a letter that appears earlier in the alphabet than the corresponding letter in b.

Solution

/**
 * @param {string} s
 * @param {number} k
 * @param {character} letter
 * @param {number} repetition
 * @return {string}
 */
var smallestSubsequence = function(s, k, letter, repetition) {
  const n = s.length;
  let letterTotal = 0;
  for (let i = 0; i < n; i++) {
    if (s[i] === letter) letterTotal++;
  }

  const stack = [];
  let stackLetterCount = 0;
  let remainingCount = letterTotal;

  for (let i = 0; i < n; i++) {
    const char = s[i];

    if (char === letter) {
      remainingCount--;
    }

    while (
      stack.length > 0 && stack[stack.length - 1] > char && stack.length - 1 + (n - i) >= k
      && (stack[stack.length - 1] !== letter || stackLetterCount + remainingCount > repetition)
    ) {
      if (stack[stack.length - 1] === letter) {
        stackLetterCount--;
      }
      stack.pop();
    }

    if (stack.length < k) {
      if (char === letter) {
        stackLetterCount++;
      }

      const neededLetters = repetition - stackLetterCount;
      const remainingPositions = k - stack.length - 1;
      if (char === letter || remainingPositions >= neededLetters) {
        stack.push(char);
      }
    }
  }

  if (stackLetterCount < repetition) {
    let missingLetters = repetition - stackLetterCount;
    const result = [...stack];

    for (let i = k - 1; i >= 0 && missingLetters > 0; i--) {
      if (result[i] !== letter) {
        result[i] = letter;
        missingLetters--;
      }
    }

    return result.join('');
  }

  return stack.join('');
};