Run-length encoding is a string compression method that works by replacing consecutive identical characters (repeated 2 or more times) with the concatenation of the character and the number marking the count of the characters (length of the run). For example, to compress the string "aabccc" we replace "aa" by "a2" and replace "ccc" by "c3". Thus the compressed string becomes "a2bc3".
Notice that in this problem, we are not adding '1' after single characters.
Given a string s and an integer k. You need to delete at most k characters from s such that the run-length encoded version of s has minimum length.
Find the minimum length of the run-length encoded version of s after deleting at most k characters.
Input & Output
Example 1 — Basic Compression
$Input:s = "aaabcccd", k = 2
›Output:4
💡 Note:Delete 'b' and one 'c' to get "aaaccd" which compresses to "a3c2d" (length 4)
Example 2 — Single Character Run
$Input:s = "aabbaa", k = 2
›Output:2
💡 Note:Delete the two 'b's to get "aaaa" which compresses to "a4" (length 2)
Example 3 — No Compression Benefit
$Input:s = "ababacb", k = 0
›Output:7
💡 Note:No deletions allowed, each character is single so compressed length equals original length
Constraints
1 ≤ s.length ≤ 100
0 ≤ k ≤ s.length
s contains only lowercase English letters
Visualization
Tap to expand
Understanding the Visualization
1
Input Analysis
Original string with scattered identical characters
2
Strategic Deletion
Remove characters to create longer runs of same characters
3
Compression
Apply run-length encoding to get minimum length
Key Takeaway
🎯 Key Insight: Strategic deletion of characters can create longer consecutive runs, leading to better compression ratios than the original string.
The key insight is that we can strategically delete characters to create longer runs of identical characters, reducing compression length. The optimal approach uses dynamic programming with memoization to explore all deletion possibilities efficiently. Time: O(n×k×26×n), Space: O(n×k×26×n)
Common Approaches
Approach
Time
Space
Notes
✓
Dynamic Programming with Memoization
O(n * k * 26 * n)
O(n * k * 26 * n)
Use recursion with memoization to avoid recomputing the same subproblems
Bottom-up Dynamic Programming
O(n² * k)
O(n * k)
Build solution iteratively using a 2D DP table to track optimal compression lengths
Brute Force (Generate All Subsequences)
O(2^n)
O(n)
Generate all possible subsequences by deleting at most k characters and find minimum compression length
Dynamic Programming with Memoization — Algorithm Steps
Define state: position, deletions used, current character, run length
Use memoization to cache computed states
For each position, try keeping or deleting the character
Visualization
Tap to expand
Step-by-Step Walkthrough
1
State Definition
Track position, remaining deletions, current character, and run count
2
Memoization
Cache results for each unique state to avoid recomputation
3
Optimal Path
Find minimum cost path through the decision tree
Code -
solution.c — C
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_MEMO 100000
typedef struct {
int i, kLeft, lastCount;
char lastChar;
int result;
} MemoEntry;
MemoEntry memo[MAX_MEMO];
int memoSize = 0;
int getLength(int count) {
if (count == 1) return 1;
if (count < 10) return 2;
if (count < 100) return 3;
return 4;
}
int findMemo(int i, int kLeft, char lastChar, int lastCount) {
for (int j = 0; j < memoSize; j++) {
if (memo[j].i == i && memo[j].kLeft == kLeft &&
memo[j].lastChar == lastChar && memo[j].lastCount == lastCount) {
return memo[j].result;
}
}
return -1;
}
void addMemo(int i, int kLeft, char lastChar, int lastCount, int result) {
if (memoSize < MAX_MEMO) {
memo[memoSize].i = i;
memo[memoSize].kLeft = kLeft;
memo[memoSize].lastChar = lastChar;
memo[memoSize].lastCount = lastCount;
memo[memoSize].result = result;
memoSize++;
}
}
int dp(char* s, int i, int kLeft, char lastChar, int lastCount) {
if (kLeft < 0) return 1000000;
if (i == strlen(s)) {
return lastCount > 0 ? getLength(lastCount) : 0;
}
int cached = findMemo(i, kLeft, lastChar, lastCount);
if (cached != -1) return cached;
int res = 1000000;
// Delete current character
int deleteRes = dp(s, i + 1, kLeft - 1, lastChar, lastCount);
if (deleteRes < res) res = deleteRes;
// Keep current character
if (s[i] == lastChar) {
int keepRes = dp(s, i + 1, kLeft, lastChar, lastCount + 1);
if (keepRes < res) res = keepRes;
} else {
int prevLength = lastCount > 0 ? getLength(lastCount) : 0;
int keepRes = prevLength + dp(s, i + 1, kLeft, s[i], 1);
if (keepRes < res) res = keepRes;
}
addMemo(i, kLeft, lastChar, lastCount, res);
return res;
}
int solution(char* s, int k) {
memoSize = 0;
return dp(s, 0, k, '\0', 0);
}
int main() {
char s[101];
int k;
fgets(s, sizeof(s), stdin);
s[strcspn(s, "\n")] = 0;
scanf("%d", &k);
int result = solution(s, k);
printf("%d\n", result);
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(n * k * 26 * n)
n positions × k deletions × 26 characters × max run length n
n
2n
✓ Linear Growth
Space Complexity
O(n * k * 26 * n)
Memoization table stores states plus recursion stack
n
2n
⚡ Linearithmic Space
28.5K Views
MediumFrequency
~35 minAvg. Time
856 Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.