从字符串的Arraylist

时间:2018-02-04 05:32:12

标签: java string palindrome

我试图在java中解决这个问题。我有一个回文字符串的arraylist。我必须从给定的数组列表中找到最短的回文串。我已经解决了这个问题,但我正在寻求获得有关我的代码的反馈,以及我如何尝试使代码更有效/更好。

以下是我尝试的代码。

在这种情况下,大小将为3,因为这是最小的回文字符串的长度

import java.util.ArrayList;
class ShortestPalindrome {
    public static int isShortestPalindrome(ArrayList<String> list) {
        int smallest = list.get(0).length();
        boolean ret = false;
        for (String element : list) {
            ret = isPalindrome(element);
            if (ret) {
                if (element.length() < smallest) 
                    smallest = element.length();                
            }
        }
        return smallest;
    }

    private static boolean isPalindrome(String input) {
        String str = "";
        boolean result = false;

        if (input.length() == 1 || input.length() == 0)
            return true;

        if (input.charAt(0) != input.charAt(input.length() - 1))
            return false;
        StringBuilder sb = new StringBuilder(input.toLowerCase());
        str = sb.reverse().toString();
        if (input.equals(str)) {
            result = true;
        }
        return result;
    }

    public static void main(String[] args) {
        ArrayList<String> array = new ArrayList<String>();
        array.add("malayam");
        array.add("aba");
        array.add("abcdeyugugi");
        array.add("nitin");
        int size = isShortestPalindrome(array);
        System.out.println("Shortest length of string in list:" + size);
    }
}

5 个答案:

答案 0 :(得分:1)

对代码的最简单改进是,只检查字符串是否是回文,如果它的长度小于smallest

Btw初始化int smallest = list.get(0).length();不正确,想象第一个元素不是回文并且是所有字符串的最小尺寸。你应该int smallest = Integer.MAX_VALUE;

还检查

if (input.charAt(0) != input.charAt(input.length() - 1))
            return false;

不正确,因为您不会将字符转换为小写字母(如稍后所做),因此"ajA"不会是回文。

您的代码可能会有进一步的改进:

您可以通过复制和倒车替换回文检查:

for (int i = 0; i < input.length() / 2; ++i)
    if (Character.toLowerCase(input.charAt(i)) != Character.toLowerCase(input.charAt(input.length() - 1 - i)))
        return false;

这里没有必要的副本,在一般情况下它可能更快(因为它可以提前终止)。

另外,就像AKSW提到的那样,按照长度对字符串进行排序可能会更快,然后一旦找到回文就可以提前终止。

答案 1 :(得分:1)

我对您的代码有几点意见:

  1. 一般情况下 - 如果您将问题分解为较小的部分,那么各地都有高效的解决方案。
  2. 正如 @AKSW 在评论中提到的,如果 - 无论如何 - 我们必须检查每个字符串的长度,最好在开头做 - 所以我们不会使用不相关的字符串运行相对昂贵的方法isPalindrome()
    (请注意我用已排序的方法覆盖给定列表,即使初始化新的排序列表也很简单)
  3. 我做的主要改进是isPalindrome()方法:
    • 反转长度为n的字符串需要 n 时间和其他 n 空间。比较两者也需要 n 时间。
      总体:2n时间,n空间
    • 比较每两个匹配的字符(从开头到结尾)需要 2 额外空间(对于整数)和 n / 2 时间。
      总体:n / 2次,2个空间
  4. 显然,当使用限制进行复杂度计算时,时间复杂度是相同的 - O(n) - 但第二种解决方案仍然便宜4倍,并且花费的空间可以忽略不计。

    因此,我相信这是实现测试的最有效方式:

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    
    class ShortestPalindrome {
        public static int isShortestPalindrome(ArrayList<String> list) {
            // Sorts the given ArrayList by length
            Collections.sort(list, Comparator.comparingInt(String::length));
            for (String element : list) {
                if(isPalindrome(element)) {
                    return element.length();
                }
            }
            return -1; // If there is no palindrome in the given array
        }
    
        private static boolean isPalindrome(String input) {
            String lowerCased = input.toLowerCase();
            int pre = 0;
            int end = lowerCased.length() - 1;
            while (end > pre) {
                if (lowerCased.charAt(pre) != lowerCased.charAt(end))
                    return false;
                pre ++;
                end --;
            }
            return true;
        }
    
        public static void main(String[] args) {
            ArrayList<String> array = new ArrayList<>(Arrays.asList("malayam", "aba", "abcdeyugugi", "nitin"));
            int size = isShortestPalindrome(array);
            System.out.println("Shortest length of string in list: " + size);
        }
    }
    



    编辑:我已使用以下列表测试了此算法。在检查回文之前对列表进行排序可以减少50%的运行时间。

      

    &#34; malayam&#34;,&#34; aba&#34;,&#34; abcdeyugugi&#34;,&#34; nitin&#34;,&#34; sadjsaudifjksdfjds&#34;,&# 34; sadjsaudifjksdfjdssadjsaudifjksdfjds&#34;,&#34; sadjsaudifjksdfjdssadjsaudifjksdfjdssadjsaudifjksdfjds&#34;,&#34; a&#34;

答案 2 :(得分:0)

下面简单的代码应该适合你。 首先检查长度然后检查它实际上是否是回文。 如果是,那么只需将其存储在最小的

public static int isShortestPalindrome(ArrayList<String> list) {
    Integer smallest = null;
    for(String s:list){
        if ( (smallest == null || s.length()< smallest) && new StringBuilder(s).reverse().toString().equalsIgnoreCase(s) ){
                smallest = s.length();
        }
    }
    return smallest == null ? 0 :smallest;
}

答案 3 :(得分:0)

这是一个流版本:

OptionalInt minimalLenOfPalindrome
            = list.paralellStream()
                    .filter(st -> {
                        StringBuilder sb = new StringBuilder(st);
                        String reversedSt = sb.reverse().toString();
                        return st.equalsIgnoreCase(reversedSt);
                    })
                    .mapToInt(String::length)
                    .min();

感谢@yassin回答我正在使用以下代码更改代码:

public class SOFlow {

    private static boolean isPalindrome(String input) {

        for (int i = 0; i < input.length() / 2; ++i) {
            if (Character.toLowerCase(input.charAt(i)) != Character.toLowerCase(input.charAt(input.length() - 1 - i))) {
            return false;
            }
        }
        return true;
    }

    public static void main(String args[]) {

        List<String> list = new ArrayList<>();
        list.add("cAcc");
        list.add("a;;;;a");
        list.add("aJA");
        list.add("vrrtrrr");
        list.add("cAccccccccc");

        OptionalInt minimalLenOfPalindrome
                = list.parallelStream()
                        .filter(SOFlow::isPalindrome)
                        .mapToInt(String::length)
                        .min();

        System.out.println(minimalLenOfPalindrome);
    }
}

答案 4 :(得分:0)

使用Java8流,并首先考虑排序,原因与其他原因相同:

boolean isPalindrome (String input) {
    StringBuilder sb = new StringBuilder(input.toLowerCase());
    return sb == sb.reverse();
}

public static int isShortestPalindrome(ArrayList<String> list) {
    return (list.stream().sorted ((s1, s2) -> { 
        return s1.length () - s2.length (); 
    })
    .filter (s-> isPalindrome (s))
    .findFirst ()
    .map (s -> s.length ())
    .orElse (-1));
}

如果你有很多相等,最小长度,非常长的弦乐,只有非中间的非回文,你可能会花费很多时间在isPalindrome上,喜欢isPalindrome1而不是isPalindrome。

如果我们假设一个长度均匀分布在1000到2000个字符之间的百万字符串,我们最终会集中注意力。 1000弦。如果它们中的大多数是相等的,除了几个字符,接近中间,那么微调这种比较可能是相关的。但是早期找到回文终止了我们的搜索,所以回文百分比对性能的影响也很大。

private static boolean isPalindrome1 (String s) {
    String input = s.toLowerCase (); 
    int len = input.length ();
    for (int i = 0, j = len -1; i < len/2 && j > len/2; ++i, --j)
        if (input.charAt(i) != input.charAt (j))
            return false;
    return true;
}

流排序和过滤的结果是一个选项,这是发出信号的好机会,没有找到任何内容。我坚持你的返回int的接口,如果没有找到,则返回-1,当然,调用者必须正确评估。