JavaRush /Blog Java /Random-VI /Đảo ngược chuỗi trong Java: học cách đảo ngược chuỗi theo...

Đảo ngược chuỗi trong Java: học cách đảo ngược chuỗi theo nhiều cách khác nhau

Xuất bản trong nhóm
Có thể trở thành lập trình viên giỏi mà không cần biết thuật toán không? Rất, rất gây tranh cãi. Có, bạn có thể tìm được việc làm ở các công ty gia công phần mềm của chúng tôi, bởi vì trong các cuộc phỏng vấn, họ chủ yếu hỏi các câu hỏi về công nghệ. Đảo ngược chuỗi trong Java: học cách đảo ngược chuỗi theo nhiều cách khác nhau - 1Nhưng liệu bạn có trở thành một chuyên gia giỏi nếu các quyết định của bạn tràn ngập nạng? Nếu bạn muốn chuyển đến một công ty nước ngoài nghiêm túc hơn, bạn sẽ gặp phải những cuộc phỏng vấn chủ yếu tập trung vào thuật toán. Bằng cách này hay cách khác, việc áp dụng các thuật toán cơ bản nhất là điều đáng làm, bởi vì thuật toán là bạn của lập trình viên . Hôm nay chúng ta sẽ đề cập đến một trong những chủ đề này và thảo luận về cách đảo ngược một chuỗi. Mọi thứ đều đơn giản ở đây. Đảo ngược một chuỗi là đưa chuỗi ngược lại. Ví dụ: JavaRush mãi mãi ->reverof hsuRavaJ Vậy làm cách nào bạn có thể đảo ngược một chuỗi trong Java?

1. StringBuilder/StringBuffer

Cách phổ biến và đơn giản nhất là sử dụng StringBuilder/StringBuffer :
public static String reverseString(String str) {
  return new StringBuilder(str).reverse().toString();
}
Giải pháp tốt nhất = đơn giản nhất. Khi được hỏi cách đảo ngược một chuỗi trong Java, đây là điều đầu tiên bạn nên nghĩ đến. Nhưng chúng ta đã nói về thuật toán trước đó phải không? Chúng ta hãy xem xét các giải pháp vượt trội.

2. Giải pháp mảng

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;
}
Chúng tôi chuyển đổi chuỗi của mình thành một mảng bằng phương thức toCharArray . Hãy chạy vòng lặp for qua mảng này từ cuối mảng, thêm các ký tự vào chuỗi kết quả trong suốt quá trình.

3. Giải pháp với charAt

public static String reverseString(String str) {
  String result = "";
  for (int i = 0; i < str.length(); i++) {
     result = str.charAt(i) + result;
  }
  return result;
}
Trong trường hợp này, chúng ta thậm chí không phải chia chuỗi thành một mảng, vì chúng ta trích xuất từng ký tự bằng phương thức lớp String - charAt (vòng lặp for, một lần nữa, ngược lại, cho phép chúng ta lấy các ký tự theo tuần tự ngược).

4. Giải pháp với ngăn xếp

Lớp Stack đã không được sử dụng trong một thời gian dài và được coi là lỗi thời, tuy nhiên, để tham khảo, sẽ rất hữu ích khi xem xét giải pháp sử dụng nó:
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;
}
Ở đây một lần nữa chúng ta sử dụng toCharArray để chia chuỗi thành một mảng và đặt tất cả vào Stack của chúng ta với kiểu chung là Character . Tiếp theo, chúng ta bắt đầu lấy các phần tử từ đầu ngăn xếp. Do tính chất của ngăn xếp là cấu trúc LIFO - L ast I n F irst O ut (vào trước, ra sau) nên các phần tử sẽ được đưa ngược lại và kết quả sẽ được lưu ở hàng kết quả.

5. Giải bằng đệ quy

Hầu hết mọi vấn đề thuật toán đều có thể được giải quyết bằng đệ quy. Và ở đây chúng tôi cũng không thể làm gì nếu không có cô ấy. Hoặc thậm chí không có chúng. Rốt cuộc, hôm nay chúng ta sẽ xem xét không chỉ một phương pháp giải đệ quy mà còn nhiều phương pháp khác.
  • phương pháp một

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

    Chúng ta sử dụng các biến rightStrleftStr để chia chuỗi đến thành hai phần bằng nhau. Tiếp theo, sử dụng cách phân tách này, chúng ta chia chuỗi thành những phần chia nhỏ nhất (1 ký tự). Sau đó, đệ quy bắt đầu sụp đổ, trả về các ký tự theo thứ tự ngược lại (những ký tự bên phải được đặt ở bên trái; những ký tự ở bên trái được đặt ở bên phải)

    Chúng ta không được quên rằng mỗi lần đệ quy là một lệnh gọi nhiều phương thức và kết quả là tiêu tốn đáng kể nguồn lực. Chà, nếu chúng ta đang nói về đệ quy với điều kiện thoát không thể đạt được, thì đây là con đường dẫn đến vô cực và StackOverflowError.

  • phương pháp hai

    Ở đây chúng ta cần một đối số bổ sung trong phương thức - index.

    Khi phương thức này được chạy, nó có độ dài chuỗi là -1:

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

    Và chính phương pháp này:

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

    Chỉ mục của chúng tôi đóng vai trò là chỉ báo về phần tử hàng nào chúng tôi sẽ sử dụng bây giờ (và chúng tôi sẽ sử dụng các phần tử từ cuối).

    Do đó, chúng ta đặt điều kiện thoát khi chỉ mục đạt đến phần tử đầu tiên.

  • Chúng tôi thêm các giá trị thu được bằng cách sử dụng chỉ mục chữ cái với kết quả thực hiện phương thức trước đó và trả về kết quả.

  • phương pháp ba

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

    Phương pháp này về cơ bản là đơn giản nhất trong số các phương pháp đệ quy. Và như chúng ta nhớ, đơn giản = tốt nhất.

    Trong mỗi lần chạy, chúng tôi chỉ định cùng một chuỗi nhưng không có phần tử đầu tiên. Khi đạt đến điều kiện thoát (khi chúng ta còn một ký tự), đệ quy bắt đầu thu gọn và ký tự không được sử dụng trước đó sẽ được thêm vào mỗi kết quả tiếp theo.

6. Sử dụng XOR

XOR là một phép toán logic theo bit. Trong trường hợp có hai biến, kết quả của một phép toán là đúng khi và chỉ khi một trong các đối số là đúng và đối số kia là sai.
MỘT B Y
0 0 0
0 1 1
1 0 1
1 1 0
Bạn có thể đọc thêm về các phép toán bitwise trong bài viết này . Giải pháp tiếp theo sẽ dựa vào thực tế là:

(A XOR B) XOR B = A
(A XOR B) XOR A = B
Phương thức này sẽ trông như thế nào:
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;
}
Chúng ta hãy tìm hiểu những gì đang xảy ra ở đây. Chúng tôi tạo một mảng từ chuỗi đến. Chúng ta tạo hai biến lowhigh để lưu trữ các chỉ mục để duyệt mảng. Theo đó, một cái sẽ di chuyển từ đầu đến cuối - chúng tôi đặt cho nó giá trị 0, thứ hai - từ đầu đến đầu, chúng tôi đặt nó arr.length - 1 . Chúng ta vào một vòng lặp sẽ phát miễn là chỉ số cao lớn hơn chỉ số thấp . Đây là nơi những điều thú vị bắt đầu xảy ra - việc sử dụng OR độc quyền. Hãy xem xy làm ví dụ . Giả sử arr[high] = 'x'; Mã nhị phân của nó sẽ là 1 1 1 1 0 0 0 Lúc này arr[high] = 'n'; Mã nhị phân - 1 1 0 1 1 1 0 Những gì chúng ta sẽ có trong các phép toán XOR trong một vòng lặp:
  1. mảng[thấp] = (char) (arr[thấp] ^ mảng[cao]);

    
    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. mảng[cao] = (char) (arr[thấp] ^ mảng[cao]);

    
    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. mảng[thấp] = (char) (arr[thấp] ^ mảng[cao]);

    
    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
Kết quả là nhờ các thao tác này mà chúng ta đã hoán đổi giá trị của hai ô mảng. arr[high] có số phần tử ở cuối mảng bằng với số phần tử ở đầu mảng. Do đó, chúng tôi chỉ cần trao đổi các phần tử với các chỉ số này. Ví dụ: trong lần thực thi đầu tiên trong câu “JavaRush mãi mãi” Jr sẽ được hoán đổi cho nhau, ở lần thực thi thứ hai - ae , v.v. Nếu chúng ta có số ký tự lẻ thì khi chúng ta tiếp cận phần tử nằm trong ở giữa, chúng ta sẽ bị loại ra khỏi vòng lặp (tức là không cần thay đổi phần tử ở giữa). Nếu nó chẵn, chúng ta sẽ bị loại sau khi xử lý tất cả các phần tử. Chà, sau đó chúng ta đi vào một vòng lặp thông thường và xây dựng một chuỗi từ các phần tử mảng.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION