在我的算法中,从最多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();
}

在我的算法中,从最多K个数字替换中找到最大的回文数,我遗漏了什么极端情况

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。)

最后:像这样调试代码的最简单的方法是生成小于一定大小的所有可能的实例(或至少其中的许多),并将你的算法的输出与已知的(例如暴力破解)算法的输出进行比较,一旦你遇到具有不同输出的输入就停止。这将(通常)给你一个足够小的例子来手动分析。