2
def getLengthOfOptimalCompression(self, s: str, k: int) -> int:3
# We define f(i, curr_run_ch, run_length, nb_dels_remain) to return4
# the minimum, additional, number of characters it will cost to run-length5
# compress the substring s[i..n-1].6
# `curr_run_ch` is the character we have in the current "run", or the same7
# contiguous block of characters.8
# `run_length` is the length of the current "run", or the length of the9
# contiguous block of identical characters.10
# e.g. if we just encoded "aaaaa", `curr_run_ch` is "a" and `run_length` = 511
# `nb_dels_remain` is the number of delete operations we have available to us,12
# should we choose to use them15
def f(i, curr_run_ch, run_length, nb_dels_remain):19
key = (i, curr_run_ch, run_length, nb_dels_remain)23
# At character i, we have two possible options, we could choose to either24
# delete this character or keep this character. Each choice we make will25
# incurr some additional run-length encoding length for s[i..n-1]. We return26
# the minimum of the two.29
del_ch_cost = float("inf")30
if nb_dels_remain > 0:31
# Deleting s[i] means the latest character we kept stays the same AND32
# the current run-length of characters stays the same as well33
del_ch_cost = f(i + 1, curr_run_ch, run_length, nb_dels_remain - 1)37
if s[i] == curr_run_ch:38
# The new character at s[i] we are about to encode is the same as the character in the39
# current "run", we could choose to include it into the current run of course.40
# Be careful that if we started with run-length of 1, 9, 99, 999 and etc, encoding another41
# character same as `curr_run_ch` into the same "run" will require an extra digit.42
# e.g. 'a' => '2a' '9a' => '10a', '99a' => '100a'44
if run_length == 1 or len(str(run_length + 1)) > len(str(run_length)):46
keep_ch_cost = extra_digit_cost + f(47
i + 1, curr_run_ch, run_length + 1, nb_dels_remain50
# s[i] != curr_run_ch, we are going to need to run-length encode at least51
# one instance of s[i] which would cost 1, plus whatever the cost to encode52
# the rest. Of course that also means the current "run" will "reset" and start anew with53
# a single character s[i]54
keep_ch_cost = 1 + f(i + 1, s[i], 1, nb_dels_remain)56
memo[key] = min(keep_ch_cost, del_ch_cost)