2030. Smallest K Length Subsequence With Occurrences of a Letter
Problem Description
Given a string s, we need to find the lexicographically smallest subsequence of length k that contains the character letter exactly repetition number of times.
** Constraints:**
- 1 <= k <= s.length <= 1000
- 1 <= repetition <= k <= 1000
- 1 <= letter.length == 1
- s and letter consist of only lowercase English letters.
Example
Let's walk through an example:
Input: s = "leetcode", k = 4, letter = 'e', repetition = 2
Output: "eecd"
Explanation: The lexicographically smallest subsequence that meets the requirement is "eecd" with 2 'e' characters.
Approach
The main idea of the solution is to use a stack data structure to maintain the desired subsequence characters. We can iterate through the input string, and for each character, we try to keep the stack in lexicographically increasing order if the remaining characters and constraints allow us to do so.
There are three cases we need to cover:
- If the character is equal to
letter, push it onto the stack and decrement therequiredcount. - If the character is not equal to
letterand we can still push more characters onto the stack to meet the length ofk, push the character. - If the character is equal to
letterbut our stack is already full (stack.size() == k), don't push it to the stack.
Finally, we convert the stack into a string and return it as the answer.
ASCII Illustration
Suppose s = "leetcode", k = 4, letter = 'e', repetition = 2
Initial state:
stack = []required = 2nLetters = 3(number of 'letter' in the input string)
Processing each character of the input string:
s[0]: 'l'
stack = ['l']
s[1]: 'e'
stack = ['e'](pop 'l' since we need to add 'e')
s[2]: 'e'
stack = ['e', 'e']
s[3]: 't'
- Ignore (since we've already added the required number of 'e')
s[4]: 'c'
stack = ['e', 'e', 'c']
s[5]: 'o'
- Ignore (since adding 'o' would make the sequence lexographically larger)
s[6]: 'd'
stack = ['e', 'e', 'c', 'd'](our final subsequence)
s[7]: 'e'
- Ignore (already added the required number of 'e')
Final answer: "eecd".
Solution in Python
python class Solution: def smallestSubsequence(self, s: str, k: int, letter: str, repetition: int) -> str: ans = "" stack = [] required = repetition nLetters = s.count(letter) for i in range(len(s)): c = s[i] while stack and stack[-1] > c and len(stack) + len(s) - i - 1 >= k and (stack[-1] != letter or nLetters > required): popped = stack.pop() if popped == letter: required += 1 if len(stack) < k: if c == letter: stack.append(c) required -= 1 elif k > len(stack) + required: stack.append(c) if c == letter: nLetters -= 1 return "".join(stack)
Solution in Java
java
import java.util.*;
class Solution {
public String smallestSubsequence(String s, int k, char letter, int repetition) {
String ans = "";
List<Character> stack = new ArrayList<>();
int required = repetition;
int nLetters = (int) s.chars().filter(c -> c == letter).count();
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
while (!stack.isEmpty() && stack.get(stack.size() - 1) > c && stack.size() + s.length() - i - 1 >= k && (stack.get(stack.size() - 1) != letter || nLetters > required)) {
char popped = stack.remove(stack.size() - 1);
if (popped == letter)
++required;
}
if (stack.size() < k)
if (c == letter) {
stack.add(c);
--required;
} else if (k > stack.size() + required) {
stack.add(c);
}
if (c == letter)
--nLetters;
}
for (char c : stack)
ans += c;
return ans;
}
}
Solution in JavaScript
javascript class Solution { smallestSubsequence(s, k, letter, repetition) { let ans = ""; let stack = []; let required = repetition; let nLetters = s.split(letter).length - 1; for (let i = 0; i < s.length; ++i) { const c = s[i]; while (stack.length > 0 && stack[stack.length - 1] > c && stack.length + s.length - i - 1 >= k && (stack[stack.length - 1] != letter || nLetters > required)) { const popped = stack.pop(); if (popped == letter) ++required; } if (stack.length < k) if (c == letter) { stack.push(c); --required; } else if (k > stack.length + required) { stack.push(c); } if (c == letter) --nLetters; } return stack.join(""); } }
Solution in C++
cpp
#include <vector>
#include <string>
#include <algorithm>
class Solution {
public:
std::string smallestSubsequence(std::string s, int k, char letter, int repetition) {
std::string ans;
std::vector<char> stack;
int required = repetition;
int nLetters = count(begin(s), end(s), letter);
for (int i = 0; i < s.length(); ++i) {
const char c = s[i];
while (!stack.empty() && stack.back() > c &&
stack.size() + s.length() - i - 1 >= k &&
(stack.back() != letter || nLetters > required)) {
const char popped = stack.back();
stack.pop_back();
if (popped == letter)
++required;
}
if (stack.size() < k)
if (c == letter) {
stack.push_back(c);
--required;
} else if (k > stack.size() + required) {
stack.push_back(c);
}
if (c == letter)
--nLetters;
}
for (const char c : stack)
ans += c;
return ans;
}
};
Solution in C#
csharp using System; using System.Collections.Generic; public class Solution { public string SmallestSubsequence(string s, int k, char letter, int repetition) { string ans = ""; List<char> stack = new List<char>(); int required = repetition; int nLetters = s.Length - s.Replace(letter.ToString(), "").Length; for (int i = 0; i < s.Length; ++i) { char c = s[i]; while (stack.Count > 0 && stack[^1] > c && stack.Count + s.Length - i - 1 >= k && (stack[^1] != letter || nLetters > required)) { char popped = stack[stack.Count - 1]; stack.RemoveAt(stack.Count - 1); if (popped == letter) ++required; } if (stack.Count < k) if (c == letter) { stack.Add(c); --required; } else if (k > stack.Count + required) { stack.Add(c); } if (c == letter) --nLetters; } foreach (char c in stack) ans += c; return ans; } }
Explanation of the Solutions
In this problem, we need to find the smallest subsequence of length k containing the character letter exactly repetition times. We use a stack to push the characters of the input string while maintaining the lexicographically smallest subsequence.
Let's discuss the intuition and code implementation of each solution language.
Python Solution
The python solution defines a class Solution with a method smallestSubsequence that takes three parameters: s, k, letter, and repetition.
- Initialize an empty stack (
stack = []), a variablerequiredequal torepetition, and a variablenLettersequal to the count of occurrences of theletterin the input strings. - Iterate through the input string using the loop
for i in range(len(s)). At each iteration, store the current character in variablec, and handle three cases mentioned before. - If the character is higher in the lexicographical order, then pop it from the stack to maintain the lexicographically smallest subsequence.
- If the character is equal to the letter and the stack size is less than k, push c to the stack and decrease the required count.
- If the character is different from the letter and the stack size plus required is less than k, push c to the stack.
- If the character is equal to the letter, decrease the nLetters count.
- Join the stack to form a string and return it as the answer.
Java Solution
The Java solution is similar to the Python solution but uses a List
JavaScript Solution
In the JavaScript solution, we use the method split to count the occurrences of the letter in the input string s. The rest of the code follows the same steps as in the Python solution, but we use methods push and pop to add and remove elements from the stack, respectively.
C++ Solution
The C++ solution uses a vector of char to hold the subsequence characters. It uses the count method of the algorithm library to count the occurrences of the letter in the input string s. The code follows the same steps as in the Python solution, and the stack is a vector of char.
C# Solution
The C# solution uses a List
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorWhat's the output of running the following function using input [30, 20, 10, 100, 33, 12]?
1def fun(arr: List[int]) -> List[int]:
2 import heapq
3 heapq.heapify(arr)
4 res = []
5 for i in range(3):
6 res.append(heapq.heappop(arr))
7 return res
81public static int[] fun(int[] arr) {
2 int[] res = new int[3];
3 PriorityQueue<Integer> heap = new PriorityQueue<>();
4 for (int i = 0; i < arr.length; i++) {
5 heap.add(arr[i]);
6 }
7 for (int i = 0; i < 3; i++) {
8 res[i] = heap.poll();
9 }
10 return res;
11}
121class HeapItem {
2 constructor(item, priority = item) {
3 this.item = item;
4 this.priority = priority;
5 }
6}
7
8class MinHeap {
9 constructor() {
10 this.heap = [];
11 }
12
13 push(node) {
14 // insert the new node at the end of the heap array
15 this.heap.push(node);
16 // find the correct position for the new node
17 this.bubble_up();
18 }
19
20 bubble_up() {
21 let index = this.heap.length - 1;
22
23 while (index > 0) {
24 const element = this.heap[index];
25 const parentIndex = Math.floor((index - 1) / 2);
26 const parent = this.heap[parentIndex];
27
28 if (parent.priority <= element.priority) break;
29 // if the parent is bigger than the child then swap the parent and child
30 this.heap[index] = parent;
31 this.heap[parentIndex] = element;
32 index = parentIndex;
33 }
34 }
35
36 pop() {
37 const min = this.heap[0];
38 this.heap[0] = this.heap[this.size() - 1];
39 this.heap.pop();
40 this.bubble_down();
41 return min;
42 }
43
44 bubble_down() {
45 let index = 0;
46 let min = index;
47 const n = this.heap.length;
48
49 while (index < n) {
50 const left = 2 * index + 1;
51 const right = left + 1;
52
53 if (left < n && this.heap[left].priority < this.heap[min].priority) {
54 min = left;
55 }
56 if (right < n && this.heap[right].priority < this.heap[min].priority) {
57 min = right;
58 }
59 if (min === index) break;
60 [this.heap[min], this.heap[index]] = [this.heap[index], this.heap[min]];
61 index = min;
62 }
63 }
64
65 peek() {
66 return this.heap[0];
67 }
68
69 size() {
70 return this.heap.length;
71 }
72}
73
74function fun(arr) {
75 const heap = new MinHeap();
76 for (const x of arr) {
77 heap.push(new HeapItem(x));
78 }
79 const res = [];
80 for (let i = 0; i < 3; i++) {
81 res.push(heap.pop().item);
82 }
83 return res;
84}
85Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!