JavaRush /Blog Java /Random-VI /Chuỗi Java. Câu hỏi và đáp án phỏng vấn phần 2
Andrey
Mức độ

Chuỗi Java. Câu hỏi và đáp án phỏng vấn phần 2

Xuất bản trong nhóm
Thật không may, bài viết không vừa một đoạn, tôi phải chia nó thành hai phần. Xem phần đầu ở đây Chuỗi Java.  Câu hỏi và đáp án phỏng vấn phần 2 - 1

12. Viết hàm tìm palindrome dài nhất trong một chuỗi cho trước

Một chuỗi có thể chứa các chuỗi palindrome và việc tìm ra chuỗi palindrome dài nhất là một vấn đề của lập trình. Điểm mấu chốt ở đây là từ giữa bất kỳ palindrome nào, nếu chúng ta sang phải và sang trái 1 ký tự thì nó sẽ luôn là cùng một ký tự. Ví dụ: 12321, ở giữa là 3 và nếu tiếp tục di chuyển từ vị trí hiện tại theo cả hai hướng, chúng ta sẽ nhận được 2 và sau đó là 1. Chúng tôi sử dụng logic tương tự trong chương trình Java của mình để tìm bảng màu dài nhất. Tuy nhiên, nếu độ dài của palindrome là chẵn thì độ dài của phần giữa cũng chẵn, vì vậy chúng ta cần đảm bảo rằng điều này cũng được cung cấp trong chương trình của chúng ta, ví dụ: 12333321, phần giữa là 33 và nếu chúng ta tiếp tục di chuyển theo cả hai hướng, chúng ta sẽ nhận được 3, 2 và 1. Trong chương trình của chúng ta, chúng ta duyệt qua chuỗi kết quả có phần giữa ở vị trí đầu tiên và kiểm tra các ký tự bên trái và bên phải. Chúng ta cũng có hai biến toàn cục để lưu trữ vị trí ban đầu của bảng màu. Chúng ta cũng cần kiểm tra xem đã tìm thấy một palindrome dài hơn hay chưa, vì chúng ta có thể tìm thấy nhiều palindrome trong một chuỗi nhất định. Dưới đây là một chương trình ví dụ hoạt động tốt trong mọi trường hợp. Chúng ta có thể cải thiện đoạn mã trên bằng cách chuyển vòng lặp while sang một phương thức riêng biệt, nhưng tôi sẽ để phần đó cho bạn. Vui lòng cho tôi biết nếu bạn có cách triển khai tốt hơn hoặc nếu chương trình bị lỗi theo cách nào đó.
package com.journaldev.util;

public class LongestPalindromeFinder {

    public static void main(String[] args) {
        System.out.println(longestPalindromeString("1234"));
        System.out.println(longestPalindromeString("12321"));
        System.out.println(longestPalindromeString("9912321456"));
        System.out.println(longestPalindromeString("9912333321456"));
        System.out.println(longestPalindromeString("12145445499"));
    }

    public static String longestPalindromeString(String in) {
        char[] input = in.toCharArray();
        int longestPalindromeStart = 0;
        int longestPalindromeEnd = 0;

        for (int mid = 0; mid < input.length; mid++) {
            // для случая нечетного палиндрома How 12321, 3 будет серединой
            int left = mid-1;
            int right = mid+1;
            // нам необходимо двигаться влево и вправо на 1 позицию до конца
            while (left >= 0 && right < input.length) {
                // ниже проверка, является ли это палиндромом
                if (input[left] == input[right]) {
                    // обновление глобальных позиций, только если палиндром длиннее имеющегося
                    if (right - left > longestPalindromeEnd
                            - longestPalindromeStart) {
                        longestPalindromeStart = left;
                        longestPalindromeEnd = right;
                    }
                }
                left--;
                right++;
            }
            // для четного палиндрома у нас должна быть подобная логика с размером середины 2
            // для этого мы начнем на одну позицию правее
            left = mid-1;
            right = mid + 2;// к примеру, для 12333321 мы выбрали 33 в качестве середины
            while (left >= 0 && right < input.length)
            {
                if (input[left] == input[right]) {
                    if (right - left > longestPalindromeEnd
                            - longestPalindromeStart) {
                        longestPalindromeStart = left;
                        longestPalindromeEnd = right;
                    }
                }
                left--;
                right++;
            }
        }
        // теперь у нас есть позиции для самого длинного палиндрома
        return in.substring(longestPalindromeStart, longestPalindromeEnd + 1);
    }
}
Chương trình sẽ xuất ra kết quả như sau:
1
12321
12321
12333321
454454

13. Sự khác biệt giữa String, StringBuffer và StringBuilder

Một chuỗi là bất biến và được hoàn thiện trong Java, vì vậy tất cả các thao tác với chuỗi của chúng ta sẽ luôn tạo ra một chuỗi mới. Thao tác chuỗi tốn nhiều tài nguyên, vì vậy Java cung cấp hai lớp hữu ích để thao tác chuỗi - StringBufferStringBuilder. StringBufferStringBuilderlà các lớp có thể thay đổi. Các hoạt động với StringBufferluồng là an toàn và được đồng bộ hóa, nhưng các phương thức StringBuilderkhông an toàn cho luồng. Vì vậy, khi nhiều luồng làm việc trên cùng một chuỗi, chúng ta nên sử dụng StringBuffer, nhưng trong môi trường một luồng, chúng ta nên sử dụng StringBuilder. StringBuilderhiệu quả hơn StringBuffervì nó không phải chịu gánh nặng đồng bộ hóa.

14. Tại sao chuỗi là bất biến và được hoàn thiện trong Java?

Có một số lợi thế đối với tính bất biến của chuỗi:
  1. Việc gộp chuỗi chỉ có thể thực hiện được vì chuỗi là bất biến trong Java, do đó, máy ảo tiết kiệm rất nhiều dung lượng vùng lưu trữ khi các biến chuỗi khác nhau trỏ đến cùng một biến trong nhóm. Nếu một chuỗi không phải là bất biến thì việc thực hiện chuỗi sẽ không thể thực hiện được vì nếu bất kỳ biến nào thay đổi giá trị của nó thì các biến khác tham chiếu đến chuỗi đó cũng sẽ bị ảnh hưởng.

  2. Nếu chuỗi có thể thay đổi thì nó sẽ trở thành một rủi ro bảo mật nghiêm trọng cho ứng dụng. Ví dụ: tên người dùng và mật khẩu cơ sở dữ liệu được truyền dưới dạng chuỗi để có được kết nối đến cơ sở dữ liệu và trong lập trình socket, chi tiết máy chủ và cổng được truyền dưới dạng chuỗi. Vì chuỗi là bất biến nên giá trị của nó không thể thay đổi, nếu không, bất kỳ hacker nào cũng có thể thay đổi giá trị của liên kết và gây ra sự cố về bảo mật của ứng dụng.

  3. Vì chuỗi là bất biến nên nó an toàn cho luồng và một phiên bản của chuỗi có thể được chia sẻ giữa các luồng khác nhau. Điều này tránh việc đồng bộ hóa để đảm bảo an toàn cho luồng, các chuỗi hoàn toàn an toàn cho luồng.

  4. Các chuỗi được sử dụng trong Java classloadervà tính bất biến đảm bảo rằng lớp được tải chính xác bằng cách sử dụng Classloader. Ví dụ: hãy nghĩ về một thể hiện của lớp khi bạn đang cố tải java.sql.Connectionmột lớp nhưng giá trị tham chiếu được thay đổi thành myhacked.Connectionmột lớp có thể thực hiện những điều không mong muốn đối với cơ sở dữ liệu của bạn.

  5. Vì chuỗi là bất biến nên nó hashcodeđược lưu vào bộ đệm tại thời điểm tạo và không cần phải tính toán lại. Điều này làm cho chuỗi trở thành một ứng cử viên xuất sắc cho khóa trong Mapvà quá trình xử lý chuỗi sẽ nhanh hơn các khóa khác HashMap. Đây là lý do tại sao chuỗi là đối tượng được sử dụng phổ biến nhất làm khóa HashMap.

15. Làm thế nào để chia một chuỗi thành nhiều phần?

Chúng ta có thể sử dụng một phương thức split(String regex)để chia một chuỗi thành một mảng các chuỗi bằng cách sử dụng biểu thức chính quy làm dấu phân cách.
import java.util.Arrays;

public class JavaSplitString {
    public static void main(String[] args) {
        String line = "I am a java developer";
        String[] words = line.split(" ");
        String[] twoWords = line.split(" ", 2);
        System.out.println("String split with delimiter: "+Arrays.toString(words));
        System.out.println("String split into two: "+Arrays.toString(twoWords));
        //split string delimited with special characters
        String wordsWithNumbers = "I|am|a|java|developer";
        String[] numbers = wordsWithNumbers.split("\\|");
        System.out.println("String split with special character: "+Arrays.toString(numbers));
    }
}
Phương thức này split(String regex, int numOfStrings)là một phương thức nạp chồng để chia một chuỗi thành một số dòng được chỉ định. Chúng ta có thể sử dụng dấu gạch chéo ngược để sử dụng các ký tự đặc biệt của biểu thức chính quy làm ký tự thông thường. Chương trình sẽ xuất ra kết quả như sau:
String split with delimiter: [I, am, a, java, developer]
String split into two: [I, am a java developer]
String split with special character: [I, am, a, java, developer]

16. Tại sao mảng chuỗi lại thích hợp hơn chuỗi để lưu trữ mật khẩu?

Một chuỗi là bất biến trong Java và được lưu trữ trong một nhóm chuỗi. Sau khi được tạo, nó vẫn ở trong nhóm cho đến khi được thu gom rác, vì vậy khi chúng tôi nghĩ rằng mình đã sử dụng xong mật khẩu, nó vẫn có sẵn trong bộ nhớ một thời gian và không có cách nào để tránh điều này. Đây là một rủi ro bảo mật vì bất kỳ ai có quyền truy cập vào kết xuất bộ nhớ đều có thể tìm thấy mật khẩu ở dạng văn bản rõ ràng. Nếu chúng ta sử dụng một mảng ký tự để lưu trữ mật khẩu, chúng ta có thể xóa nó sau khi thực hiện xong. Bằng cách này, chúng ta có thể kiểm soát thời gian nó tồn tại trong bộ nhớ, tránh các rủi ro bảo mật vốn có trong một chuỗi.

17. Làm cách nào để kiểm tra sự giống nhau của hai chuỗi trong Java?

Có hai cách để kiểm tra xem hai chuỗi có tương đương nhau hay không - sử dụng ==toán tử “ ” hoặc sử dụng toán tử equals. Khi chúng ta sử dụng toán tử “ ==”, nó sẽ kiểm tra giá trị của chuỗi làm tham chiếu, nhưng trong phần lớn thời gian lập trình, chúng ta chỉ kiểm tra tính tương đương của chuỗi đối với giá trị. Vì vậy, chúng ta phải sử dụng phương thức bằng để kiểm tra sự bằng nhau của hai chuỗi. Ngoài ra còn có một phương pháp equalsIgnoreCasechúng ta có thể sử dụng để bỏ qua trường hợp.
String s1 = "abc";
String s2 = "abc";
String s3= new String("abc");
System.out.println("s1 == s2 ? "+(s1==s2)); //true
System.out.println("s1 == s3 ? "+(s1==s3)); //false
System.out.println("s1 equals s3 ? "+(s1.equals(s3))); //true

18. Pool chuỗi là gì?

Như tên cho thấy, nhóm chuỗi là tập hợp các chuỗi được lưu trữ trong vùng heap Java. Chúng ta biết rằng Stringđây là một lớp đặc biệt trong Java và chúng ta có thể tạo các đối tượng của lớp này bằng cách sử dụng toán tử mới giống như chúng ta có thể tạo các đối tượng bằng cách cung cấp giá trị của một chuỗi trong dấu ngoặc kép. Sơ đồ bên dưới giải thích cách phân bổ nhóm chuỗi trong vùng heap Java và điều gì xảy ra khi chúng ta sử dụng các cách khác nhau để tạo chuỗi. Chuỗi Java.  Câu hỏi và đáp án phỏng vấn phần 2 - 2Việc gộp chuỗi chỉ có thể thực hiện được nhờ tính bất biến của chuỗi trong Java và việc triển khai ý tưởng thực tập chuỗi. Nhóm chuỗi cũng là một ví dụ về mẫu Flyweight. String pool giúp tiết kiệm rất nhiều bộ nhớ nhưng mặt khác việc tạo một hàng sẽ mất nhiều thời gian hơn. Khi chúng ta sử dụng dấu ngoặc kép để tạo một chuỗi, trước tiên nó sẽ tìm một chuỗi trong nhóm có cùng giá trị, nếu tìm thấy thì chỉ cần trả về một tham chiếu, nếu không, một chuỗi mới sẽ được tạo trong nhóm rồi trả về một tham chiếu. Tuy nhiên, khi sử dụng toán tử mới, chúng ta buộc lớp Stringphải tạo một đối tượng chuỗi mới và sau đó chúng ta có thể sử dụng phương thức này intern()để đặt chuỗi vào nhóm hoặc lấy tham chiếu từ nhóm đến một đối tượng khác Stringcó cùng giá trị. Dưới đây là một ví dụ cho thấy cách hoạt động của nhóm chuỗi.
public class StringPool {
    public static void main(String[] args) {
        String s1 = "Cat";
        String s2 = "Cat";
        String s3 = new String("Cat");

        System.out.println("s1 == s2 :"+(s1==s2));
        System.out.println("s1 == s3 :"+(s1==s3));
    }
}
Chương trình sẽ xuất ra kết quả như sau:
s1 == s2 :true
s1 == s3 :false

19. Phương thức intern() có tác dụng gì?

Khi phương thức intern()được gọi, nếu nhóm chuỗi đã chứa một chuỗi tương đương với đối tượng của chúng ta, như được xác minh bằng phương thức equals(Object), thì tham chiếu đến chuỗi từ nhóm sẽ được trả về. Nếu không, đối tượng chuỗi sẽ được thêm vào nhóm và trả về một tham chiếu đến đối tượng đó. Phương thức này luôn trả về một chuỗi có cùng giá trị với chuỗi hiện tại, nhưng đảm bảo rằng đó sẽ là một chuỗi từ nhóm các chuỗi duy nhất. Dưới đây là một ví dụ về cách thức hoạt động của phương pháp này intern():
public class StringPool {
    public static void main(String[] args) {
        String a = "string a";
        String b = new String("string a");
        String c = b.intern();

        System.out.println(a == b);
        System.out.println(b == c);
        System.out.println(a == c);
    }
}
Программа выведет следующее:false
false
true

20. Chuỗi chuỗi có an toàn trong Java không?

Chuỗi là bất biến nên chúng ta không thể thay đổi giá trị của chúng trong chương trình. Do đó, chúng an toàn cho luồng và có thể được sử dụng an toàn trong môi trường đa luồng.

21. Tại sao String lại là khóa phổ biến trong HashMap trong Java?

Vì các chuỗi là bất biến nên mã băm của chúng được lưu vào bộ đệm tại thời điểm tạo và không cần tính toán lại. Điều này làm cho chuỗi trở thành ứng cử viên xuất sắc cho khóa Mapvà chúng được xử lý nhanh hơn các đối tượng chính khác HashMap. Đây là lý do tại sao chuỗi chủ yếu được sử dụng làm khóa HashMap. Tôi hy vọng những câu hỏi được liệt kê trong bài viết này sẽ giúp ích cho bạn trong các cuộc phỏng vấn, vui lòng cho tôi biết nếu tôi bỏ sót điều gì. Liên kết tới bài viết gốc Tác giả: Pankaj Kumar
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION