这是我的代码
using System;
public class Program
{
private static string GetLongestPalindrome(string input)
{
int rightIndex = 0, leftIndex = 0;
var x = "";
string currentPalindrome = string.Empty;
string longestPalindrome = string.Empty;
for(int currentIndex = 1; currentIndex < input.Length - 1; currentIndex++)
{
leftIndex = currentIndex - 1;
rightIndex = currentIndex + 1;
while(leftIndex >= 0 && rightIndex < input.Length)
{
if(input[leftIndex] != input[rightIndex])
{
break;
}
currentPalindrome = input.Substring(leftIndex, rightIndex - leftIndex + 1);
if(currentPalindrome.Length > x.Length)
x = currentPalindrome;
leftIndex--;
rightIndex++;
}
}
return x;
}
public static void Main()
{
Console.WriteLine(GetLongestPalindrome("12345354987"));
}
}
输出:
input = 12345354987,output = 345543.
这里最长的子阵列是345354,它可以重新排列形成345543,这是一个回文。
在上面的代码中,我获得了回文号45354.但是在使用C#重新排列345354
之后,上面的输入包含最大的回文数345543
。
答案 0 :(得分:3)
宝贝步骤......
你的方法做得太多,把它分解成你可以处理的小问题。我们需要解决什么?
好的,让我们这样做:
获取所有子字符串相对容易:
private static IEnumerable<string> GetAllSubSequences(
this string s)
=> from start in Enumerable.Range(0, s.Length)
from length in Enumerable.Range(1, s.Length - start)
select s.Substring(start, length);
或者如果您更喜欢流利的语法:
private static IEnumerable<string> GetAllSubSequences(string s)
=> Enumerable.Range(0, s.Length)
.SelectMany(start => Enumerable.Range(1, s.Length - start),
(start, length) => s.Substring(start, length));
现在我们需要一个方法来告诉我们一个给定的字符串是否可以转移到回文结构中。嗯......我们怎么能轻易做到这一点?我们可以检查所有可能的转变,但这看起来非常混乱和浪费。
Palindromes有两种口味;甚至长度的回文123321
和不均匀的长度123444321
。你看到我们可以利用这两种模式吗?看起来在前一种情况下,每个角色的总数必须是均匀的。在后者中,条件几乎相同,但也必须有一个且只有一个字符总数不均匀。
好的,让我们实现这个:
private static bool IsRearrangableIntoPalindrome(
this IEnumerable<char> characters)
=> characters.Count() % 2 == 0 ?
//all even
characters.GroupBy(c => c)
.All(g => g.Count() % 2 == 0):
//one odd
characters.GroupBy(c => c)
.Count(g => g.Count() % 2 != 0) == 1;
现在,我们只是将所有内容放在一起:
var str = "12345354987";
var largestPotentialPalindrome =
str.GetAllSubSequences()
.Where(s => s.IsRearrangableIntoPalindrome())
.OrderBy(s => s.Length)
.LastOrDefault();
果然,答案是3453549
,这是可以转移到回文中的最大子字符串:3459543
(等等)。
答案 1 :(得分:1)
我迟到了,因为已经为这个问题提供了一个很好的答案,但是自从我昨天开始研究这个问题并且刚刚结束,我想与社区分享我的方法。
我决定在不使用LINQ
并尽可能将代码生成为“传统”的情况下解决此问题。第一个问题是找到一种方法来检测potential palindrome
。正如@InBetween和我搜索的其他线程中的许多其他StackExchange用户所说,最简单的方法是:
这是我的实施:
private static Boolean IsPotentialPalindrome(String input)
{
Dictionary<Char,Int32> occurrences = new Dictionary<Char,Int32>();
Int32 inputLength = input.Length;
for (Int32 i = 0; i < inputLength; ++i)
{
Char c = input[i];
if (occurrences.ContainsKey(c))
++occurrences[c];
else
occurrences.Add(c, 1);
}
if ((inputLength % 2) == 0)
{
foreach (Int32 occurrence in occurrences.Values)
{
if ((occurrence % 2) != 0)
return false;
}
}
else
{
Boolean oddSpotted = false;
foreach (Int32 occurrence in occurrences.Values)
{
if ((occurrence % 2) != 0)
{
if (oddSpotted)
return false;
else
oddSpotted = true;
}
}
if (!oddSpotted)
return false;
}
return true;
}
一旦最困难的部分完成,我创建了主要方法来检测最长的潜在回文(包括创建给定输入的所有可能的substrings
)。由于可以检测到一个或多个具有最大长度的潜在回文,我选择返回List
。这是它:
private static List<String> GetLongestPotentialPalindromes(String input)
{
input = input.Trim().ToLowerInvariant();
List<String> potentials = new List<String>();
if (input.Length < 2)
return potentials;
for (Int32 i = 0; i < input.Length; ++i)
{
String potential = String.Empty;
for (Int32 j = i; j < input.Length; ++j)
{
potential += input[j];
if ((potential.Length > 1) && !potentials.Contains(potential) && IsPotentialPalindrome(potential))
potentials.Add(potential);
}
}
if (potentials.Count < 2)
return potentials;
Int32 maximumLength = 0;
foreach (String potential in potentials)
{
Int32 potentialLength = potential.Length;
if (potentialLength > maximumLength)
maximumLength = potentialLength;
}
List<String> finalPotentials = new List<String>();
foreach (String potential in potentials)
{
if (potential.Length == maximumLength)
finalPotentials.Add(potential);
}
return finalPotentials;
}
我的实施工作演示可以找到here。使用您的输入,它发现两个最长的潜在回文是:
2345354
3453549
答案 2 :(得分:0)
让我们提高效率。一些观察
HashSet
。当前项目将意味着它重复奇数次。 HashSet
直方图有一个很大的优势 - 你可以在恒定时间内测试你有多少奇数项目。len
,其中5个(不同)字符出现奇数次,那么您不必测试其子字符串的时间长于len - 4
。仅删除3个字符将留下至少2个奇数字符。本声明可以概括。代码在这里,根据输入,它可以比基本的暴力方法快几个数量级。
private static IEnumerable<string> GetLongestPotentialPalindromes2(string input)
{
HashSet<char> odds = new HashSet<char>();
void AddToSet(char c)
{
if (!odds.Add(c)) { odds.Remove(c); }
}
for (int len = input.Length; len > 0;)
{
odds.Clear();
for (int i = 0; i < len - 1; ++i)
{
AddToSet(input[i]);
}
int minOddCount = int.MaxValue;
for (int start = 0; start <= input.Length - len; ++start)
{
AddToSet(input[start + len - 1]);
int oddCount = odds.Count;
if (oddCount <= 1) { yield return input.Substring(start, len); }
minOddCount = Math.Min(minOddCount, oddCount);
AddToSet(input[start]);
}
if (minOddCount <= 1) { yield break; }
len -= minOddCount - 1;
}
}