给定字符串的可能回文检查 - 需要高效代码

Possible Palindrome check from given string - efficient code needed

我正在解决 Palindrome index 问题。问题的难度级别很简单,但我仍然没有通过所有测试用例:(。在大多数测试用例中,我超时了,令人惊讶的是,一个测试用例也失败了。我在谷歌上搜索了回文检查——似乎只有两种方法——

1. Using StringBuilder reverse() method.
2. Comparing characters till mid of the string length.

我尝试了两种方法,但仍然没有成功。

以下是我的尝试:

import java.util.Scanner;

public class PalindromeIndex {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int totalTestCases = Integer.parseInt(scanner.nextLine());

        String testString = null;
        StringBuffer outputString = new StringBuffer();
        for (int i = 0; i < totalTestCases; i++) {
            testString = scanner.nextLine();
            boolean is0thElementTrue = false;
            // One lettered word is always a palindrome so checked that
            // condition
            if (isPalindrome(testString) || testString.length() == 1) {
                outputString.append("-1");
            } else {
                if (isPalindrome(testString.substring(1))) {
                    outputString.append("0 ");
                    is0thElementTrue = true;
                }
                // See here j - index starts from 1 as initial case is
                // already
                // handled in above if-condition
                // Also see the condition checks [j < testString.length() -
                // 1;]
                // because (testString.length() - 1) is checked separately
                // after
                // this for loop.;
                boolean isLoopSuccessAtleastOnce = false;
                for (int j = 1; j < testString.length() - 1; j++) {
                    if (isPalindrome(testString.substring(0, j)
                            + testString.substring(j + 1, testString.length()))) {
                        isLoopSuccessAtleastOnce = true;
                        if (is0thElementTrue) {
                            outputString.append(j);
                            is0thElementTrue = false;
                        } else
                            outputString.append(" " + j);
                    }
                }
                if (isPalindrome(testString.substring(0,
                        testString.length() - 1))) {
                    if (isLoopSuccessAtleastOnce)
                        outputString.append(" " + (testString.length() - 1));
                    else
                        outputString.append((testString.length() - 1));
                }
            }
            outputString.append("\n");
        }
        System.out.println(outputString.toString());
        scanner.close();
    }

    private static boolean isPalindrome(String str) {
        StringBuilder strBuffer = new StringBuilder(str);
        return str.equalsIgnoreCase(strBuffer.reverse().toString());
    }

    private static boolean isPalindrome_2ndWay(String str) {
        int n = str.length();
        for (int i = 0; i < (n / 2) + 1; ++i) {
            if (str.charAt(i) != str.charAt(n - i - 1)) {
                return false;
            }
        }

        return true;
    }
}

这就是我的答案:

String text = "Anita lava la tina";
text = text.toLowerCase().replaceAll(" ", "");

StringBuilder strb = new StringBuilder(text);

String text2 = strb.reverse().toString();

System.out.println("Palindrome: " + text.equals(text2));

您的解决方案是二次方的,这绝对不是该网站正在寻找的,您可以做得更好。

考虑一下。如果第一个和最后一个字符彼此不相等,那么其中一个就是答案。如果它们相等,则可以将相同的逻辑应用于第二个和最后一个字符的前一个。等等

尝试更有效的解决方案:使用 StringBuilder.deleteCharAt(int index) 但请注意,您要么必须将其放回原位,要么从要测试的字符串中创建一个新的 StringBuilder。然后您可以迭代字符,删除它们并使用现有方法测试生成的字符串。

小记:

Note: If the character at the given index is a supplementary character, this method does not remove the entire character.

...但我不认为这是在此时测试您的 Unicode 知识。

问题描述为

figure out the index of the character on whose removal will make the string a palindrome. There will always be a valid solution. In case string is already palindrome, then -1 is also a valid answer

所以可以这样处理:

  • 找到使字符串不是回文的第一个字符,换句话说,第一个与 "mirror" 位置的字符不同的字符。
  • 如果没有这个字符,则字符串已经是回文
  • 如果有这样的字符,判断去掉它是否使字符串成为回文。如果是,则您已找到解决方案。如果不是,那么镜像位置的字符一定是答案(问题说明总是有一个有效的解决方案)。

找到使字符串不是回文的第一个字符是 O(n)。这个操作每个字符串最多会执行两次,所以全局解还是O(n).

这是一个可能的实现。它已通过所有测试

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class PalindromeIndex {

    public static void main(String[] args) {

        List<String> inputStrs = readInput();

        for (String inputStr : inputStrs) {
            int index = findIndexToRemove(inputStr);
            System.out.println(index);
        }
    }

    private static List<String> readInput() {
        int inputSize;
        List<String> inputStrs = new ArrayList<>();
        try(Scanner scanner = new Scanner(System.in)){
            inputSize = Integer.parseInt(scanner.nextLine());
            for (int i = 0; i < inputSize; i++) {
                inputStrs.add(scanner.nextLine());
            }
        }
        return inputStrs;
    }

    private static int findIndexToRemove(String inputStr){
        int i = findIndexOfDifference(inputStr);
        int result;
        if(i == -1){
            // String is a palindrome
            result = -1;
        } else {
            // Either the char at i or the char at the opposite side (length-1-i)
            // is the char to remove. Let's remove one of them and see
            // if the result is a palindrome
            if(findIndexOfDifference(removeChar(inputStr, i)) == -1){
                result = i;
            } else {
                result = inputStr.length() - 1 - i;
            }
        }
        return result;
    }

    /**
     * Returns the position of the first character that is not equal to the
     * character at its simmetric position (i.e. the char at the same position
     * counting from the opposite side of the string).
     */
    private static int findIndexOfDifference(String inputStr){
        int i=0, j=inputStr.length()-1;
        while(i<j && inputStr.charAt(i) == inputStr.charAt(j)){
            i++;
            j--;
        }
        int index;
        if(i<j){
            index = i;
        } else {
            index = -1;
        }
        return index;
    }

    private static String removeChar(String str, int charIndex){
        String firstPart = str.substring(0, charIndex);
        String secondPart = str.substring(Math.min(str.length(), charIndex+1), str.length());
        return firstPart + secondPart;
    }

}