[LeetCode/Top Interview 150] [Two Pointers] 125. Valid Palindrome

1vl·2023년 8월 25일
0

LeetCode Top Interview 150

목록 보기
10/31

문제 링크: https://leetcode.com/problems/valid-palindrome/?envType=study-plan-v2&envId=top-interview-150
사용 언어: Java(OpenJDK 17. Java 8)

난이도: easy

문제:

A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers.

Given a string s, return true if it is a palindrome, or false otherwise.

Example 1:

Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.
Example 2:

Input: s = "race a car"
Output: false
Explanation: "raceacar" is not a palindrome.
Example 3:

Input: s = " "
Output: true
Explanation: s is an empty string "" after removing non-alphanumeric characters.
Since an empty string reads the same forward and backward, it is a palindrome.

Constraints:

1 <= s.length <= 2 * 105
s consists only of printable ASCII characters.

전략:

먼저 주어진 문자열을 toLowerCase와 trim, charAt을 이용해 알파벳 소문자와 숫자로만 이루어진 문자열로 바꾼다.
회문인지 아닌지 판별하기 위해서는 시작과 끝 양 끝단의 포인터를 비교하다가 같지 않은게 나오는 순간 false, 두 포인터가 한 점에서 만날 때 까지 false가 안 난다면 true

코드 구현:

class Solution {
    public boolean isPalindrome(String s) {
        // 문자만 남기기
        s = trim(s);
        
        // 빈 문자열인 경우 true
        if (s.length() == 0) {
            return true;
        }
        
        // 투포인터로 비교후 다른 경우 즉시 false 리턴
        for (int i=0;i<s.length()/2;i++) {
            if (s.charAt(i) != s.charAt(s.length()-1-i)) {
               return false; 
            }
        }
        // 투포인터 통과시 회문
        return true;
    }
    
    public String trim(String s) {
        s=s.toLowerCase();
        StringBuilder sb = new StringBuilder();
        for (int i=0;i<s.length();i++) {            
            char c = s.charAt(i);
            // 숫자 또는 알파벳 소문자만
            if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')) {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}

실행결과:
Time: 3 ms (87.05%), Space: 43.5 MB (59.15%) - LeetHub
https://github.com/1-vL/LeetCode/blob/main/0125-valid-palindrome/0125-valid-palindrome.java

개선 방안:

java String에서 alphanumeric한 글자만 남기는 기본 메서드가 분명 있을거 같은데 모르겠어서 냅다 만들어서 푼 부분에서 복잡도가 증가하지 않았나 싶다.
StringBuilder로 문자열로 바꾸는게 아니라 바로 char인 상태로 비교하고, 실패시에는 다시 이전에 비교한 문자를 비교하는 식으로 하면 더 빠를듯하다.

Discuss 탭의 타인 코드:

class Solution{
public  boolean isPalindrome(String s) {
        // int i = 0, j = s.length() - 1;
        // 0 9  A Z  a z
        
        char[] c = s.toCharArray();
        int i = 0, j = c.length - 1;
        // if(c.length==2){
        //     return c[i]==c[j]?true:false;
        // }
        while (i <=j) {
            if (upper(c[i])) {
                c[i] = tolowercase(c[i]);
            }
            if (upper(c[j])) {
                c[j] = tolowercase(c[j]);
            }
            i++;
            j--;
        }
        // 2 -1
        // System.out.println(Arrays.toString(c));
        i = 0;
        j = c.length - 1;
        while (i < j) {
            while (i<c.length&&!isalphanu(c[i])) {
                i++;
            }
            while (i<c.length&&!isalphanu(c[j])) {
                j--;
            }
            if(j<i){
                return true;
            }
            if (c[i] != c[j]) {
                return false;
            }
            i++;
            j--;
        }
        return true;
    }

    public  char tolowercase(char c) {
        return (char) (c + 32);
    }

    public  boolean isalphanu(char c) {
        boolean b = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ? true : false;
        return b;
    }

    public  boolean upper(char c) {
        return (c >= 'A' && c <= 'Z') ? true : false;
    }
}
Time: 2 ms (99.64%), Space: 42.1 MB (73.32%) - LeetHub

회고:

While문을 돌면서 char 배열을 순회하는 부분에서 성능차이가 난 것 같다. 내 코드도 한 번 그 부분을 직접 구현해 봐야겠다. 그래도 역시 처음에 한 번 문자열을 깔끔하게 정리하는 과정은 생략할 수 없는 듯 하다.

class Solution {
    public boolean isPalindrome(String s) {
        // char 배열 가져오기
        char[] array = s.toCharArray();
        
        // 앞 포인터 i, 뒤 포인터 j
        int i = 0;
        int j = s.length()-1;
        
        // char 배열 정리
        while (i <=j) {
            if (isUpper(array[i])) {
                array[i] = toLowerCase(array[i]);
            }
            if (isUpper(array[j])) {
                array[j] = toLowerCase(array[j]);
            }
            i++;
            j--;
        }
        
        i = 0;
        j = s.length()-1;
        // 두 포인터가 만나면 탈출
        
        while (i < j) {
            while (i<array.length&&!isAlphaNumeric(array[i])) {
                i++;
            }
            while (i<array.length&&!isAlphaNumeric(array[j])) {
                j--;
            }
            if(j<i){
                return true;
            }
            if (array[i] != array[j]) {
                return false;
            }
            i++;
            j--;
        }
        return true;
    }
    
    public boolean isAlphaNumeric(char c) {
        // 숫자 또는 알파벳 소문자만
        if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')) {
            return true;
        }
        return false;
    }
    
    public char toLowerCase(char c) {
        return (char) (c+32);
    }
    public boolean isUpper(char c) {        
        if (c >= 'A' && c <= 'Z') {
            return true;
        }
        return false;
    }
}
Time: 2 ms (99.64%), Space: 41.8 MB (90.71%) - LeetHub
profile
React-Native, Flutter, Java, Spring, lua

0개의 댓글