zoukankan      html  css  js  c++  java
  • 反转字符串

    去哪儿面试的最后一道题,开始我写了全数遍历的实现代码,然后面试官要求使用递归来实现,但是我一个算法战五渣早就忘记递归是个什么鬼了,然后面试就GG了。
    对于这道题目的解答方法有多种,先把它们全部列出来吧:

    • 全数遍历;
    • 半数遍历;
    • 递归实现;
    • 使用栈来实现;

    全数遍历(我的答案)

    刚开始,我写的是最近的从尾到头的遍历的形式:

    public class StringReverseExample {
    
        public static void main(String[] args) {
            String str = "abcdefg";
            StringBuilder sb = new StringBuilder(str.length());
            for (int i = str.length() - 1; i >= 0; i--) {
                sb.append(str.charAt(i));
            }
            System.out.println(sb.toString());
        }
    }
    

    这个毫无技术含量,当过一天程序员的人应该都是可以写出来的。。。然后面试官就说用递归写一下吧,然后我思考了三分钟之后就交白卷投降了。。。那么,用递归究竟怎么实现呢?以下内容来自网络,我只是做了下个人整理。

    递归实现

    递归的思想就是把反转长度为 n 的字符串 str 的任务划分为反转长度为 n - 1 的字符串 subStr1(其中 subStr1 = str.substring(1);),然后再加上有 str 第一个字符构成的字符串 subStr2(即 subStr2 = str.charAt(0);),具体实现如下:

    public class StringReverseRecursive {
    
        public static void main(String[] args) {
            String str = "abcdefg";
            String reverseStr = recursiveReverse(str);
            System.out.println(reverseStr);
        }
    
        public static String recursiveReverse(String str) {
            if (str.length() <= 1) {
                return str;
            }
            return recursiveReverse(str.substring(1)) + str.charAt(0);
        }
    }
    

    那么,使用递归这种算法究竟有什么好处呢?这个问题我还尚未想到,网上搜索的话,基本上都是说算法的实现,然而并没有进行时间复杂度以及空间复杂度的分析。我个人也没想出递归算法跟上面的从尾到头遍历相比有啥好处。。。

    半数遍历

    半数遍历-JDK类库的实现

    JDK 类库里面 StringBuilder 类有一个 reverse 方法,里面有反转的实现,其实也就是类似于半数遍历而已,下面直接贴代码:

    public class StringReverseByInBuild {
    
        public static void main(String[] args) {
            String str = "abcdefg";
            StringBuilder sb = new StringBuilder(str);
            sb.reverse();
            String destStr = sb.toString();
            System.out.println(destStr);
        }
    }
    

    然后是 StringBuilder.reverse 的内部实现:

    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;
        }
    

    半数遍历-直白的实现

    这种遍历算法也是容易理解,下面直接贴实现代码:

    public class StringHalfTraverseReverseExample {
    
        public static void main(String[] args) {
            String str = "abcdefgh";
            char[] chars = new char[str.length()];
            for (int i = 0; i < Math.ceil(str.length() / 2f); i++) {
                chars[i] = str.charAt(str.length() -1 - i);
                chars[str.length() - 1 - i] = str.charAt(i);
            }
            String destStr = new String(chars);
            System.out.println(destStr);
        }
    }
    

    半数遍历-使用异或

    这种方法就真的是涨姿势了,数学没学好玩算法就是蛋疼啊,没办法只能以后多补补了。下面先说说异或的基本性质:

    1. 交换律:A^B = B^A
    2. 结合律:A^(B^C) = (A^B)^C
    3. 恒等率:A^0 = A
    4. 归零率:A^A = 0
    5. 自反:A^B^B = A^0 = A
    

    然后是代码实现:

    public class StringReverseByXor {
    
        public static void main(String[] args) {
            String str = "abcdefgh";
            char[] chars = str.toCharArray();
            int halfCeil =  (int) Math.floor(str.length() / 2f);
            for (int i = 0, j = str.length() - 1; i < halfCeil; i++, j--) {
                chars[i] ^= chars[j];
                chars[j] ^= chars[i];
                chars[i] ^= chars[j];
            }
            String destStr = new String(chars);
            System.out.println(destStr);
        }
    }
    

    半数遍历-使用指针

    Java 里面并没有指针,不过使用指针的思路就是:进行半数遍历,然后交换对称位置上的值,当然了交换过程需要一个临时变量,在 Java 中不用指针的实现大概如下:

    public class StringReverseByExchange {
    
        public static void main(String[] args) {
            String str = "abcdefg";
            char[] chars = str.toCharArray();
            for (int i = 0; i < Math.ceil(chars.length / 2f); i++) {
                char temp = chars[i];
                chars[i] = chars[chars.length - 1 - i];
                chars[chars.length - 1 - i] = temp;
            }
            String destStr = new String(chars);
            System.out.println(destStr);
        }
    }
    

    使用栈

    栈这种数据接口有先进后出的特性,所以可以用它来轻松的实现字符串的反转,不过这么使用栈真的好吗?只是徒增了空间复杂度和时间复杂度吧!

    public class StringReverseByStack {
    
        public static void main(String[] args) {
            String str = "abcdefg";
            Stack<Character> stack = new Stack<>();
            for (int i = 0; i < str.length(); i++) {
                stack.push(str.charAt(i));
            }
            char[] chars = new char[str.length()];
            for (int i = 0; i < str.length(); i++) {
                chars[i] = stack.pop();
            }
            String destStr = new String(chars);
            System.out.println(destStr);
        }
    }
    

    参考

    1. http://blog.sina.com.cn/s/blog_6997f0150100tpse.html
    2. https://www.cnblogs.com/JohnTsai/p/5606719.html
  • 相关阅读:
    Node 修改默认镜像源
    Mac下apache虚拟主机配置
    Grep命令出现 Binary file (standard input) matches
    idea取出方法参数提示
    Java8 Optional用法
    Codeforces Round #638 (Div. 2)
    Codeforces Round #637 (Div. 2)
    Codeforces Round #636 (Div. 3)
    Tree
    Educational Codeforces Round 85
  • 原文地址:https://www.cnblogs.com/optor/p/8758816.html
Copyright © 2011-2022 走看看