【问题标题】:finding the biggest subpalindrome in a string在字符串中找到最长的子回文
【发布时间】:2012-09-15 00:05:17
【问题描述】:

我正在尝试在 Java 中查找子回文。但是下面的代码没有提供正确的输出。

public static void main(String[] args)
{
    Scanner in = new Scanner(System.in);
    in.useDelimiter("\n");
    String text = in.next();
    int start = 0;
    int end = 0;

    int i = 0;
    int j = 0;
    while(i <= text.length())
    {
        j = i+1;
        while(j < text.length())
        {
            if(text.substring(i, j).equals(reverse(text.substring(i, j))))
            {
                if(j-i > end-start)
                {
                    start = i; end = j;
                }   
            }
            j++;
        }
        i++;
    }
    System.out.println(start + " : " + end);
}
static String reverse(String s)
{
    return new StringBuffer(s).reverse().toString();
}

样本输出:

apros tda adda
7 : 12
after the ostso
11 : 14
att feref
5 : 8

以上都错了。

PS:我知道这不是一个有效的算法。

【问题讨论】:

  • 我在查看此内容时找不到错误;你能发布另一个示例输出吗?
  • 请务必将花括号放在 if(j-i > end-start) 块周围,否则仅 start = i;将被设置。
  • @mprivat:我认为这可能是他的问题。这就是问题的全部吗?
  • 我其实在想为什么它不会崩溃...

标签: java


【解决方案1】:

有两个问题:

1:我在上面评论中提到的那个:

if(j-i > end-start) {
    start = i;
    end = j;
}

2:让j一直到正文结尾:

while(j <= text.length())

这是另一种可能性,既然您已经修复了代码,如果您愿意,我可以为您提供一个更优化的替代解决方案。找到最大的回文基本上是在一个字符串和它的反向之间找到最大的共同词。因此,从反转字符串(即 text2)开始。遍历文本 (i),然后有一个表示长度减小的子迭代(从 text.length()-i 下降到 0。如果您在 text2 中找到当前单词,那么您就找到了回文。您只需需要评估它是否是最大的。

一个明显的额外优化是,如果您已经找到回文,则长度的子迭代不需要降为零。

    String text = "absoopoo";       
    String text2 = new StringBuffer(text).reverse().toString();

    int start = 0;
    int end = -1;

    for(int i=0; i<text.length(); i++) {
        for(int length=text.length()-i; length > (end-start); length--) {
            String sub = text.substring(i, i+length);
            if(text2.indexOf(sub) >= 0) {
                start = i;
                end = start+length;
            }
        }
    }

    System.out.println(start + " : " + end+ " => "+text.substring(start, end));

【讨论】:

  • 很抱歉,不小心编辑了你的答案而不是我的答案,我尝试了 6 次才恢复原来的样子哈哈。
  • 好吧,这并不酷,我还为他的实现添加了 cmets,但你把它搞砸了 :) 我会读的。
【解决方案2】:

终于搞定了。

public static void main(String[] args)
{
    Scanner in = new Scanner(System.in);
    in.useDelimiter("\n");
    String text = in.next();

    int start = 0;
    int end = 0;

    int i = 0;
    int j = 0;
    while(i < text.length())
    {
        j = i;
        while(j <= text.length())
        {
            if(text.substring(i, j).equals(reverse(text.substring(i, j))))
            {
                if(j-i > 1 && j-i > end-start)
                {
                    start = i; 
                    end = j;
                }   
            }
            j++;
        }
        i++;
    }
    System.out.println(start + " : " + (end-1));
}
static String reverse(String s)
{
    return new StringBuffer(s).reverse().toString();
}

这是一个更优化的版本。这是基于this

public static void main(String[] args)
{
    Scanner in = new Scanner(System.in);
    in.useDelimiter("\n");
    char[] text = in.next().toCharArray();

    int start = 0;
    int end = 0;
    ArrayList<Integer[]> list = new ArrayList<Integer[]>();
    for( ;start<text.length; start++)
    {
        for(end=start; end<=start+1; end++)
        {
            list.add(grow(text, start, end));
        }
    }
    for(Integer[] v: list)
        System.out.println(v[0] +" : "+v[1]);
    findmax(list);
}
static Integer[] grow(char[] text, int start, int end)
{
    while(start>0 && end < text.length && text[start-1]==text[end])
    {
        start--;
        end++;
    }
    return new Integer[]{start, end};
}
static void findmax(ArrayList<Integer[]> list)
{
    int i=0; int j=0;
    for(Integer[] v: list)
    {
        if(v[1]-v[0]>j-i)
        {
            i = v[0];
            j = v[1];
        }
    }
    System.out.println(i+" "+j);
}

【讨论】:

  • 对上面的“优化”版本只有我的两分钱。我不确定这会快多少,因为您的算法现在是 O(n3) 而不是 O(n2)。
  • 第一个代码是 O(n3),因为字符串中有 N 个字符,N 个起始位置和 N 个结束位置。其次是 O(n2) 或更好,具体取决于输入。
  • 很高兴你让它工作了,对不起所有蹩脚的建议(我真的不应该尝试在 2 小时的睡眠中回答 SO 问题)。我确实觉得很奇怪,谷歌上的第二个链接错误地描述了 java 子字符串是如何工作的,尽管 homeandlearn.co.uk/java/substring.html
【解决方案3】:

让我们知道您是否需要它(以及它是否具有良好的性能):

/** Transmitted max size between to parses */
static int maxSize = 0;

/**
 * Said if the String is a palindrome.
 * 
 * @param s
 *            sentence to parse.
 */
static void singlePalindrome(final String s) {

    System.out.println("singlePalindrome: " + s);
    final char[] word = s.toCharArray();
    final int t = word.length;
    boolean ok = true;
    for (int i = t / 2; i > 0; i--) {

        if (word[i - 1] != word[word.length - i]) {

            ok = false;
            break;
        }

        System.out.println((i - 1) + ":" + word[i - 1] + "\t" + (t - i)
            + ":" + word[t - i]);
    }

    System.out.println("It is " + (true == ok ? "" : "NOT ")
        + "a palindrome.");
}

/**
 * Find all palindromes included anywhere in a sentence, with two search
 * phases from left to right and right to left. Then keep the biggest one *
 * 
 * @param sentence
 *            to parse
 * @param len
 *            minimal size of palindrome(s) to find.
 */
static void palindromeNested(final String sentence, final int len) {
    System.out.println(len + " = minimal size for palindromeNested(..): "
        + sentence);
    int debS = 2;
    String max = null;

    while (debS <= sentence.length()) {

        int i = debS / 2;
        int cpt = 0;
        for (; i <= debS; i++) {
            ++cpt;
            if (sentence.charAt(i) == sentence.charAt(debS - i)) {
                if (cpt >= len) {
                    final String sTmp = (i > debS - i) //
                        ? sentence.substring(debS - i, i + 1) //
                        : sentence.substring(i, debS - i + 1);

                    final int maxTmp = sTmp.length();
                    if (maxTmp > maxSize) {
                        maxSize = maxTmp;
                        max = sTmp;
                        System.out.println(maxTmp + "\t" + max);
                    }

                    // System.out.format("%4d:%-4d %d :: %d %s,\n", i, debS
                    // - i, cpt, maxTmp, sTmp);
                }

                continue;
            }

            break;
        }

        debS++;         
    }

    System.out.println("Result: " + max);

}

/** @param args */
public static void main(final String[] args) {

    singlePalindrome("abccdccba");// "abccddccba" works
    System.out.println("============================");

    // "baabcc dd ccbaabiib" works like "baabcc d ccbaabiib" (odd problem)
    final String words = "baabcc d ccbaabi o iba ab";
    palindromeNested(new StringBuilder(words).reverse().toString(), 3); // 3carsMini
    System.out.println("----------------------------");

    palindromeNested(words, maxSize / 2); // the max found in first
    System.out.println("============================");

}

}

输出:

单回文:abccdccba
3:c 5:c
2:c 6:c
1:b 7:b
0:a 8:a
这是一个回文。
==============================
3 = palindromeNested(..) 的最小尺寸:ba abi o ibaabcc d ccbaab
5 巴 ab
7 bi o ib
9 abi o iba
结果:abi o iba
----------------------------------------
4 = palindromeNested(..) 的最小尺寸:baabcc d ccbaabi o iba ab
11 abcc d ccba
13 aabcc d ccbaa
15 baabcc d ccbaab
结果:baabcc d ccbaab
=============================

【讨论】:

    猜你喜欢
    • 2016-08-01
    • 2015-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    • 2020-03-28
    相关资源
    最近更新 更多