したいので計算の数字に必要な切文字列への回文?
-
19-09-2019 - |
質問
私は最近、コンテスト問題の確認を行うために以下の計算の最低文字数を挿入しなければな(もの)に文字列が回文.
例えば、文字列:"abcbd"まで回文に挿入しで文字:後に"a"別後の"d":"adbcbda".
といっていいのかもしれない一般化する同様の問題が問われるのと同じものを除き、文字で付加することはかなりシンプル溶液をO(N)のハッシュテーブル
そこで広く用いられている修正の Levenshtein距離アルゴリズム この問題を解決するものなした取り組みは成功しています。のお役に立てるようどのように解決するのか(でんする必要が効率的で、私を行なっている方々が入会させDP液)によりお願い申し上げます。
解決
注:これは単なる好奇心です。 DAVはOで(N ^ 2)時間とO(N ^ 2)空間容易(より良い簿記と、おそらくOを(n))を実行するためにDPアルゴリズムに変更することができるアルゴリズムを提案した。
あなたが許可された操作を変更することを決定した場合は、もちろん、この「ナイーブ」アルゴリズムは、実際に便利になるかもしれません。
<時間>ここでは、おそらく巧妙な簿記を速くすることができる「naive'ishアルゴリズムである。
の文字列を考えると、我々は結果の回文の真ん中を推測し、その文字列その真ん中の周りに回文を作るために必要なインサートの数を計算してみます。
文字列が長さnである場合、、2N + 1の可能な中学(各文字は、直前と単なる文字列の後に、2つの文字の間、)があります。
私たちは私たちに二つの文字列LとR(左から右へと1対1に)与え真ん中を考えるとします。
私たちは挿入を使用している場合、私はDPで最長共通部分のアルゴリズムrel="noreferrer">の最短共通参照、両方のLが含まれており、Rの逆の「スーパー」という文字列を作成し使用することができますsupersequence でます。
あなたに最も小さい番号の挿入を与える真ん中を選びます。
このはO(N ^ 3)である私は信じています。 (注:私はそれが真実であることを証明しようとしていない)。
他のヒント
私C#ソ見を繰り返すように文字を文字列として使用する削減の数に占めるがある場合には、 プログラム, 使用している"r"の文字として境界線。内部にrっくりと回文を(再帰的に).外でのrの、ミラーの文字の左側と右側。
一部入力により最短出力: 出力 可 toutptuot または outuputuo.私のソリューションの選択の可能性が広がる。
一例を走る:
- レーダー -> レーダー, 0を挿入
- esystem -> metsystem, 2つ挿入
- メッセージ -> megassagem, 3に挿入
- stackexchange -> stegnahckexekchangets,8挿入
について最初にチェックをする必要の場合の入力は回文:
public static bool IsPalindrome(string str)
{
for (int left = 0, right = str.Length - 1; left < right; left++, right--)
{
if (str[left] != str[right])
return false;
}
return true;
}
その後必ず繰り返し文字を入力します。があります。の言葉 メッセージ 二つの最も繰り返し文字('e'、's'):
private static bool TryFindMostRepeatedChar(string str, out List<char> chs)
{
chs = new List<char>();
int maxCount = 1;
var dict = new Dictionary<char, int>();
foreach (var item in str)
{
int temp;
if (dict.TryGetValue(item, out temp))
{
dict[item] = temp + 1;
maxCount = temp + 1;
}
else
dict.Add(item, 1);
}
foreach (var item in dict)
{
if (item.Value == maxCount)
chs.Add(item.Key);
}
return maxCount > 1;
}
私のアルゴリズムはこちら:
public static string MakePalindrome(string str)
{
List<char> repeatedList;
if (string.IsNullOrWhiteSpace(str) || IsPalindrome(str))
{
return str;
}
//If an input has repeated characters,
// use them to reduce the number of insertions
else if (TryFindMostRepeatedChar(str, out repeatedList))
{
string shortestResult = null;
foreach (var ch in repeatedList) //"program" -> { 'r' }
{
//find boundaries
int iLeft = str.IndexOf(ch); // "program" -> 1
int iRight = str.LastIndexOf(ch); // "program" -> 4
//make a palindrome of the inside chars
string inside = str.Substring(iLeft + 1, iRight - iLeft - 1); // "program" -> "og"
string insidePal = MakePalindrome(inside); // "og" -> "ogo"
string right = str.Substring(iRight + 1); // "program" -> "am"
string rightRev = Reverse(right); // "program" -> "ma"
string left = str.Substring(0, iLeft); // "program" -> "p"
string leftRev = Reverse(left); // "p" -> "p"
//Shave off extra chars in rightRev and leftRev
// When input = "message", this loop converts "meegassageem" to "megassagem",
// ("ee" to "e"), as long as the extra 'e' is an inserted char
while (left.Length > 0 && rightRev.Length > 0 &&
left[left.Length - 1] == rightRev[0])
{
rightRev = rightRev.Substring(1);
leftRev = leftRev.Substring(1);
}
//piece together the result
string result = left + rightRev + ch + insidePal + ch + right + leftRev;
//find the shortest result for inputs that have multiple repeated characters
if (shortestResult == null || result.Length < shortestResult.Length)
shortestResult = result;
}
return shortestResult;
}
else
{
//For inputs that have no repeated characters,
// just mirror the characters using the last character as the pivot.
for (int i = str.Length - 2; i >= 0; i--)
{
str += str[i];
}
return str;
}
}
る必要がありますので注意して逆機能:
public static string Reverse(string str)
{
string result = "";
for (int i = str.Length - 1; i >= 0; i--)
{
result += str[i];
}
return result;
}
の C# のの再帰的解決策は、文字列の末尾に追加する:
強いです>2ベースケースがあります。長さは、1または2再帰ケースである場合:極値が等しい場合、次いで 両極端のない内部の文字列を回文作り、極端にそれを返します。 両極端が等しくない場合は、最後に最初の文字を追加し、回文作り 前の最後の文字を含む内側の列。それを返します。
public static string ConvertToPalindrome(string str) // By only adding characters at the end
{
if (str.Length == 1) return str; // base case 1
if (str.Length == 2 && str[0] == str[1]) return str; // base case 2
else
{
if (str[0] == str[str.Length - 1]) // keep the extremes and call
return str[0] + ConvertToPalindrome(str.Substring(1, str.Length - 2)) + str[str.Length - 1];
else //Add the first character at the end and call
return str[0] + ConvertToPalindrome(str.Substring(1, str.Length - 1)) + str[0];
}
}