我已经在这方面工作了好几个小时,我的解决方案是满足性能基准测试,并且几乎通过了所有测试用例。它是O(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();
}
答案 0 :(得分:2)
Abishek Bansal的评论是正确的:例如,如果sb =“1234561”和k = 4,你将首先使用2个子位移动到“1654561”(到目前为止是正确的) - 但是从那里到“1994991” “而不是”9654569“,因为您的while
循环更喜欢便宜的更改以更好地进行更改。
但还有第二个错误:为什么,在你的最后一个循环中,如果k == 1,你是否只尝试修改中间(i == j
)数字?这意味着,例如,对于输入sb =“121”和k = 4,当可能清楚地“999”时,您的算法将返回“929”。 (对于类似的反例,但k <= n,考虑输入sb =“929”和k = 2.)
最后:调试这样的代码的最简单方法是生成低于特定大小的所有可能实例(或至少其中很多)并将算法的输出与a的输出进行比较每个都有一个已知良好的(例如蛮力)算法,一旦你用不同的输出击中输入就停止。这将(通常)给你一个小到足以手动分析的例子。