web-dev-qa-db-ja.com

パリンドロームであるすべての部分文字列を見つける

入力が「abba」の場合、可能な回文はa、b、b、a、bb、abbaです。
文字列が回文であるかどうかを判断するのは簡単です。次のようになります。

public static boolean isPalindrome(String str) {
 int len = str.length();
 for(int i=0; i<len/2; i++) {
     if(str.charAt(i)!=str.charAt(len-i-1) {
         return false;
     }
 return true;  
}

しかし、パリンドロームの部分文字列を見つける効率的な方法は何ですか?

20
Himanshu Yadav

おそらく、潜在的な中間文字(奇数長パリンドローム)および文字間の中間点(偶数長パリンドローム)を反復処理し、それ以上取得できなくなるまでそれぞれを拡張できます(次の左右の文字が一致しません)。

文字列に多くのpallidromesがない場合、それは多くの計算を節約します。そのような場合、コストはO(n)疎パリドローム文字列の場合になります。

パリンドロームの密な入力の場合、各位置は配列の長さ/ 2を超えて拡張できないため、O(n ^ 2)になります。明らかに、配列の端に向かってこれはさらに小さくなります。

  public Set<String> palindromes(final String input) {

     final Set<String> result = new HashSet<>();

     for (int i = 0; i < input.length(); i++) {
         // expanding even length palindromes:
         expandPalindromes(result,input,i,i+1);
         // expanding odd length palindromes:
         expandPalindromes(result,input,i,i);
     } 
     return result;
  }

  public void expandPalindromes(final Set<String> result, final String s, int i, int j) {
      while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) {
            result.add(s.substring(i,j+1));
            i--; j++;
      }
  }
18
Valentin Ruano

したがって、それぞれの異なる文字はすでに回文です-したがって、すでにN + 1回の回文があります。ここで、Nは別個の文字の数(および空の文字列)です。これは1回の実行で実行できます-O(N)。

さて、非自明な回文では、文字列の各点が潜在的な回文の中心になるようにテストできます-両方向に成長します-Valentin Ruano提案。
各テストはO(N)であり、可能な「中心」の数もO(N)-centerは文字または2つの文字の間のスペースのいずれかです。これもValentinのソリューションの場合と同じです。

注:また、O(N) Manacher's algoritmに基づく問題の解決策もあります(記事では「最長回文」について説明していますが、すべてを数えるためにアルゴリズムを使用できますそのうちの)

9
kiruwka

この問題を解決するのに役立つ独自のロジックを思いつきました。ハッピーコーディング.. :-)

System.out.println("Finding all palindromes in a given string : ");
        subPal("abcacbbbca");

private static void subPal(String str) {
        String s1 = "";
        int N = str.length(), count = 0;
        Set<String> palindromeArray = new HashSet<String>();
        System.out.println("Given string : " + str);
        System.out.println("******** Ignoring single character as substring palindrome");
        for (int i = 2; i <= N; i++) {
            for (int j = 0; j <= N; j++) {
                int k = i + j - 1;
                if (k >= N)
                    continue;
                s1 = str.substring(j, i + j);
                if (s1.equals(new StringBuilder(s1).reverse().toString())) {
                    palindromeArray.add(s1);
                }
            }

        }
        System.out.println(palindromeArray);
        for (String s : palindromeArray)
            System.out.println(s + " - is a palindrome string.");
        System.out.println("The no.of substring that are palindrome : "
                + palindromeArray.size());
    }
Output:-
Finding all palindromes in a given string : 
Given string : abcacbbbca
******** Ignoring single character as substring palindrome ********
[cac, acbbbca, cbbbc, bb, bcacb, bbb]
cac - is a palindrome string.
acbbbca - is a palindrome string.
cbbbc - is a palindrome string.
bb - is a palindrome string.
bcacb - is a palindrome string.
bbb - is a palindrome string.
The no.of substring that are palindrome : 6
6
Bala

ベースケースから組み立てて、すべての回文ができるまで拡張することをお勧めします。

パリンドロームには、偶数番号と奇数番号の2種類があります。両方を同じ方法で処理する方法がわからないので、それを分割します。

1)すべての単一文字を追加する

2)このリストを使用すると、パリンドロームのすべての出発点が得られます。文字列の各インデックスに対してこれらの両方を実行します(少なくとも2つの長さが必要なため、1-> length-1):

findAllEvenFrom(int index){
  int i=0;
  while(true) {
    //check if index-i and index+i+1 is within string bounds

    if(str.charAt(index-i) != str.charAt(index+i+1)) 
      return; // Here we found out that this index isn't a center for palindromes of >=i size, so we can give up

    outputList.add(str.substring(index-i, index+i+1));
    i++;
  }
}
//Odd looks about the same, but with a change in the bounds.
findAllOddFrom(int index){
  int i=0;
  while(true) {
    //check if index-i and index+i+1 is within string bounds

    if(str.charAt(index-i-1) != str.charAt(index+i+1)) 
      return;

    outputList.add(str.substring(index-i-1, index+i+1));
    i++;
  }
}

これがランタイムのBig-Oに役立つかどうかはわかりませんが、各部分文字列を試すよりもはるかに効率的です。最悪の場合は、「すべての部分文字列を検索する」計画よりも悪いかもしれないすべて同じ文字の文字列ですが、ほとんどの入力ではほとんどの部分文字列が切り取られます。回文。

1
Eric Barr
public class PolindromeMyLogic {

static int polindromeCount = 0;

private static HashMap<Character, List<Integer>> findCharAndOccurance(
        char[] charArray) {
    HashMap<Character, List<Integer>> map = new HashMap<Character, List<Integer>>();
    for (int i = 0; i < charArray.length; i++) {
        char c = charArray[i];
        if (map.containsKey(c)) {
            List list = map.get(c);
            list.add(i);
        } else {
            List list = new ArrayList<Integer>();
            list.add(i);
            map.put(c, list);
        }
    }
    return map;
}

private static void countPolindromeByPositions(char[] charArray,
        HashMap<Character, List<Integer>> map) {
    map.forEach((character, list) -> {
        int n = list.size();
        if (n > 1) {
            for (int i = 0; i < n - 1; i++) {
                for (int j = i + 1; j < n; j++) {
                    if (list.get(i) + 1 == list.get(j)
                            || list.get(i) + 2 == list.get(j)) {
                        polindromeCount++;
                    } else {
                        char[] temp = new char[(list.get(j) - list.get(i))
                                + 1];
                        int jj = 0;
                        for (int ii = list.get(i); ii <= list
                                .get(j); ii++) {
                            temp[jj] = charArray[ii];
                            jj++;
                        }
                        if (isPolindrome(temp))
                            polindromeCount++;
                    }

                }
            }
        }
    });
}

private static boolean isPolindrome(char[] charArray) {
    int n = charArray.length;
    char[] temp = new char[n];
    int j = 0;
    for (int i = (n - 1); i >= 0; i--) {
        temp[j] = charArray[i];
        j++;
    }
    if (Arrays.equals(charArray, temp))
        return true;
    else
        return false;
}

public static void main(String[] args) {
    String str = "MADAM";
    char[] charArray = str.toCharArray();
    countPolindromeByPositions(charArray, findCharAndOccurance(charArray));
    System.out.println(polindromeCount);
}
}

これを試してください。その独自のソリューション。

0
Bhavani

コードは、回文であるすべての別個の部分文字列を見つけることです。これが私が試したコードです。正常に動作しています。

import Java.util.HashSet;
import Java.util.Set;

public class SubstringPalindrome {

    public static void main(String[] args) {
        String s = "abba";
        checkPalindrome(s);
}

public static int checkPalindrome(String s) {
    int L = s.length();
    int counter =0;
    long startTime = System.currentTimeMillis();
    Set<String> hs = new HashSet<String>();
    // add elements to the hash set
    System.out.println("Possible substrings: ");
    for (int i = 0; i < L; ++i) {
      for (int j = 0; j < (L - i); ++j) {
          String subs = s.substring(j, i + j + 1);
            counter++;
            System.out.println(subs);
            if(isPalindrome(subs))
                hs.add(subs);
      }
    }
    System.out.println("Total possible substrings are "+counter);
    System.out.println("Total palindromic substrings are "+hs.size());
    System.out.println("Possible palindromic substrings: "+hs.toString());
    long endTime = System.currentTimeMillis();
    System.out.println("It took " + (endTime - startTime) + " milliseconds");
    return hs.size();
}
public static boolean isPalindrome(String s) {
    if(s.length() == 0 || s.length() ==1)
        return true;
    if(s.charAt(0) ==  s.charAt(s.length()-1))
        return isPalindrome(s.substring(1, s.length()-1));
    return false;
}

}

出力:

可能なサブストリング:a b b a ab bb ba abb bba abba

可能な部分文字列の合計は10です

総回文部分文字列は4です

可能性のあるパリンドローム部分文字列:[bb、a、b、abba]

1ミリ秒かかりました

0
user8778562

私は次のコードを試してみました

合格したケースはほとんどありません。

abaaa --> [aba, aaa, b, a, aa] 
geek  --> [g, e, ee, k] 
abbaca --> [b, c, a, abba, bb, aca] 
abaaba -->[aba, b, abaaba, a, baab, aa] 
abababa -->[aba, babab, b, a, ababa, abababa, bab] 
forgeeksskeegfor --> [f, g, e, ee, s, r, eksske, geeksskeeg, 
                      o, eeksskee, ss, k, kssk]

コード

static Set<String> set = new HashSet<String>(); 
static String DIV = "|";

public static void main(String[] args) {
    String str = "abababa";
    String ext = getExtendedString(str);

    // will check for even length palindromes
    for(int i=2; i<ext.length()-1; i+=2) {
        addPalindromes(i, 1, ext);
    }
    // will check for odd length palindromes including individual characters
    for(int i=1; i<=ext.length()-2; i+=2) {
        addPalindromes(i, 0, ext);
    }
    System.out.println(set);
}

/*
 * Generates extended string, with dividors applied
 * eg: input = abca
 * output = |a|b|c|a|
 */
static String getExtendedString(String str) {
    StringBuilder builder = new StringBuilder();
    builder.append(DIV);
    for(int i=0; i< str.length(); i++) {
        builder.append(str.charAt(i));
        builder.append(DIV);

    }
    String ext = builder.toString();
    return ext;
}

/*
 * Recursive matcher
 * If match is found for palindrome ie char[mid-offset] = char[mid+ offset]
 * Calculate further with offset+=2
 * 
 * 
 */
static void addPalindromes(int mid, int offset, String ext) {
    // boundary checks
    if(mid - offset <0 || mid + offset > ext.length()-1) {
        return;
    }
    if (ext.charAt(mid-offset) == ext.charAt(mid+offset)) {
        set.add(ext.substring(mid-offset, mid+offset+1).replace(DIV, ""));
        addPalindromes(mid, offset+2, ext);
    }
}

いいね

0
hemantvsn
    // Maintain an Set of palindromes so that we get distinct elements at the end
    // Add each char to set. Also treat that char as middle point and traverse through string to check equality of left and right char


static int palindrome(String str) {

    Set<String> distinctPln = new HashSet<String>();
    for (int i=0; i<str.length();i++) {
        distinctPln.add(String.valueOf(str.charAt(i)));
        for (int j=i-1, k=i+1; j>=0 && k<str.length(); j--, k++) {
            // String of lenght 2 as palindrome
            if ( (new Character(str.charAt(i))).equals(new Character(str.charAt(j)))) { 
                distinctPln.add(str.substring(j,i+1));
            }
            // String of lenght 2 as palindrome
            if ( (new Character(str.charAt(i))).equals(new Character(str.charAt(k)))) { 
                distinctPln.add(str.substring(i,k+1));
            }
            if ( (new Character(str.charAt(j))).equals(new Character(str.charAt(k)))) { 
                distinctPln.add(str.substring(j,k+1));
            } else {
                continue;
            }
        }
    }

    Iterator<String> distinctPlnItr = distinctPln.iterator();
    while ( distinctPlnItr.hasNext()) {
        System.out.print(distinctPlnItr.next()+ ",");
    }
    return distinctPln.size();

}
0
user5999909