103

たとえば、文字列「abaccddccefe」の「ccddcc」

解決策を考えましたが、O(n^2)時間で実行されます

アルゴリズム 1:

手順: 力ずくの方法


  1. i = 1 から i が array.length 未満の場合は2 つの for ループを持ち
    、j=i+1 から j が array.length 未満の場合は -1
  2. このようにして、配列から可能なすべての組み合わせの部分文字列を取得できます
  3. 文字列が回文かどうかをチェックする回文関数を用意する
  4. したがって、すべての部分文字列 (i,j) に対してこの関数を呼び出し、回文の場合は文字列変数に格納します
  5. 次の回文部分文字列が見つかった場合、それが現在のものよりも大きい場合は、現在のものに置き換えます。
  6. 最後に、文字列変数に答えがあります

問題: 1. このアルゴリズムは O(n^2) 時間で実行されます。

アルゴリズム 2:

  1. 文字列を反転し、別の配列に格納します
  2. 両方の配列間で一致する最大の部分文字列を見つけます
  3. しかし、これも O(n^2) 時間で実行されます

より良い時間で実行されるアルゴリズムを考えてもらえますか? できればO(n)時間

4

23 に答える 23

9

Algo 2 は、すべての文字列に対して機能するとは限りません。このような文字列「ABCDEFCBA」の例を次に示します。

文字列の部分文字列として「ABC」と「CBA」が含まれているわけではありません。元の文字列を逆にすると「ABCFEDCBA」になります。最長一致部分文字列は「ABC」であり、回文ではありません。

この最長一致部分文字列が実際に O(n^3) の実行時間を持つ回文であるかどうかをさらに確認する必要がある場合があります。

于 2010-11-14T00:12:05.847 に答える
5

私が問題を理解している限り、中央のインデックスの周りに回文を見つけて、中央の左右に検索を広げることができます。入力の隅に回文がないことがわかっているので、境界を 1 と長さ 1 に設定できます。文字列の最小境界と最大境界に注意を払いながら、対称インデックス (左右) の位置にある文字が、最大上限の中心に到達するまで、各中心位置で同じであるかどうかを検証します。

外側のループは O(n) (最大 n-2 反復) で、内側の while ループは O(n) (最大 (n / 2) - 1 反復) です。

これは、他のユーザーから提供された例を使用した私の Java 実装です。

class LongestPalindrome {

    /**
     * @param input is a String input
     * @return The longest palindrome found in the given input.
     */
    public static String getLongestPalindrome(final String input) {
        int rightIndex = 0, leftIndex = 0;
        String currentPalindrome = "", longestPalindrome = "";
        for (int centerIndex = 1; centerIndex < input.length() - 1; centerIndex++) {
            leftIndex = centerIndex - 1;  rightIndex = centerIndex + 1;
            while (leftIndex >= 0 && rightIndex < input.length()) {
                if (input.charAt(leftIndex) != input.charAt(rightIndex)) {
                    break;
                }
                currentPalindrome = input.substring(leftIndex, rightIndex + 1);
                longestPalindrome = currentPalindrome.length() > longestPalindrome.length() ? currentPalindrome : longestPalindrome;
                leftIndex--;  rightIndex++;
            }
        }
        return longestPalindrome;
    }

    public static void main(String ... args) {
        String str = "HYTBCABADEFGHABCDEDCBAGHTFYW12345678987654321ZWETYGDE";
        String longestPali = getLongestPalindrome(str);
        System.out.println("String: " + str);
        System.out.println("Longest Palindrome: " + longestPali);
    }
}

この出力は次のとおりです。

marcello:datastructures marcello$ javac LongestPalindrome
marcello:datastructures marcello$ java LongestPalindrome
String: HYTBCABADEFGHABCDEDCBAGHTFYW12345678987654321ZWETYGDE
Longest Palindrome: 12345678987654321
于 2012-03-01T21:45:39.003 に答える
2

正規表現とルビーを使用すると、次のような短い回文をスキャンできます。

PROMPT> irb
>> s = "longtextwithranynarpalindrome"
=> "longtextwithranynarpalindrome"
>> s =~ /((\w)(\w)(\w)(\w)(\w)\6\5\4\3\2)/; p $1
nil
=> nil
>> s =~ /((\w)(\w)(\w)(\w)\w\5\4\3\2)/; p $1
nil
=> nil
>> s =~ /((\w)(\w)(\w)(\w)\5\4\3\2)/; p $1
nil
=> nil
>> s =~ /((\w)(\w)(\w)\w\4\3\2)/; p $1
"ranynar"
=> nil
于 2012-10-27T10:37:31.337 に答える
1

こんにちはこれは、文字列で最も長い回文を見つけるための私のコードです。アルゴリズムを理解するには、次のリンクを参照してください http://stevekrenzel.com/articles/longest-palnidrome

使用したテスト データは HYTBCABADEFGHABCDEDCBAGHTFYW12345678987654321ZWETYGDE です。

 //Function GetPalindromeString

public static string GetPalindromeString(string theInputString)
 { 

        int j = 0;
        int k = 0;
        string aPalindrome = string.Empty;
        string aLongestPalindrome = string.Empty ;          
        for (int i = 1; i < theInputString.Length; i++)
        {
            k = i + 1;
            j = i - 1;
            while (j >= 0 && k < theInputString.Length)
            {
                if (theInputString[j] != theInputString[k])
                {
                    break;
                }
                else
                {
                    j--;
                    k++;
                }
                aPalindrome = theInputString.Substring(j + 1, k - j - 1);
                if (aPalindrome.Length > aLongestPalindrome.Length)
                {
                    aLongestPalindrome = aPalindrome;
                }
            }
        }
        return aLongestPalindrome;     
  }
于 2010-12-24T08:23:08.703 に答える
1

最近こんな質問をされました。これが私が[最終的に]思いついた解決策です。JavaScript でやったのは、その言語では非常に簡単だからです。

基本的な概念は、可能な限り最小の複数文字の回文 (2 文字または 3 文字のいずれか) を探して文字列をたどることです。それができたら、回文でなくなるまで両側の境界線を広げます。その長さが現在の最長のものより長い場合は、保管して移動します。

// This does the expanding bit.
function getsize(s, start, end) {
    var count = 0, i, j;
    for (i = start, j = end; i >= 0 && j < s.length; i--, j++) {
        if (s[i] !== s[j]) {
            return count;
        }
        count = j - i + 1; // keeps track of how big the palindrome is
    }
    return count;
}

function getBiggestPalindrome(s) {
    // test for simple cases
    if (s === null || s === '') { return 0; }
    if (s.length === 1) { return 1; }
    var longest = 1;
    for (var i = 0; i < s.length - 1; i++) {
        var c = s[i]; // the current letter
        var l; // length of the palindrome
        if (s[i] === s[i+1]) { // this is a 2 letter palindrome
            l = getsize(s, i, i+1);
        }
        if (i+2 < s.length && s[i] === s[i+2]) { // 3 letter palindrome
            l = getsize(s, i+1, i+1);
        }
        if (l > longest) { longest = l; }
    }
    return longest;
}

これは間違いなくクリーンアップされ、もう少し最適化される可能性がありますが、最悪のシナリオ (同じ文字の文字列) を除いて、かなり良いパフォーマンスが得られるはずです。

于 2010-08-13T15:06:12.717 に答える
1

Regexpブルートフォースを回避する効率的なソリューション

文字列全体の長さから始まり、2 文字まで下向きに機能し、一致するとすぐに存在します

"abaccddccefe"regexp テストの場合、 を返す前に 7 つの一致がありましccddccた。

(.)(.)(.)(.)(.)(.)(\6)(\5)(\4)(\3)(\2)(\1)
(.)(.)(. )(.)(.)(.)(\5)(\4)(\3)(\2)(\1)
(.)(.)(.)(.)(.)(\5)( \4)(\3)(\2)(\1)
(.)(.)(.)(.)(.)(\4)(\3)(\2)(\1)
(.)( .)(.)(.)(\4)(\3)(\2)(\1)
(.)(.)(.)(.)(\3)(\2)(\1)
(. )(.)(.)(\3)(\2)(\1)

Dim strTest
wscript.echo Palindrome("abaccddccefe")

Sub Test()
Dim strTest
MsgBox Palindrome("abaccddccefe")
End Sub

関数

Function Palindrome(strIn)

Set objRegex = CreateObject("vbscript.regexp")

For lngCnt1 = Len(strIn) To 2 Step -1
    lngCnt = lngCnt1 \ 2
    strPal = vbNullString

    For lngCnt2 = lngCnt To 1 Step -1
        strPal = strPal & "(\" & lngCnt2 & ")"
    Next

    If lngCnt1 Mod 2 = 1 Then strPal = "(.)" & strPal

    With objRegex
        .Pattern = Replace(Space(lngCnt), Chr(32), "(.)") & strPal
        If .Test(strIn) Then
            Palindrome = .Execute(strIn)(0)
            Exit For
        End If
    End With
Next

End Function
于 2014-01-02T04:04:16.860 に答える
1

このトピックに関するウィキペディアの記事を参照してください。以下の記事から、線形 O(n) ソリューションの Manacher のアルゴリズムJava 実装のサンプル:

java.util.Arrays をインポートします。public class ManachersAlgorithm { public static String findLongestPalindrome(String s) { if (s==null || s.length()==0) return "";

char[] s2 = addBoundaries(s.toCharArray());
int[] p = new int[s2.length]; 
int c = 0, r = 0; // Here the first element in s2 has been processed.
int m = 0, n = 0; // The walking indices to compare if two elements are the same
for (int i = 1; i<s2.length; i++) {
  if (i>r) {
    p[i] = 0; m = i-1; n = i+1;
  } else {
    int i2 = c*2-i;
    if (p[i2]<(r-i)) {
      p[i] = p[i2];
      m = -1; // This signals bypassing the while loop below. 
    } else {
      p[i] = r-i;
      n = r+1; m = i*2-n;
    }
  }
  while (m>=0 && n<s2.length && s2[m]==s2[n]) {
    p[i]++; m--; n++;
  }
  if ((i+p[i])>r) {
    c = i; r = i+p[i];
  }
}
int len = 0; c = 0;
for (int i = 1; i<s2.length; i++) {
  if (len<p[i]) {
    len = p[i]; c = i;
  }
}
char[] ss = Arrays.copyOfRange(s2, c-len, c+len+1);
return String.valueOf(removeBoundaries(ss));   }
private static char[] addBoundaries(char[] cs) {
if (cs==null || cs.length==0)
  return "||".toCharArray();

char[] cs2 = new char[cs.length*2+1];
for (int i = 0; i<(cs2.length-1); i = i+2) {
  cs2[i] = '|';
  cs2[i+1] = cs[i/2];
}
cs2[cs2.length-1] = '|';
return cs2;   }
private static char[] removeBoundaries(char[] cs) {
if (cs==null || cs.length<3)
  return "".toCharArray();

char[] cs2 = new char[(cs.length-1)/2];
for (int i = 0; i<cs2.length; i++) {
  cs2[i] = cs[i*2+1];
}
return cs2;   }     }
于 2014-04-08T22:11:06.800 に答える
0

以下は JavaScript での実装です。

var longestPalindromeLength = 0;
var longestPalindrome = ''

function isThisAPalidrome(word){
  var reverse = word.split('').reverse().join('')
  return word == reverse
}

function findTheLongest(word){ // takes a word of your choice
  for(var i = 0; i < word.length; i++){ // iterates over each character
    var wordMinusOneFromBeginning = word.substr(i, word.length) // for each letter, create the word minus the first char
    for(var j = wordMinusOneFromBeginning.length; j > 0; j--){ // for the length of the word minus the first char
      var wordMinusOneFromEnding = wordMinusOneFromBeginning.substr(0, j) // create a word minus the end character
      if(wordMinusOneFromEnding <= 0) // make sure the value is more that 0,
      continue // if more than zero, proced to next if statement
      if(isThisAPalidrome(wordMinusOneFromEnding)){ // check if the word minus the first character, minus the last character = a plaindorme
        if(wordMinusOneFromEnding.length > longestPalindromeLength){ // if it is
          longestPalindromeLength = wordMinusOneFromEnding.length; // save its length
          longestPalindrome = wordMinusOneFromEnding // and save the string itself
        } // exit the statement that updates the longest palidrome
      } // exit the stament that checks for a palidrome
    } // exit the loop that goes backwards and takes a letter off the ending
  } // exit the loop that goes forward and takes off the beginning letter
  return console.log('heres the longest string: ' + longestPalindrome
  + ' its ' + longestPalindromeLength + ' charachters in length'); // return the longest palidrome! :)
}
findTheLongest('bananas');

于 2016-04-16T23:14:50.927 に答える
0

線形解の場合、Manacher のアルゴリズムを使用できます。Gusfield のアルゴリズムと呼ばれる別のアルゴリズムがあり、以下は Java のコードです。

public class Solution {  
    char[] temp;   
    public int match(int a, int b,int len){   
        int i = 0;   
        while (a-i>=0 && b+i<len && temp[a-i] == temp[b+i]) i++;   
        return i;   
    }  

    public String longestPalindrome(String s) {  

        //This makes use of the assumption that the string has not more than 1000 characters.  
        temp=new char[1001*2];  
        int[] z=new int[1001 * 2];  
        int L=0, R=0;  
        int len=s.length();  

        for(int i=0;i<len*2+1;i++){  
            temp[i]='.';  
        }  

        for(int i=0;i<len;++i){  
            temp[i*2+1] = s.charAt(i);  
        }  

        z[0]=1;  
        len=len*2+1;  

        for(int i=0;i<len;i++){  
            int ii = L - (i - L);     
            int n = R + 1 - i;  
            if (i > R)  
            {  
                z[i] = match(i, i,len);  
                L = i;  
                R = i + z[i] - 1;  
            }  
            else if (z[ii] == n)  
            {  
                z[i] = n + match(i-n, i+n,len);  
                L = i;  
                R = i + z[i] - 1;  
            }  
            else  
            {  
                z[i] = (z[ii]<= n)? z[ii]:n;  
            }   
        }  

        int n = 0, p = 0;  
        for (int i=0; i<len; ++i)  
            if (z[i] > n)  
                n = z[p = i];  

        StringBuilder result=new StringBuilder();  
        for (int i=p-z[p]+1; i<=p+z[p]-1; ++i)  
            if(temp[i]!='.')  
                result.append(String.valueOf(temp[i]));  

        return result.toString();  
    }  
}  

最良の O(n^2) ソリューションや Manacher のアルゴリズムなど、他のソリューションの詳細については、自分のブログを参照してください。

于 2015-07-31T07:01:40.323 に答える
0
  1. 区切り記号を使用して各文字を区切るように文字列を変更します [これは奇数回文と偶数回文を組み込むためです]
  2. 各文字を中心として、その周りの回文を見つけます

これを使用して、すべての長さのすべての回文を見つけることができます。

サンプル :

単語 = abcdcbc

modifiedString = a#b#c#d#c#b#c

パリン数 = 1010105010301

最長の回文の長さ = 5;

最長の回文 = bcdcb

public class MyLongestPalindrome {

static String word;
static int wordlength;
static int highestcount = 0;
static int newlength;
static char[] modifiedString; // stores modified string
static int[] palinCount; // stores palindrome length at each position
static char pound = '#';

public static void main(String[] args) throws IOException {
    // TODO Auto-generated method stub
    System.out.println("Enter String : ");
    InputStreamReader isr = new InputStreamReader(System.in);
    BufferedReader bfr = new BufferedReader(isr);
    word = bfr.readLine();
    wordlength = word.length();
    newlength = (wordlength * 2) - 1;
    convert();
    findpalindrome();
    display();
}

// Inserting # in string
public static void convert() {

    modifiedString = new char[newlength];
    int j = 0;
    int i;
    for (i = 0; i < wordlength - 1; i++) {
        modifiedString[j++] = word.charAt(i);
        modifiedString[j++] = pound;
    }
    modifiedString[j] = word.charAt(i);
}

// display all palindromes of highest length
public static void display() {
    String palindrome;
    String s = new String(modifiedString);
    System.out.println("Length of longest palindrome = " + highestcount);
    for (int i = 0; i < newlength; i++) {
        if (palinCount[i] == highestcount) {
            palindrome = s.substring(i - (highestcount - 1), i
                    + (highestcount));
            i = i + (highestcount - 1);
            palindrome = palindrome.replace("#", "");
            System.out.println(palindrome);
        }
    }
}

// populate palinCount with length of palindrome string at each position
public static void findpalindrome() {
    int left, right, count;
    palinCount = new int[newlength];
    palinCount[0] = 1;
    palinCount[newlength - 1] = 1;
    for (int i = 1; i < newlength - 1; i++) {
        count = 0;
        left = i - 1;
        right = i + 1;
        ;
        if (modifiedString[i] != pound)
            count++;
        while (left >= 0 && right < newlength) {
            if (modifiedString[left] == modifiedString[right]) {
                if (modifiedString[left] != pound)
                    count = count + 2;
                left--;
                right++;
            } else
                break;
        }

        palinCount[i] = count;
        highestcount = count > highestcount ? count : highestcount;

    }

}

}

于 2014-01-23T23:37:44.070 に答える
0

文字列「HYTBCABADEFGHABCDEDCBAGHTFYW123456789987654321ZWETYGDE」を試してください。偶数および奇数の仲間で機能するはずです。Mohitに感謝します!

名前空間 std を使用します。

string largestPal(string input_str)
{
  string isPal = "";
  string largest = "";
  int j, k;
  for(int i = 0; i < input_str.length() - 1; ++i)
    {
      k = i + 1;
      j = i - 1;

      // starting a new interation                                                      
      // check to see if even pal                                                       
      if(j >= 0 && k < input_str.length()) {
        if(input_str[i] == input_str[j])
          j--;
        else if(input_str[i] == input_str[j]) {
          k++;
        }
      }
      while(j >= 0 && k < input_str.length())
        {
          if(input_str[j] != input_str[k])
            break;
          else
            {
              j--;
              k++;
            }
          isPal = input_str.substr(j + 1, k - j - 1);
            if(isPal.length() > largest.length()) {
              largest = isPal;
            }
        }
    }
  return largest;
}
于 2011-04-20T06:03:50.470 に答える
0

ここで私はそれを試すロジックを書いています:)

public class palindromeClass{

public  static String longestPalindromeString(String in) {
        char[] input = in.toCharArray();
        int longestPalindromeStart = 0;
        int longestPalindromeEnd = 0;

        for (int mid = 0; mid < input.length; mid++) {
            // for odd palindrome case like 14341, 3 will be the mid
            int left = mid-1;
            int right = mid+1;
            // we need to move in the left and right side by 1 place till they reach the end
            while (left >= 0 && right < input.length) {
                // below check to find out if its a palindrome
                if (input[left] == input[right]) {
                    // update global indexes only if this is the longest one till now
                    if (right - left > longestPalindromeEnd
                            - longestPalindromeStart) {
                        longestPalindromeStart = left;
                        longestPalindromeEnd = right;
                    }
                }
                else
                    break;
                left--;
                right++;
            }
            // for even palindrome, we need to have similar logic with mid size 2
            // for that we will start right from one extra place
            left = mid;
            right = mid + 1;// for example 12333321 when we choose 33 as mid
            while (left >= 0 && right < input.length)
            {
                if (input[left] == input[right]) {
                    if (right - left > longestPalindromeEnd
                            - longestPalindromeStart) {
                        longestPalindromeStart = left;
                        longestPalindromeEnd = right;
                    }
                }
                else
                    break;
                left--;
                right++;
            }


        }
        // we have the start and end indexes for longest palindrome now
        return in.substring(longestPalindromeStart, longestPalindromeEnd + 1);
    }
public static void main(String args[]){
System.out.println(longestPalindromeString("HYTBCABADEFGHABCDEDCBAGHTFYW12345678987654321ZWETYGDE"));
}

}
于 2014-03-13T10:42:28.347 に答える
0

与えられた文字列から回文である最長の部分文字列を見つけるプログラム。

 package source;
    
    import java.util.ArrayList;
            
    public class LongestPalindrome 
    {
        //Check the given string is palindrome by 
        public static boolean isPalindrome (String s)
        {
            StringBuffer sb = new StringBuffer(s);
            if(s.equalsIgnoreCase(sb.reverse().toString()))
                return true;
            else
                return false;
        }
    
        public static void main(String[] args) 
        {
            //String / word without space
            String str = "MOMABCMOMOM"; // "mom" //abccbabcd
            
            if(str.length() > 2 )
            {
                StringBuffer sb = new StringBuffer();
                ArrayList<String> allPalindromeList = new ArrayList<>();
                        
                for(int i=0; i<str.length(); i++)
                {
                    for(int j=i; j<str.length(); j++)
                    {
                        sb.append(str.charAt(j));
                        if( isPalindrome(sb.toString()) ) {
                            allPalindromeList.add(sb.toString());                       
                        }
                    }
                    //clear the stringBuffer
                    sb.delete(0, sb.length());
                }
                 
                int maxSubStrLength = -1;
                int indexMaxSubStr = -1;
                int index = -1;
                
                for (String subStr : allPalindromeList) {
                    ++index;
                    if(maxSubStrLength < subStr.length()) {
                        maxSubStrLength = subStr.length();
                        indexMaxSubStr = index;
                    }
                }
                if(maxSubStrLength > 2)
                    System.out.println("Maximum Length Palindrome SubString is : "+allPalindromeList.get(indexMaxSubStr));
                else
                    System.out.println("Not able to find a Palindrome who is three character in length!!");
            
            }
        }
    
    }
于 2020-10-27T10:52:18.640 に答える
0

これは、指定された文字列から最長の回文文字列を返します

-(BOOL)isPalindromString:(NSString *)strInput
{
    if(strInput.length<=1){
        return NO;
    }
    int halfLenth = (int)strInput.length/2;

    BOOL isPalindrom = YES;
    for(NSInteger i=0; i<halfLenth; i++){

        char a = [strInput characterAtIndex:i];
        char b = [strInput characterAtIndex:(strInput.length-1)-i];

        if(a != b){
            isPalindrom = NO;
            break;
        }
    }
    NSLog(@"-%@- IS Plaindrom %@",strInput,(isPalindrom ? @"YES" : @"NO"));
    return isPalindrom;
}


-(NSString *)longestPalindrom:(NSString *)strInput
{
    if(strInput.length<=1){
        return @"";
    }

    NSString *strMaxPalindrom = @"";

    for(int i = 0; i<strInput.length ; i++){

        for(int j = i; j<strInput.length ; j++){

            NSString *strSub = [strInput substringWithRange:NSMakeRange(i, strInput.length-j)];

            if([self isPalindromString:strSub]){

                if(strSub.length>strMaxPalindrom.length){

                    strMaxPalindrom = strSub;
                }
            }
        }
    }
    NSLog(@"-Max - %@",strMaxPalindrom);
    return strMaxPalindrom;
}

-(void)test
{
    [self longestPalindrom:@"abcccbadeed"];
}

== 出力 ===

入力: abcccde 出力: ccc

入力: abcccbd 出力: bcccb

入力: abedccde 出力: edccde

入力: abcccdeed 出力: deed

入力: abcccbadeded 出力: abcccba

于 2016-01-24T17:47:05.137 に答える
-1

これが私のアルゴリズムです:

1) 現在の中心を最初の文字に設定する

2) 現在の中心付近で回文数が最大になるまで、左右に同時に展開します。

3) 見つかった回文が前の回文よりも大きい場合は、それを更新します。

4) 現在の中心を次の文字に設定する

5) 文字列内のすべての文字について、手順 2) から 4) を繰り返します。

これは O(n) で実行されます。

それが役に立てば幸い。

于 2012-04-23T21:37:28.657 に答える
-5

私の解決策は次のとおりです。

static string GetPolyndrom(string str)
{
    string Longest = "";

    for (int i = 0; i < str.Length; i++)
    {
        if ((str.Length - 1 - i) < Longest.Length)
        {
            break;
        }
        for (int j = str.Length - 1; j > i; j--)
        {
            string str2 = str.Substring(i, j - i + 1);
            if (str2.Length > Longest.Length)
            {
                if (str2 == str2.Reverse())
                {
                    Longest = str2;
                }
            }
            else
            {
                break;
            }
        }

    }
    return Longest;
}
于 2011-06-13T12:54:55.297 に答える