JavaRush /Java 博客 /Random-ZH /Java 中的反转字符串:学习以不同方式反转字符串

Java 中的反转字符串:学习以不同方式反转字符串

已在 Random-ZH 群组中发布
不懂算法就可以成为一名优秀的程序员吗?非常非常有争议。是的,你可以在我们的外包公司找到工作,因为面试时他们问的问题主要是技术方面的。 Java 中的反转字符串:学习以不同方式反转字符串 - 1但如果你的决定充满了拐杖,你会成为一名优秀的专家吗?如果你想跳槽到一家更认真的外企,你会遇到主要针对算法的面试。无论如何,采用最基本的算法是值得的,因为算法是程序员的朋友。今天我们将讨论其中一个主题并讨论反转字符串的方法。这里一切都很简单。反转字符串就是使字符串向后移动。例如: JavaRush Forever ->reverof hsuRavaJ 那么,如何在 Java 中反转字符串呢?

1. StringBuilder/StringBuffer

最常见和最简单的方法是使用StringBuilder/StringBuffer
public static String reverseString(String str) {
  return new StringBuilder(str).reverse().toString();
}
最好的解决方案=最简单的。当被问及如何在 Java 中反转字符串时,这是应该首先想到的。但我们之前讨论过算法,不是吗?让我们看一下非开箱即用的解决方案。

2. 数组解决方案

public static String reverseString(String str) {
  char[] array = str.toCharArray();
  String result = "";
  for (int i = array.length - 1; i >= 0; i--) {
     result = result + array[i];
  }
  return result;
}
我们使用toCharArray方法 将字符串转换为数组。让我们从数组的末尾开始运行for循环,将字符添加到结果字符串中。

3.用charAt解决

public static String reverseString(String str) {
  String result = "";
  for (int i = 0; i < str.length(); i++) {
     result = str.charAt(i) + result;
  }
  return result;
}
在这种情况下,我们甚至不必将字符串拆分为数组,因为我们使用String类方法charAt提取每个字符(for 循环又是相反的,这允许我们按顺序向后获取字符)

4. 堆栈解决方案

Stack类已经很长时间没有使用了,它被认为已经过时了,但是,作为参考,查看使用它的解决方案将会很有用:
public static String reverseString(String str) {
  Stack<Character> stack = new Stack<>();
  String result = "";
  for (Character character : str.toCharArray()) {
     stack.add(character);
  }
  while (!stack.isEmpty()) {
     result = result + stack.pop();
  }
  return result;
}
在这里,我们再次使用toCharArray将字符串拆分为数组,并将其全部放入具有泛型类型的Stack。接下来,我们开始从栈顶取出元素。由于堆栈的本质是LIFO结构-后进先出(先进后出),元素将向后取出,结果将存储在结果

5. 递归求解

几乎所有算法问题都可以使用递归来解决。而在这里我们也离不开她。或者甚至没有它们。毕竟,今天我们将考虑的不仅仅是一种解决递归的方法,而是几种。
  • 方法一

    public static String reverseString(String str) {
      String rightStr;
      String leftStr;
      int length = str.length();
    
      if (length <= 1) {
         return str;
      }
    
      leftStr = str.substring(0, length / 2);
      rightStr = str.substring(length / 2, length);
    
      return reverseString(rightStr) + reverseString(leftStr);
    }

    我们使用rightStrleftStr变量将传入的字符串分成两个相等的部分。接下来,使用此拆分,我们将字符串拆分为最小的可分割部分(1 个字符)。之后,递归开始崩溃,以相反的顺序返回字符(右边的放在左边;左边的放在右边)

    我们不能忘记,每次递归都是对一个方法的多次调用,因此会消耗相当大的资源。好吧,如果我们谈论的是具有无法达到的退出条件的递归,那么这就是通往无穷大和 StackOverflowError 的路径。

  • 方法二

    这里我们需要在方法中添加一个参数——index。

    当这个方法运行时,它的字符串长度被赋予-1:

    String str = "JavaRush forever";
    System.out.println(reverseString(str, str.length()-1));

    以及方法本身:

    public static String reverseString(String str, int index) {
      if(index == 0){
         return str.charAt(0) + "";
      }
    
      char letter = str.charAt(index);
      return letter + reverseString(str, index-1);
    }

    我们的索引充当我们现在将使用哪个行元素的指示器(我们将使用末尾的元素)。

    因此,我们在索引到达第一个元素时设置退出条件。

  • 我们将使用字母索引获得的值与先前执行该方法的结果相加并返回结果。

  • 方法三

    public static String reverseString(String str) {
      if (str.length() <= 1) {
         return str;
      }
      return reverseString(str.substring(1)) + str.charAt(0);
    }

    这种方法本质上是最简单的递归方法。我们记得,简单=最好。

    在每次运行期间,我们指定相同的字符串,但没有第一个元素。当达到退出条件时(当我们还剩下一个字符时),递归开始崩溃,并且前一个未使用的字符将被添加到每个后续结果中。

6. 使用异或

XOR是逻辑按位运算。在有两个变量的情况下,当且仅当参数之一为 true 而另一个为 false 时,运算结果为 true。
A
0 0 0
0 1 1
1 0 1
1 1 0
您可以在本文中阅读有关按位运算的更多信息。下一个解决方案将依赖于以下事实:

(A XOR B) XOR B = A
(A XOR B) XOR A = B
该方法将是什么样子:
public static String reverseString(String str) {
  char[] arr = str.toCharArray();
  int low = 0;
  int high = arr.length - 1;
  String result = "";
  while (low < high) {
     arr[low] = (char) (arr[low] ^ arr[high]);
     arr[high] = (char) (arr[low] ^ arr[high]);
     arr[low] = (char) (arr[low] ^ arr[high]);
     low++;
     high--;
  }
  for (int i = 0; i < arr.length; i++) {
     result = result + arr[i];
  }
  return result;
}
让我们弄清楚这里发生了什么。我们从传入的字符串创建一个数组。我们创建两个变量lowhigh,它们存储用于遍历数组的索引。因此,一个将从开始移动到结束 - 我们给它值 0,第二个 - 从结束到开始,我们将其设置为arr.length - 1。我们进入一个循环,只要索引high大于low ,该循环就会播放。这就是有趣的事情开始发生的地方——异或的使用。让我们以xy为例。假设arr[high] = 'x'; 其二进制码将为 1 1 1 1 0 0 0 此时arr[high] = 'n'; 二进制代码 - 1 1 0 1 1 1 0 我们将在循环中执行 XOR 运算:
  1. arr[低] = (char) (arr[低] ^ arr[高]);

    
    arr[low] = 1 1 0 1 1 1 0
    arr[high] =1 1 1 1 0 0 0
    arr[low] = 0 0 1 0 1 1 0
  2. arr[高] = (char) (arr[低] ^ arr[高]);

    
    arr[low] =  0 0 1 0 1 1 0
    arr[high] = 1 1 1 1 0 0 0
    arr[high] = 1 1 0 1 1 1 0
  3. arr[低] = (char) (arr[低] ^ arr[高]);

    
    arr[low] =  0 0 1 0 1 1 0
    arr[high] = 1 1 0 1 1 1 0
    arr[low] =  1 1 1 1 0 0 0
结果,通过这些操作,我们交换了两个数组单元格的值。 arr[high]是从数组末尾算起的元素数,而arr[low]是从数组开头算起的元素数。因此,我们只需将元素与这些索引交换即可。例如,在句子“JavaRush Forever”中的第一次执行时, Jr将被交换,第二次执行时 - ae等。如果我们有奇数个字符,那么当我们到达middle,我们将被抛出循环(即不需要更改中间元素)。如果是偶数,我们将在处理完所有元素后被抛出。好吧,之后我们进入常规循环并从数组元素构建一个字符串。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION