【问题标题】:Where is the flaw in my algorithm to get the largest palindrome is a string representation of a number?我的算法中获得最大回文的缺陷在哪里是数字的字符串表示?
【发布时间】:2016-08-08 15:10:23
【问题描述】:

我试图获得最大的回文数,它可以通过k 替换字符串number 中的数字来形成。

例如

number="3943",k=1 --> "3993"

对于那个确切的测试用例,我收到了"393",而对于某些测试用例,我收到了类似的错误

未处理的异常:System.InvalidOperationException:序列 System.Linq.Enumerable.Last[TSource] 中不包含任何元素 (IEnumerable`1 源) 在 :0 在 Solution.LargestPalindrome (System.String numstr, Int32 k) [0x00197] 在 solution.cs:74 中 解决方案+c__AnonStorey0.m__0 (System.String str) [0x00009] 在 solution.cs:61

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution
{
    static bool IsPalindrome(string s)
    {
        // returns true or false depending on whether the string
        // s is a palindrome
        // e.g. "abba" --> true, "acba" --> false
        for(int i = 0, j = s.Length - 1; i < j; ++i, --j)
        {
            if(s[i] != s[j])
                return false;
        }
        return true;
    }

    static string Replace(string s, int i, char c)
    {
        // returns a copy of s with the character at index i
        // replaced by character c
        // e.g. "george",2,"x" --> "gexrge"
        string part1 = s.Length > 0 ? s.Substring(0, i) : string.Empty;
        string part2 = i < (s.Length - 1) ? c.ToString() : string.Empty;
        string part3 = (i + 1) < (s.Length - 1) ? s.Substring(i + 1, s.Length - i - 1) : string.Empty;
        return part1 + part2 + part3;
    }

    static string LargestPalindrome(string numstr, int k)
    {
        // numstr: string representation of number
        // k: maximum number of digit replacements allowed

        // if no digit replacements allowed, return same string
        if(k == 0)
            return numstr;

        // digrange will be {'0', '1', ..., '9'}
        List<char> digrange = new List<char>();
        for(char c = '0'; c <= '9'; ++c)
            digrange.Add(c);

        // possibilities will be all possibilities of replacing one digit from numstr
        // e.g. numstr="02" --> possibilities={"12","22","32",...,"92","00","01","03","09"}
        List<string> possibilities = new List<string>();        
        for(int i = 0; i < numstr.Length; ++i)
        {         
            foreach(char dig in digrange.Where(d => d != numstr[i]))
            {
                possibilities.Add(Replace(numstr,i,dig));
            }
        }

        // if k = 1, get all the strings in cumulativePossiblities that are palindromes; 
        // else, transform each into the largest palindrome formed by k - 1 character
        // replacements of itself
        var cumulativePossibilities =  k == 1 
            ? possibilities.Where(str => IsPalindrome(str))
            : possibilities.Select(str => LargestPalindrome(str, k - 1)).Where(str => IsPalindrome(str));

        // sort cumulativePossibilities in ascending order of the integer representation
        // of the strings
        cumulativePossibilities.ToList().Sort((s1,s2) => {
            Int64 i1 = Int64.Parse(s1),
                  i2 = Int64.Parse(s2);
            return (i1 > i2) ? 1 : ((i1 == i2) ? 0 : -1);
        });

        // get the last element of the now-sorted cumulativePossibilities, 
        // which will be the largest number represented by the possible strings
        // or will be null if there are none
        string largest = cumulativePossibilities.Last();

        // return the largest or "-1" if there were none
        return largest != null ? largest : "-1";
    }

    static void Main(String[] args)
    {
        string[] tokens_n = Console.ReadLine().Split(' ');
        int k = Convert.ToInt32(tokens_n[1]);
        string number = Console.ReadLine();
        // use brute force algorithm to find largest palindrome of the string
        // representation of the number after k replacements of characters
        Console.WriteLine(LargestPalindrome(number,k));
    }
}

【问题讨论】:

  • 我不确定这是否是一个好的 SO 问题,贴出一堵代码墙,希望有人能调试它。您是否尝试调试它?您说您有多个结果错误的测试用例...您是否调试并逐步检查代码以查看发生了什么以及哪里出错了?如果没有,请先试试这个。如果你这样做了,你发现了什么?这些信息可以缩小问题范围并帮助我们为您提供帮助。
  • 我猜在注释// or will be null if there are none....Last() 不返回null 下方的行中引发了异常(如堆栈跟踪所述),如果序列为空。也许你想要LastOrDefault(),但这可能只是一个症状,而不是真正的问题。

标签: c# string algorithm linq


【解决方案1】:

不是很有效的方法,但是实现起来很简单;关键特性是使用PalindromeSubstitutions(计算多少个字符的替换可以防止字符串成为回文)而不是IsPalindrome只是一个事实如果字符串是回文)

// How many characters should be substituted in order to
// turn the string into palindrom
private static int PalindromeSubstitutions(string value) {
  if (string.IsNullOrEmpty(value))
    return 0;

  int result = 0;

  for (int i = 0; i < value.Length / 2; ++i)
    if (value[i] != value[value.Length - 1 - i])
      result += 1;

  return result;
}

// Let's test all substrings of size Length, Length - 1, ... , 2, 1
// until we find substring with required tolerance
private static string BestPalindromeSubstitutions(string value, int tolerance) {
  for (int size = value.Length; size >= 1; --size)
    for (int start = 0; start <= value.Length - size; ++start)
      if (PalindromeSubstitutions(value.Substring(start, size)) <= tolerance)
        return value.Substring(start, size);

  return "";
}

private static string SubstituteToPalindrome(string value) {
  if (string.IsNullOrEmpty(value))
    return value;

  StringBuilder sb = new StringBuilder(value);

  for (int i = 0; i < value.Length / 2; ++i) 
    sb[value.Length - 1 - i] = sb[i];

  return sb.ToString();
}

测试:

 string input = "73943";
 string best = BestPalindromeSubstitutions(input, 1);
 string report = 
   string.Format("Best palindrome {0} -> {1}", best, SubstituteToPalindrome(best));

输出

   Best palindrome 3943 -> 3993

【讨论】:

    【解决方案2】:

    这个问题是贪心算法的一个非常简单的例子。让我们首先计算将数字转换为回文需要(至少)多少次排列。

    int req = 0;
    for(int i = 0; i <= (s.length()-1)/2; i++){
        if (s[i] != s[s.length()-1-i] && i != s.length()-1-i) req++;
    }
    

    现在完成后,让我们再次从左到右遍历数字:i 遍历 0(s.length()-1)/2 包括在内。考虑以下情况(这里i不是中间字母,这种情况我们单独考虑):

    • s[i] == s[s.length()-i-1],没有计入req,所以如果k &gt;= req + 2s[i] != '9',我们把两个字母都改成'9',把k减2,req保持不变。但请注意,我们保证有足够的操作来确保该数字可以变成回文(如果最初可能的话)
    • s[i] != s[s.length()-i-1] - 现在如果k == req 或其中一个字母是'9',则执行以下操作:s[i]=s[s.length()-i-1]=max({s[i], s[s.length()-i-1]})。将kreq 都减少1
    • 现在如果k &gt; req 和两个字母都不是'9',我们将它们都更改为9k -= 2, req -= 1.

    现在如果i = s.length()-i-1k &gt; 0,将这封信s[i] 更改为'9'

    你最终得到的结果就是你想要的。

    总复杂度为O(n)

    【讨论】:

      猜你喜欢
      • 2016-12-07
      • 1970-01-01
      • 2017-06-20
      • 2020-07-29
      • 1970-01-01
      • 2023-03-11
      • 2017-09-06
      • 1970-01-01
      • 2013-10-08
      相关资源
      最近更新 更多