JAVA实现字符串反转(Reverse)的方法(没有最快,只有更快)

字符串反转在Java程序笔试面试中经常遇到,程序出了满足设计需要外,往往我们还要考虑到性能及内存相关的问题,如果考虑到性能和内存相关的问题,在笔试或面试中更容易赢得考官的青睐。

不多说,给出我这边实现的几种方案:

方案一:

    private static String reverse(String str) {
        if (str == null) {
            return null;
        }
        return new StringBuffer(str).reverse().toString();
    }

利用StringBuffer或StringBuilder自带reverse方法,简单!

方案二:

private static String reverse1(String str) {
        if (str == null) {
            return null;
        }
        String result = "";
        for (int i = str.length() - 1; i >= 0; i--) {
            result = result + str.charAt(i);
        }
        return result;
    }

利用String的charAt方法,逆序拼接。

方案三:

private static String reverse2(String str) {
        if (str == null) {
            return null;
        }
        String result = "";
        char[] chars = str.toCharArray();
        for (int i = chars.length - 1; i >= 0; i--) {
            result = result + chars[i];
        }
        return result;
    }

利用String的toCharArray方法,逆序拼接。

方案四:

private static String reverse3(String str) {
        if (str == null) {
            return null;
        }
        int stackSize = str.length();
        Stack theStack = new Stack();
        for (int i = 0; i < stackSize; i++) {
            theStack.push(str.charAt(i));
        }
        String result = "";
        while (!theStack.isEmpty()) {
            char ch = (char) theStack.pop();
            result = result + ch;
        }
        return result;
    }

利用栈,压栈出栈来逆序。

方案五:

    private static String reverse4(String str) {
        if (str == null) {
            return null;
        }
        char[] chars = str.toCharArray();
        int n = chars.length - 1;
        for (int i = 0; i <= chars.length / 2; i++) {
            char temp = chars[i];
            chars[i] = chars[n - i];
            chars[n - i] = temp;
        }
        return new String(chars);
    }

二分法逆序字符串数组。

以上方法是容易想到的,都可以实现字符串逆序的功能。我们可以测试下上述五种方法执行的效率。

import java.util.Random;
import java.util.Stack;

public class TestStringReverse {
    public static void main(String[] args) {
        // 实例一个长度为100000的字符串
        String test = "";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 100000; i++) {
            sb.append(random.nextInt(10));
        }
        test = sb.toString();

        // 方法1
        long start1 = System.nanoTime();
        String reverse1 = reverse1(test);
        System.out.println("reverse1 time = " + (System.nanoTime() - start1));
        // 方法2
        long start2 = System.nanoTime();
        String reverse2 = reverse2(test);
        System.out.println("reverse2 time = " + (System.nanoTime() - start2));
        // 方法3
        long start3 = System.nanoTime();
        String reverse3 = reverse3(test);
        System.out.println("reverse3 time = " + (System.nanoTime() - start3));
        // 方法4
        long start4 = System.nanoTime();
        String reverse4 = reverse4(test);
        System.out.println("reverse4 time = " + (System.nanoTime() - start4));
        // 方法5
        long start5 = System.nanoTime();
        String reverse5 = reverse5(test);
        System.out.println("reverse5 time = " + (System.nanoTime() - start5));

        System.out.println(test);

        System.out.println(reverse1);
        System.out.println(reverse2);
        System.out.println(reverse3);
        System.out.println(reverse4);
        System.out.println(reverse5);
    }

    private static String reverse1(String str) {
        if (str == null) {
            return null;
        }
        return new StringBuffer(str).reverse().toString();
    }

    private static String reverse2(String str) {
        if (str == null) {
            return null;
        }
        String result = "";
        for (int i = str.length() - 1; i >= 0; i--) {
            result = result + str.charAt(i);
        }
        return result;
    }

    private static String reverse3(String str) {
        if (str == null) {
            return null;
        }
        String result = "";
        char[] chars = str.toCharArray();
        for (int i = chars.length - 1; i >= 0; i--) {
            result = result + chars[i];
        }
        return result;
    }

    private static String reverse4(String str) {
        if (str == null) {
            return null;
        }
        int stackSize = str.length();
        Stack theStack = new Stack();
        for (int i = 0; i < stackSize; i++) {
            theStack.push(str.charAt(i));
        }
        String result = "";
        while (!theStack.isEmpty()) {
            char ch = (char) theStack.pop();
            result = result + ch;
        }
        return result;
    }

    private static String reverse5(String str) {
        if (str == null) {
            return null;
        }
        char[] chars = str.toCharArray();
        int n = chars.length - 1;
        for (int i = 0; i <= chars.length / 2; i++) {
            char temp = chars[i];
            chars[i] = chars[n - i];
            chars[n - i] = temp;
        }
        return new String(chars);
    }

}

运行结果:(方法一到五对应时间分别为reverse1到reverse5,方法执行时间使用纳秒计时单位)

reverse1 time = 3206954
reverse2 time = 5384374368
reverse3 time = 1996738321
reverse4 time = 1471417533
reverse5 time = 1476173

因为测试时间具有随机性,所以测试多组,五种方法耗时关系:reverse2>reverse3>reverse4>reverse1>reverse5.

简单分析下:

Java官方API解释:

The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method. String conversions are implemented through the method toString, defined by Object and inherited by all classes in Java. For additional information on string concatenation and conversion, see Gosling, Joy, and Steele, The Java Language Specification.

意思是:Java语言为字符串连接运算符(+)提供特殊支持,并为其他对象转换为字符串。 字符串连接是通过StringBuilder (或StringBuffer )类及其append方法实现的。 另外字串在拼接生成新字串的时候,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多低。

所以:reverse2注定比reverse1慢

方法三和方法四实现上其实也有字串的循环拼接,所以自然也比reverse1慢。

从方法三和方法四时间快慢看,charAt的效率比char数组取指定index的字符效率低,时间也是如此。

所以:reverse2>reverse3>reverse4>reverse1

方法五比方法1要快,这个可以从StringBuffer源码上分析:

    public AbstractStringBuilder reverse() {
        boolean hasSurrogates = false;
        int n = count - 1;
        for (int j = (n-1) >> 1; j >= 0; j--) {
            int k = n - j;
            char cj = value[j];
            char ck = value[k];
            value[j] = ck;
            value[k] = cj;
            if (Character.isSurrogate(cj) ||
                Character.isSurrogate(ck)) {
                hasSurrogates = true;
            }
        }
        if (hasSurrogates) {
            reverseAllValidSurrogatePairs();
        }
        return this;
    }

    /** Outlined helper method for reverse() */
    private void reverseAllValidSurrogatePairs() {
        for (int i = 0; i < count - 1; i++) {
            char c2 = value[i];
            if (Character.isLowSurrogate(c2)) {
                char c1 = value[i + 1];
                if (Character.isHighSurrogate(c1)) {
                    value[i++] = c1;
                    value[i] = c2;
                }
            }
        }
    }

可以看出,StringBuffer逆序也是基于char数组,循环次数(时间复杂度)比方法五要多。

从而reverse1>reverse5

所以:reverse2>reverse3>reverse4>reverse1>reverse5.

最后,关于字符串逆序方法应该还有其他方法,后续如发现比方法五还高效的方法会补充。

 

备注:

1.大家如有更高效方法,请留言补充;

2.方法暂时未考虑空间复杂度,一般来说高效的方法或多或少空间复杂度高,即所谓的空间换时间。

 

 

你可能感兴趣的:(Java)