在我的算法中,从最多K个数字替换中找到最大的回文数,我遗漏了什么极端情况
本文关键字:回文 情况 什么 算法 我的 替换 数字 | 更新日期: 2023-09-27 18:01:32
我已经为此工作了几个小时,我的解决方案符合性能基准,并且通过了几乎所有的测试用例。它是0 (n)在评论中有很好的描述。不幸的是,测试用例是如此巨大,以至于不可能逐一完成它们,所以我希望你们中的一个人可以提供一组新的眼睛,看看我是否可能在这里遗漏了一个角落用例。
static string LargestPalindromeAfterKReplacements(string number, int k)
{
// Finds the largest palindromic number (digits are the same in reverse order)
// that can be formed by at most k replacements of digits.
// e.g. "001", k=2 --> "909"
// "001", k=1 --> "101"
// "001", k=0 --> "-1" (not possible)
// Get number as a StringBuilder element
var sb = new StringBuilder(number);
// For the first pass through the string, replace any of the unequal
// characters on the left and right side by the larger of the two. For
// later use, keep track of the left index of each of these replacements.
var replacementIndices = new Queue<int>();
for(int i = 0, j = sb.Length - 1; i < j && k > 0; ++i, --j)
{
if(sb[i] < sb[j])
{
sb[i] = sb[j];
replacementIndices.Enqueue(i);
k -= 1;
}
else if(sb[i] > sb[j])
{
sb[j] = sb[i];
replacementIndices.Enqueue(i);
k -= 1;
}
}
// If sb isn't a palindrome at this point, then it was never possible to
// make it one.
if(!IsPalindrome(sb.ToString()))
return "-1";
// If here, sb is a palindrome. If we have any k left over, then for any of
// the indices where we made a replacement, if the pair isn't already both 9,
// we coudld've made them both 9 during the first pass through the string, at
// a cost decreasing k by 2 rather than by 1. "Replay" the original pass like this.
while(k > 0 && replacementIndices.Count > 0)
{
int i = replacementIndices.Dequeue(), j = sb.Length - i - 1;
if(sb[i] != '9')
{
sb[i] = '9';
sb[j] = '9';
k -= 1;
}
}
// In case we still have k > 0, that means we ran out of replacementIndices.
// Make a third pass through the string and make any non-equal characters
// on opposite ends become 9.
for(int i = 0, j = sb.Length - 1; i <= j && k > 0; ++i, --j)
{
if(sb[i] != '9')
{
if(k > 1)
{
sb[i] = '9';
sb[j] = '9';
k -= 2;
}
else if(i == j) // k = 1 and i = j
{
sb[i] = '9';
}
}
}
// In case we ran out of replacement indices,
return sb.ToString();
}
Abishek Bansal的评论是正确的:例如,如果sb =" 1234561"和k = 4,您将首先使用2个替换来移动到"1654561"(这是正确的到目前为止)-但然后从那里到"1994991"而不是"9654569",因为您的while
循环更喜欢便宜的更改而不是更好的更改。
但是有第二个错误:为什么在最后一个循环中,如果k == 1,您只尝试修改中间(i == j
)数字?这意味着,例如,对于输入sb ="121"和k = 4,你的算法将返回"929",而显然"999"是可能的。(对于一个类似的反例,但k <= n,考虑输入sb = "929"和k = 2。)