코딩테스트/HackerRank

[HackerRank] Palindrome Index(투포인터) 📌

주니어주니 2023. 4. 9. 19:58

 

 

문제 

 

거꾸로 읽어도 똑같은 문자열이 되도록 하기 위해 몇번째 문자를 제거해야 하는지 구하기 

이미 palindrome 이거나 답이 없으면 -1 반환

이게 투포인터구나.. 

 

 

 

 

내 풀이 

 

일단 틀렸다. test case 몇 개 통과가 안되고, 시간이 초과되어서 점수 한 18점 정도 받았음 .. ㅠ

앞에서부터 읽었을 때와 뒤에서부터 읽었을 때가 같은지를 어케 알 수 있을까 하다가 더 고민하지 않고 

문자열의 첫번째부터 삭제해가면서

reverse()를 사용했는데 그럼 다시 또 reverse를 해야하고, 

deleteCharAt()으로 삭제하고 나서 다시 원래 문자열을 담아야 하고 그래서 복잡하긴 했다 .... ㅠ

 

private static int palindromeIndex(String s) {

    StringBuffer sb = new StringBuffer();
    sb.append(s);

    // 이미 맞으면 -> return -1
    if(sb.toString().equals(sb.reverse().toString())) {
        return -1;
    }
    sb.reverse();

    // 문자열에서 앞에서부터 하나씩 지우면서 뒤집어도 같은 문자열인지 확인
    for(int i=0; i < s.length(); i++) {
        sb.deleteCharAt(i);
        if(sb.toString().equals(sb.reverse().toString())) {
            return i;
        }
        sb.reverse().replace(0, sb.length(), s);
    }

    return -1;

}

 

 

 

아 이 코드는 이해할 만 하다 헀는데 

이것도 타임 초과 ㅡㅡ 

 

private static int palindromeIndex(String s) {

    // 이미 회문이면 -1 반환
    if(isPalindrome(s)) {
        return -1;
    }

    // 하나씩 삭제하면서 확인 (그 문자를 제외한 문자의 합)
    for(int i=0; i<s.length(); i++) {
        // (처음 ~ i-1번째 문자) + (i+1번째 ~ 끝 문자) -> i번째를 제외한 문자열의 합
        String str = s.substring(0, i) + s.substring(i + 1);
        if(isPalindrome(str))
            return i;
    }

    // 해당하는게 없으면 -1 반환
    return -1;
}

// 회문인지 확인하는 메소드
private static boolean isPalindrome(String s) {

    // 양쪽 끝 설정
    int start = 0;
    int end = s.length() - 1;

    // 둘이 만날 때까지
    while(start < end) {
        // start번째의 문자와 end번째의 문자가 다르면 false (회문 아님)
        if(s.charAt(start) != s.charAt(end)) {
            return false;
        }
        start ++;
        end --;
    }
    // 만날 때까지 다른 문자가 없었으면 true (회문)
    return true;
}

 

 

 

다른 사람 풀이 

 

private static int palindromeIndex(String s) {
 
    int start = 0; 
    int end = s.length() - 1; 

    // 양쪽 끝에서부터 만날 때까지 회문인지 확인
    while (start < end) {
        if(s.charAt(start) != s.charAt(end)) 
            break;
        start ++;
        end --; 
    }
    // 만날 때까지 다른 문자 없으면 회문 -> -1 반환
    if(start >= end) 
        return -1;

    // 문자열이 회문이 아닐 때 
    // 반환할 인덱스 구하기
    int i = start; 
    int j = end;

    // 전체 string이 회문 아닌건 알았으니까 첫번째 문자 제외
    start ++;

    // 회문인지 확인
    while(start < end) {
        if(s.charAt(start) != s.charAt(end))
            return j;
        start ++; 
        end --;
    }

    // 회문이면 현재 제외한 i번째 인덱스 반환
    return i;

}

 

솔직히 두번째 while문에서 왜 문자열의 끝에서부터 제외하는지 이해가 안된다

 

앞에서부터 제외하면, 

한 글자를 제외하고 다시 비교를 수행할 때 매번 문자열의 모든 길이를 재계산해야 함

 

뒤에서부터 제외하면, 

문자열의 길이가 변하지 않기 때문에 불필요한 계산을 줄일 수 있음 -> 문자열의 길이가 길 수록 효율적

 

뭔말이지? ㅠ