[Study] 프로그래머스 lv.1 시저 암호(71%)

ayboori·2023년 6월 28일
0

Java Study

목록 보기
8/34

https://school.programmers.co.kr/learn/courses/30/lessons/12926

풀이 로직

  1. 함수의 리턴 값을 StringBuilder로 변경한다 (append 연산으로 수행 시간 감소를 위해)
  2. 입력받은 String을 char 배열로 변경한다
  3. char 배열의 값을 ascii 코드로 변환한다 (int)
  4. 두 가지 조건을 체크한다
    4-1. char 값이 공백이 아닌지 > 아니면 ascii 값 증가
    4-2. 증가 이후 대문자, 소문자 범위를 벗어나는지 > 범위를 벗어날 경우 원래 범위로 돌아오기
  5. 증가 이후의 값을 append를 통해 빌더에 붙이고, 최종 리턴

관련 지식 / 함수

String to char []

char [] charArray = string.toCharArray();
참고

ASCII 코드 표

문자 하나 당 ASCII 숫자 하나에 대응한다

char to ASCII

int ascii = (int) c;
위와 같이 단순히 int로 변환 가능하고, byte로도 변환 가능하다 참고

ASCII to char

char asciiToChar = ( char ) ascii ;
위와 같이 단순히 int로 변환 가능하다 참고


내가 작성한 코드

class Solution {
    public StringBuilder solution(String s, int n) {
        char [] charArray = s.toCharArray(); // String을 char 배열로 변경
        StringBuilder answer = new StringBuilder();
        
        for (char c : charArray){
            int ascii = (int) c;
            if(c != ' '){ // 공백이 아닐 때만 밀기
                ascii += n;
            }
            
            if(c <= 90 && ascii > 90 || // 대문자이면서 밀면 범위 벗어남
                c >=97 && c <= 122 && ascii > 122){ // 소문자이면서 밀면 범위 벗어남 
                ascii -= 26; // 초기값으로 
            }
            answer.append((char)ascii); // 연산한 값을 부착
        }
        return answer;             
    }
}

통과 시간

0.05ms~ 2.46ms

테스트 1 〉	통과 (0.05ms, 77.6MB)
테스트 2 〉	통과 (0.11ms, 74.7MB)
테스트 3 〉	통과 (0.05ms, 76MB)
테스트 4 〉	통과 (0.07ms, 75.7MB)
테스트 5 〉	통과 (0.05ms, 70.4MB)
테스트 6 〉	통과 (0.05ms, 75.2MB)
테스트 7 〉	통과 (2.46ms, 86.3MB)
테스트 8 〉	통과 (0.03ms, 75.4MB)
테스트 9 〉	통과 (0.03ms, 76.7MB)
테스트 10 〉	통과 (0.05ms, 76.7MB)
테스트 11 〉	통과 (0.11ms, 81.5MB)
테스트 12 〉	통과 (0.09ms, 72.8MB)
테스트 13 〉	통과 (1.06ms, 76.9MB)

통과 시간 줄이기

더 이상 검사할 필요가 없는 코드(공백일 경우)에서 continue; 걸어버리기

class Solution {
    public StringBuilder solution(String s, int n) {
        char [] charArray = s.toCharArray(); // String을 char 배열로 변경
        StringBuilder answer = new StringBuilder();
        
        for (char c : charArray){
            int ascii = (int) c;
            if(c == ' '){
                answer.append((char)ascii); // 연산한 값을 부착
                continue;
            }else{ // 공백이 아닐 때만 밀기
                ascii += n;
            }
            
            if(c <= 90 && ascii > 90 || // 대문자이면서 밀면 범위 벗어남
                c >=97 && c <= 122 && ascii > 122){ // 소문자이면서 밀면 범위 벗어남 
                ascii -= 26; // 초기값으로 
            }
            answer.append((char)ascii); // 연산한 값을 부착
        }
        return answer;             
    }
}

최종 통과 시간

0.04ms ~ 1.38ms

테스트 1 〉	통과 (0.04ms, 77.4MB)
테스트 2 〉	통과 (0.04ms, 80.2MB)
테스트 3 〉	통과 (0.05ms, 72.9MB)
테스트 4 〉	통과 (0.03ms, 70.6MB)
테스트 5 〉	통과 (0.05ms, 78.4MB)
테스트 6 〉	통과 (0.05ms, 73.4MB)
테스트 7 〉	통과 (0.04ms, 77.1MB)
테스트 8 〉	통과 (0.04ms, 75.6MB)
테스트 9 〉	통과 (0.07ms, 76.9MB)
테스트 10 〉	통과 (0.03ms, 71.5MB)
테스트 11 〉	통과 (0.04ms, 75.6MB)
테스트 12 〉	통과 (0.13ms, 84.6MB)
테스트 13 〉	통과 (1.38ms, 76.9MB)

다른 사람의 풀이

    String caesar(String s, int n) {
        String result = "";
    n = n % 26;
    for (int i = 0; i < s.length(); i++) {
      char ch = s.charAt(i);
      if (Character.isLowerCase(ch)) {
        ch = (char) ((ch - 'a' + n) % 26 + 'a');
      } else if (Character.isUpperCase(ch)) {
        ch = (char) ((ch - 'A' + n) % 26 + 'A');
      }
      result += ch;
    }
        return result;
    }

범위를 벗어나는 문자

26 (알파벳의 범위)의 나머지를 구하는 방식을 사용하여 애초에 증가 값을 26을 넘지 않게 했다

대소문자 검색에 다른 방식 적용

if (Character.isLowerCase(ch))


스터디에서 배운 점

검사를 위한 메소드 만들기

chat GPT에게 물어봐서 랜덤 문자열 생성 메소드

import java.util.Random;

public class RandomStringGenerator {
    public static void main(String[] args) {
        int length = 10; // 생성할 문자열의 길이

        String randomString = generateRandomString(length);
        System.out.println(randomString);
    }

    public static String generateRandomString(int length) {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < length; i++) {
            int choice = random.nextInt(3); // 0, 1, 2 중에서 선택

            // choice 값에 따라 소문자, 대문자, 공백 중 하나를 선택하여 문자열에 추가
            if (choice == 0) {
                char lowercase = (char) (random.nextInt(26) + 'a');
                sb.append(lowercase);
            } else if (choice == 1) {
                char uppercase = (char) (random.nextInt(26) + 'A');
                sb.append(uppercase);
            } else {
                sb.append(' '); // 공백 추가
            }
        }

        return sb.toString();
    }
}

통과 시간 재기


        long beforeTime = System.currentTimeMillis();

        String test = RandomStringGenerator.generateRandomString(8000);
        test = js.solution(test,30); // 연산하고, 앞 뒤 시간 기
        long afterTime = System.currentTimeMillis();

        System.out.println("걸린 시간 : " + (afterTime - beforeTime));

append() vs setChar()

저는 StringBuilder를 초기화 시켜 놓고 String.charAt()을 append하는 방식이 더 좋을 거라고 생각했는데, 실제로 아주 긴 문자열로 실험해보니 더 빠르다고 합니다..!
아마 charAt()을 append를 하면서 계속 StringBuilder의 용량을 동적으로 조정해야 하는 과정에서 시간이 더 걸린 것이 아닌가 싶습니다!

profile
프로 개발자가 되기 위해 뚜벅뚜벅.. 뚜벅초

0개의 댓글