วิธีการ Reverse สตริงใน Java โดยใช้การเรียกซ้ำ

⚡ สรุปอย่างชาญฉลาด

Revการส่งสตริงใน Java การเรียกซ้ำทำงานโดยการตัดอักขระตัวแรกออก กลับด้านส่วนที่เหลือ และเพิ่มอักขระตัวแรกนั้นต่อท้าย สตริงว่างจะหยุดการเรียกและคลายสแต็ก

  • 🔘 กรณีฐาน: เมธอดนี้จะส่งคืนค่าทันทีเมื่อ isEmpty() รายงานว่าไม่มีอะไรเหลือให้ย้อนกลับแล้ว
  • ☑️ ขั้นตอนการเรียกซ้ำ: substring(1) จะลบอักขระตัวแรกออก และ charAt(0) จะใส่กลับเข้าไปหลังจากส่วนที่เหลือที่กลับด้านแล้ว
  • ไม่เปลี่ยนรูป: ทุกครั้งที่มีการเรียกใช้ จะสร้างอ็อบเจ็กต์ String ใหม่ เนื่องจาก Java ข้อความไม่สามารถแก้ไขได้โดยตรง
  • 🧪 Trace: Guru99 จะกลายเป็น 99uruG หลังจากเรียกฟังก์ชันเจ็ดครั้ง โดยแต่ละครั้งแทนอักขระแต่ละตัว บวกกับกรณีฐานที่ว่างเปล่า
  • 🛠️ ตัวเลือกที่เร็วกว่า: การเรียกใช้ StringBuilder.reverse() และการสลับตัวชี้สองตัวไปยัง toCharArray() เสร็จสิ้นในรอบเดียว
  • 📌 ค่าใช้จ่าย: การเรียกซ้ำด้วย substring() ใช้เวลาในการทำงานแบบกำลังสอง และใช้เฟรมสแต็กหนึ่งเฟรมต่ออักขระหนึ่งตัว

Java โปรแกรมที่กลับลำดับสตริงโดยใช้วิธีเรียกซ้ำ

ในโปรแกรมตัวอย่างนี้ เราจะย้อนกลับสตริงที่ผู้ใช้ป้อน

เราจะสร้างฟังก์ชันเพื่อย้อนกลับสตริง Later เราจะเรียกฟังก์ชันนี้ซ้ำไปเรื่อยๆ จนกว่าตัวอักษรทั้งหมดจะกลับด้าน การเรียกซ้ำเหมาะสมกับปัญหานี้ เพราะสตริงที่กลับด้านแล้วก็คือส่วนท้ายของสตริงเดิมที่ถูกกลับด้าน โดยมีตัวอักษรตัวแรกของสตริงเดิมติดอยู่ที่ท้าย ซึ่งก็คือปัญหาเดียวกันแต่ลดจำนวนตัวอักษรลงหนึ่งตัว

เขียนถึง Java โปรแกรมไป Reverse เชือก

คลาสข้างล่างนี้ประกาศตัวแปรอินพุตในเมธอด main() ส่งต่อไปยังเมธอด reverseString() และพิมพ์สิ่งที่ได้กลับมา การเรียกใช้ println() สองครั้งภายในเมธอดทำให้แต่ละขั้นตอนของการเรียกซ้ำปรากฏให้เห็นในคอนโซล

package com.guru99;
 
public class ReverseString {
 
	public static void main(String[] args) {
 
 
		String myStr = "Guru99";
 
 
		//create Method and pass and input parameter string 
		String reversed = reverseString(myStr);
		System.out.println("The reversed string is: " + reversed);
		
	}
 
 
	//Method take string parameter and check string is empty or not
	public static String reverseString(String myStr)
	{
		if (myStr.isEmpty()){
		 System.out.println("String in now Empty");	
		 return myStr;
		}
		//Calling Function Recursively
		System.out.println("String to be passed in Recursive Function: "+myStr.substring(1));
		return reverseString(myStr.substring(1)) + myStr.charAt(0);
	}
 
}

Code Output:

แต่ละบรรทัดของผลลัพธ์คือการเรียกซ้ำหนึ่งครั้ง ตัวอักษรส่วนท้ายที่พิมพ์ในแต่ละบรรทัดจะสั้นกว่าบรรทัดด้านบนหนึ่งตัว และบรรทัดสุดท้ายจะแสดงผลลัพธ์ที่กลับด้าน

String to be passed in Recursive Function: uru99
String to be passed in Recursive Function: ru99
String to be passed in Recursive Function: u99
String to be passed in Recursive Function: 99
String to be passed in Recursive Function: 9
String to be passed in Recursive Function: 
String in now Empty
The reversed string is: 99uruG

วิธีการใช้การเรียกซ้ำ Reversal ทำงานทีละขั้นตอน

เมธอดทั้งหมดถูกประมวลผลด้วยโค้ดเพียงสองบรรทัด กรณีพื้นฐาน if (myStr.isEmpty()) จะทำให้การเรียกซ้ำหยุดลงที่จุดใดจุดหนึ่ง บรรทัดที่เรียกซ้ำ return reverseString(myStr.substring(1)) + myStr.charAt(0) จะแบ่งการทำงานออกเป็นสองส่วน: substring(1) คือทุกอย่างหลังจากอักขระตัวแรก และ charAt(0) คืออักขระตัวแรกที่ต่อท้าย หลังจาก เศษเหลือที่กลับด้าน

Tracการป้อนข้อมูล Guru99 ทำให้ลำดับชัดเจนขึ้น Java ส่งเฟรมหนึ่งเฟรมต่อการเรียกแต่ละครั้งก่อนที่จะมีการรวมเฟรมเกิดขึ้น:

โทรมายสตรโอนสายไปยังสายถัดไปนิพจน์ที่รอการเสร็จสิ้น
1Guru99uru99reverseString(“uru99”) + G
2uru99ru99reverseString(“ru99”) + u
3ru99u99reverseString(“u99”) + r
4u9999reverseString(“99”) + u
5999reverseString(“9”) + 9
69(ว่าง)reverseString(“”) + 9
7(ว่าง)กรณีพื้นฐานบรรลุแล้วส่งคืนสตริงว่าง

จากนั้นสแต็กจะคลายตัวจากล่างขึ้นบน และแต่ละเฟรมจะเพิ่มอักขระที่บันทึกไว้เข้าไป: สตริงว่างจะกลายเป็น 9 จากนั้น 99 จากนั้น 99u, 99ur, 99uru และสุดท้าย 99uruG. เพราะ Java สตริงไม่สามารถเปลี่ยนแปลงได้ ค่ากลางเหล่านี้จะไม่เขียนทับค่าก่อนหน้า การเชื่อมต่อแต่ละครั้งจะสร้างอ็อบเจ็กต์ String ใหม่ขึ้นมา

มีรายละเอียดสองอย่างในเอาต์พุตคอนโซลที่ควรกล่าวถึง บรรทัดที่หกจบลงโดยไม่มีอะไรอยู่หลังเครื่องหมายโคลอน เนื่องจาก substring(1) บนสตริงที่มีอักขระเดียวจะคืนค่าสตริงว่างแทนที่จะเป็นค่า null ข้อความที่ตามมาอ่านว่า “String in now Empty” ในโปรแกรมต้นฉบับ ซึ่งเป็นคำที่พิมพ์ผิด ควรจะเป็น “String is now empty” และไม่ได้แก้ไข เพื่อให้โค้ดและเอาต์พุตด้านบนยังคงตรงกันทุกบรรทัด

วิธีอื่นๆ Reverse สตริงใน Java

การเรียกซ้ำเป็นวิธีที่ชัดเจนที่สุดในการ เห็น การกลับทิศทางเกิดขึ้นได้ แต่แทบจะไม่เกิดขึ้นในรูปแบบที่โค้ดใช้งานจริงทำกัน มีสามทางเลือกที่ครอบคลุมเกือบทุกกรณีในโลกแห่งความเป็นจริง

1. StringBuilder.reverse() เป็นวิธีที่สั้นที่สุดและเร็วที่สุด คลาสนี้มีเมธอด reverse() ในตัว ดังนั้นงานทั้งหมดจึงสามารถทำได้ในบรรทัดเดียว:

String reversed = new StringBuilder(myStr).reverse().toString();

2. ลูป for ที่ใช้ charAt() โค้ดนี้จะไล่ดูสตริงย้อนหลังตั้งแต่ดัชนีสุดท้ายไปจนถึงศูนย์ ผู้สัมภาษณ์มักขอโค้ดเวอร์ชันนี้ เพราะมันแสดงให้เห็นถึงตรรกะ แทนที่จะเป็นการมอบหมายงานให้ผู้อื่นทำ:

String reversed = "";
for (int i = myStr.length() - 1; i >= 0; i--) {
    reversed = reversed + myStr.charAt(i);
}

3. การสลับตัวชี้สองตัวไปยัง toCharArray() แปลงสตริงเป็นอาร์เรย์อักขระ จากนั้นสลับอักขระด้านนอกสุดเข้ามาด้านในจนกระทั่งตัวชี้มาบรรจบกันตรงกลาง:

char[] chars = myStr.toCharArray();
int left = 0;
int right = chars.length - 1;
while (left < right) {
    char temp = chars[left];
    chars[left] = chars[right];
    chars[right] = temp;
    left++;
    right--;
}
String reversed = new String(chars);

เทคนิคการจัดเรียงแบบเดียวกันนี้สามารถกลับลำดับตัวเลขหรือชุดข้อมูลที่เรียงลำดับอื่นๆ ได้ ซึ่งเป็นเหตุผลว่าทำไมจึงปรากฏอยู่ใน... Java แถว แบบฝึกหัดเหล่านี้ทำบ่อยพอๆ กับแบบฝึกหัดที่ใช้เครื่องสาย

ความซับซ้อนด้านเวลาและพื้นที่ของแต่ละแนวทาง

ทั้งสี่เวอร์ชันมีต้นทุนไม่เท่ากัน สูตรกำลังสองทั้งสองสูตรด้านล่างมีสาเหตุร่วมกันอย่างหนึ่งคือ มันสร้างสตริงใหม่เอี่ยมในทุกขั้นตอน และการคัดลอกอักขระ n ตัว n ครั้งนั้นเท่ากับงาน n กำลังสอง

เข้าใกล้เวลาพื้นที่พิเศษทำไม
การเรียกซ้ำด้วย substring()โอ(n²)โอ(n²)ฟังก์ชัน substring() จะคัดลอกอักขระที่เหลือในทุกครั้งที่เรียกใช้ และจะเก็บเฟรมสแต็กหนึ่งเฟรมต่ออักขระหนึ่งตัว
ลูป for ที่มี charAt() และ +โอ(n²)โอ(n²)การเชื่อมต่อแต่ละครั้งจะสร้างสตริงใหม่และคัดลอกทุกสิ่งที่รวบรวมไว้จนถึงขณะนั้น
StringBuilder.reverse()O (n)O (n)บัฟเฟอร์ที่เปลี่ยนแปลงได้หนึ่งตัว การประมวลผลหนึ่งรอบ และคู่ตัวแทนจะยังคงอยู่เหมือนเดิม
ตัวชี้สองตัวไปยัง toCharArray()O (n)O (n)คัดลอกอาร์เรย์หนึ่งครั้ง จากนั้นสลับ n/2 ครั้งโดยไม่มีการจัดสรรเพิ่มเติม

เลือกใช้เวอร์ชันแบบเรียกซ้ำเพื่อเรียนรู้หรือสาธิตวิธีการทำงานของสแต็กการเรียก เลือกใช้เวอร์ชันอาร์เรย์อักขระเมื่อผู้สัมภาษณ์ขอให้แสดงตรรกะด้วยตนเอง และใช้ StringBuilder.reverse() ในทุกสิ่งที่นำไปใช้งานจริง การแลกเปลี่ยนระหว่างวิธีแก้ปัญหาเพื่อการสอนและวิธีแก้ปัญหาเพื่อการใช้งานจริงนั้นปรากฏให้เห็นในแบบฝึกหัดคลาสสิกต่างๆ ตั้งแต่ เรียงฟอง และ ชุดฟีโบนักชี ไปยัง การตรวจสอบจำนวนเฉพาะแต่ละอย่างล้วนคุ้มค่าแก่การฝึกฝน Java ทั้งสองทาง

คำถามที่พบบ่อย

อ็อบเจ็กต์สตริงไม่สามารถเปลี่ยนแปลงได้ ดังนั้นอักขระภายในจึงไม่สามารถเปลี่ยนแปลงได้หลังจากสร้างขึ้นแล้ว การแปลงกลับแต่ละครั้งจึงสร้างอ็อบเจ็กต์ใหม่ขึ้นมา ควรใช้ StringBuilder หรืออาร์เรย์อักขระเมื่อจำเป็นต้องแก้ไขอักขระโดยไม่ต้องสร้างสตริงใหม่ในแต่ละขั้นตอน

การเรียกใช้ isEmpty() ครั้งแรกจะทำให้เกิด NullPointerException เนื่องจากเมธอดนี้ถูกเรียกใช้กับค่าว่างเปล่า จึงควรตรวจสอบค่าว่างก่อนเริ่มการเรียกซ้ำ โดยการตรวจสอบค่าว่างจะส่งคืนค่าว่างหรือทำให้เกิด IllegalArgumentException

ไม่น่าเชื่อถือ charAt() ทำงานกับหน่วยรหัส 16 บิต ดังนั้นอักขระที่จัดเก็บเป็นคู่ตัวแทนจะถูกแยกออก และข้อความที่กลับด้านจะแสดงช่องสี่เหลี่ยมที่ใช้แทนที่ StringBuilder.reverse() จะเก็บคู่ตัวแทนไว้ด้วยกัน ทำให้เป็นตัวเลือกที่ปลอดภัยกว่าสำหรับข้อความ Unicode

StringBuilder ในเกือบทุกกรณี ทั้งสองแบบมีเมธอด reverse() เหมือนกัน แต่ StringBuffer การเรียกใช้ฟังก์ชันนี้จะซิงโครไนซ์ทุกครั้ง ซึ่งทำให้ความเร็วลดลง เลือกสตริงBuffer เฉพาะในกรณีที่บัฟเฟอร์หนึ่งถูกแชร์ระหว่างเธรดอย่างแท้จริงเท่านั้น

แยกประโยคตามช่องว่างด้วยฟังก์ชัน `split(" ")` จากนั้นวนลูปผ่านอาร์เรย์ที่ได้โดยเริ่มจากดัชนีสุดท้ายไปยังดัชนีแรก แล้วเพิ่มแต่ละคำลงใน `StringBuilder` ตัวอักษรภายในแต่ละคำจะยังคงอยู่ในลำดับเดิม

มีการใช้เฟรมสแต็กหนึ่งเฟรมต่ออักขระหนึ่งตัว ดังนั้นโดยทั่วไปแล้วจะสามารถรับอักขระได้หลายพันตัวก่อนที่จะเกิดข้อผิดพลาด StackOverflowError ขีดจำกัดที่แน่นอนขึ้นอยู่กับขนาดของสแต็กเธรด JVM เวอร์ชันแบบวนซ้ำใดๆ ก็ตามจะหลีกเลี่ยงขีดจำกัดสูงสุดนี้ได้อย่างสมบูรณ์

ผู้ช่วย AI สามารถอ่านสแต็กได้ tracเช่น ชี้ให้เห็นกรณีพื้นฐานที่ขาดหายไปหรือไม่สามารถเข้าถึงได้ และอธิบายลำดับการคลี่คลายของเฟรม นอกจากนี้ยังร่างการทดสอบกรณีพิเศษสำหรับการป้อนข้อมูลว่างเปล่า อักขระตัวเดียว และค่าว่าง ตรวจสอบเหตุผลกับข้อมูลจริง

ใช่. Copilot โดยปกติแล้วจะสร้างเมธอดแบบย้อนกลับทั้งหมดจากลายเซ็นเพียงอย่างเดียว โดยมักจะนำเสนอรูปแบบ StringBuilder ก่อน ตรวจสอบกรณีพื้นฐานและความซับซ้อน เพราะคำแนะนำที่สั้นที่สุดอาจไม่ใช่เวอร์ชันที่แบบฝึกหัดต้องการเสมอไป

สรุปโพสต์นี้ด้วย: