본문 바로가기
알고리즘 풀이

221122 알고리즘 풀이 6문제

by 미노킴 2022. 11. 22.

1. 시저 암호

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

1) 문제 설명

어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 "AB"는 1만큼 밀면 "BC"가 되고, 3만큼 밀면 "DE"가 됩니다. "z"는 1만큼 밀면 "a"가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.

2) 제한 사항

  • 공백은 아무리 밀어도 공백입니다.
  • s는 알파벳 소문자, 대문자, 공백으로만 이루어져 있습니다.
  • s의 길이는 8000이하입니다.
  • n은 1 이상, 25이하인 자연수입니다.

3) 풀이

아스키코드 값을 조정하여 풀려고 했는데, 아스키코드를 조정하는 과정에서 뭔가 문제가 생김. 결국 못 풀음...

 

오늘은 정규 표현식 공부하는 게 더 우선일 것 같아서 일단 스킵하고 스터디 때 팀원들한테 조금 물어보기로 결정함.

4) 소스 코드

2. 신규 아이디 추천

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

1) 문제 설명

카카오에 입사한 신입 개발자 네오는 "카카오계정개발팀"에 배치되어, 카카오 서비스에 가입하는 유저들의 아이디를 생성하는 업무를 담당하게 되었습니다. "네오"에게 주어진 첫 업무는 새로 가입하는 유저들이 카카오 아이디 규칙에 맞지 않는 아이디를 입력했을 때, 입력된 아이디와 유사하면서 규칙에 맞는 아이디를 추천해주는 프로그램을 개발하는 것입니다.
다음은 카카오 아이디의 규칙입니다.

아이디의 길이는 3자 이상 15자 이하여야 합니다.
아이디는 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.) 문자만 사용할 수 있습니다.
단, 마침표(.)는 처음과 끝에 사용할 수 없으며 또한 연속으로 사용할 수 없습니다.
"네오"는 다음과 같이 7단계의 순차적인 처리 과정을 통해 신규 유저가 입력한 아이디가 카카오 아이디 규칙에 맞는 지 검사하고 규칙에 맞지 않은 경우 규칙에 맞는 새로운 아이디를 추천해 주려고 합니다.
신규 유저가 입력한 아이디가 new_id 라고 한다면,

1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
     만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.
예를 들어, new_id 값이 "...!@BaT#*..y.abcdefghijklm" 라면, 위 7단계를 거치고 나면 new_id는 아래와 같이 변경됩니다.

1단계 대문자 'B'와 'T'가 소문자 'b'와 't'로 바뀌었습니다.
"...!@BaT#*..y.abcdefghijklm" → "...!@bat#*..y.abcdefghijklm"

2단계 '!', '@', '#', '*' 문자가 제거되었습니다.
"...!@bat#*..y.abcdefghijklm" → "...bat..y.abcdefghijklm"

3단계 '...'와 '..' 가 '.'로 바뀌었습니다.
"...bat..y.abcdefghijklm" → ".bat.y.abcdefghijklm"

4단계 아이디의 처음에 위치한 '.'가 제거되었습니다.
".bat.y.abcdefghijklm" → "bat.y.abcdefghijklm"

5단계 아이디가 빈 문자열이 아니므로 변화가 없습니다.
"bat.y.abcdefghijklm" → "bat.y.abcdefghijklm"

6단계 아이디의 길이가 16자 이상이므로, 처음 15자를 제외한 나머지 문자들이 제거되었습니다.
"bat.y.abcdefghijklm" → "bat.y.abcdefghi"

7단계 아이디의 길이가 2자 이하가 아니므로 변화가 없습니다.
"bat.y.abcdefghi" → "bat.y.abcdefghi"

따라서 신규 유저가 입력한 new_id가 "...!@BaT#*..y.abcdefghijklm"일 때, 네오의 프로그램이 추천하는 새로운 아이디는 "bat.y.abcdefghi" 입니다.

 

신규 유저가 입력한 아이디를 나타내는 new_id가 매개변수로 주어질 때, "네오"가 설계한 7단계의 처리 과정을 거친 후의 추천 아이디를 return 하도록 solution 함수를 완성해 주세요.

2) 제한 사항

new_id는 길이 1 이상 1,000 이하인 문자열입니다.
new_id는 알파벳 대문자, 알파벳 소문자, 숫자, 특수문자로 구성되어 있습니다.
new_id에 나타날 수 있는 특수문자는 -_.~!@#$%^&*()=+[{]}:?,<>/ 로 한정됩니다.

3) 풀이

(네오 부럽다)

문자열을 split으로 나눈 후 개별 문자들을 아스키코드로 확인하여 1,2,3단계를 진행하였다. 1,2,3단계는 묶어서 한꺼번에 진행하였고, 3단계를 쉽게 하기 위해 check라는 boolean 값을 만들어 직전값이 "."일 경우 false가 되게 하고 아닐 경우 true가 되도록 하였다.

 

문자열 비교할 때 equals를 안쓰고 ==를 썼다가 계속 에러가 나왔었다. 다음부턴 조심하자..

 

매니저님의 풀이를 보니 '정규표현식'을 잘 활용하면 코드가 거의 10줄 전후까지 줄어든다. 정규표현식은 아래 글에 정리해두었다.

https://kimdirector1090.tistory.com/69 

 

[Java] 정규 표현식

 

kimdirector1090.tistory.com

4) 소스 코드

import java.util.*;
class Solution {
    public String solution(String new_id) {
        //아이디가 빈칸일 경우 5단계 -> 7단계 진행
        if(new_id==null || new_id.equals("")){
            String answer = "aaa";
            return answer;
        }
        
        String[] idArr = new_id.split("");
        List<String> splitList = Arrays.asList(idArr);

        //1단계,2단계,3단계 처리, 리스트 삭제보다 새로운 리스트에 값 넣는게 더 빨라서 새로운 LinkedList 생성
        
        boolean check = true;
        LinkedList<String> newSplitList = new LinkedList<>();
        for(String i : splitList){
            String s = i.toLowerCase(Locale.ROOT);
            
            if(s.charAt(0)>96 && s.charAt(0)<123){
                newSplitList.add(s);
                check = true;
            }
            
            else if(s.charAt(0)>47 && s.charAt(0)<58){
                newSplitList.add(s);
                check = true;
            }
            
            else if(s.equals("-") || s.equals("_")){
                newSplitList.add(s);
                check = true;
            }
            
            else if(s.equals(".") && check){
                newSplitList.add(s);
                check = false;
            }
        }

        
        if(newSplitList.isEmpty()){
            newSplitList.add("a");
        }
        //4단계 처리
        while (newSplitList.getFirst().equals(".") || newSplitList.getLast().equals(".")){
            
            if(newSplitList.getFirst().equals(".")){
                newSplitList.removeFirst();
                
                if(newSplitList.isEmpty()){
                    newSplitList.add("a");
                }
            }
            
            else if(newSplitList.getLast().equals(".")){
                newSplitList.removeLast();
                
                if(newSplitList.isEmpty()){
                    newSplitList.add("a");
                }
            }
        }

        //6단계 진행
        while(newSplitList.size()>15 || newSplitList.getLast().equals(".")){
            newSplitList.removeLast();
        }

        //7단계 진행
        while(newSplitList.size()<3){
            String s = newSplitList.getLast();
            newSplitList.add(s);
        }

        
        String answer = String.join("",newSplitList);
        return answer;
    }
}
테스트 1 통과 (0.44ms, 81.2MB)
테스트 2 통과 (0.57ms, 72.4MB)
테스트 3 통과 (0.56ms, 67.9MB)
테스트 4 통과 (0.62ms, 75.1MB)
테스트 5 통과 (0.72ms, 78.9MB)
테스트 6 통과 (0.65ms, 75.2MB)
테스트 7 통과 (0.72ms, 75.2MB)
테스트 8 통과 (0.51ms, 70.5MB)
테스트 9 통과 (0.48ms, 70.6MB)
테스트 10 통과 (0.36ms, 76.7MB)
테스트 11 통과 (0.43ms, 71.2MB)
테스트 12 통과 (0.55ms, 75MB)
테스트 13 통과 (0.70ms, 72.8MB)
테스트 14 통과 (0.60ms, 76.6MB)
테스트 15 통과 (0.64ms, 79.3MB)
테스트 16 통과 (0.63ms, 72.2MB)
테스트 17 통과 (2.00ms, 86.5MB)
테스트 18 통과 (2.62ms, 79.4MB)
테스트 19 통과 (3.04ms, 75MB)
테스트 20 통과 (2.96ms, 76.8MB)
테스트 21 통과 (3.44ms, 75.2MB)
테스트 22 통과 (2.21ms, 66.9MB)
테스트 23 통과 (3.12ms, 76.9MB)
테스트 24 통과 (3.08ms, 82.2MB)
테스트 25 통과 (2.87ms, 72.7MB)
테스트 26 통과 (3.28ms, 73.9MB)

3. 약수의 개수와 덧셈

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

1) 문제 설명

두 정수 left와 right가 매개변수로 주어집니다. left부터 right까지의 모든 수들 중에서, 약수의 개수가 짝수인 수는 더하고, 약수의 개수가 홀수인 수는 뺀 수를 return 하도록 solution 함수를 완성해주세요.

2) 제한 사항

  • 1 ≤ left  right ≤ 1,000

3) 풀이

소수를 구하는 메소드를 활용하여 약수의 수를 구하는 메소드를 작성하였다. 

4) 소스 코드

class Solution {
    public int solution(int left, int right) {
        int answer = 0;
        
        for(int i=left;i<=right;i++){
            if(countDivisor(i)%2==0){
                answer+=i;
            }

            else if(countDivisor(i)%2==1){
                answer-=i;
            }
        }
        return answer;
    }
    
    //약수 구하는 메소드
    public static int countDivisor(int num){
        int count = 0;
        for(int i=1; i<=num; i++){
            if(num%i==0){
                count +=1;
            }
        }
        return count;

    }
}
테스트 1 통과 (3.14ms, 77MB)
테스트 2 통과 (0.80ms, 74.3MB)
테스트 3 통과 (1.04ms, 77.2MB)
테스트 4 통과 (1.06ms, 79.3MB)
테스트 5 통과 (3.98ms, 92.9MB)
테스트 6 통과 (0.54ms, 76.8MB)
테스트 7 통과 (0.17ms, 78.6MB)

4. 약수의 합

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

1) 문제 설명

정수 n을 입력받아 n의 약수를 모두 더한 값을 리턴하는 함수, solution을 완성해주세요.

2) 제한 사항

  • n은 0 이상 3000이하인 정수입니다.

3) 풀이

약수 구하는 메소드 활용하면 끝. 0일때만 따로 if문을 작성해주었다.

4) 소스 코드

class Solution {
    public int solution(int n) {
        int answer = 0;
        if(n ==0){
            return answer;
        }
        for(int i=1; i<=n; i++){
            if(n%i==0){
                answer +=i;
            }
        }
        return answer;
    }
}
테스트 1 통과 (0.03ms, 79.3MB)
테스트 2 통과 (0.02ms, 76MB)
테스트 3 통과 (0.04ms, 75.8MB)
테스트 4 통과 (0.03ms, 68.9MB)
테스트 5 통과 (0.06ms, 77.7MB)
테스트 6 통과 (0.03ms, 72.7MB)
테스트 7 통과 (0.05ms, 71.1MB)
테스트 8 통과 (0.02ms, 75.5MB)
테스트 9 통과 (0.04ms, 87.9MB)
테스트 10 통과 (0.09ms, 84MB)
테스트 11 통과 (0.04ms, 73.4MB)
테스트 12 통과 (0.07ms, 79.4MB)
테스트 13 통과 (0.01ms, 75.2MB)
테스트 14 통과 (0.09ms, 79.8MB)
테스트 15 통과 (0.04ms, 73.5MB)
테스트 16 통과 (0.02ms, 75.7MB)
테스트 17 통과 (0.06ms, 71.4MB)

5. 예산

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

1) 문제 설명

S사에서는 각 부서에 필요한 물품을 지원해 주기 위해 부서별로 물품을 구매하는데 필요한 금액을 조사했습니다. 그러나, 전체 예산이 정해져 있기 때문에 모든 부서의 물품을 구매해 줄 수는 없습니다. 그래서 최대한 많은 부서의 물품을 구매해 줄 수 있도록 하려고 합니다.

물품을 구매해 줄 때는 각 부서가 신청한 금액만큼을 모두 지원해 줘야 합니다. 예를 들어 1,000원을 신청한 부서에는 정확히 1,000원을 지원해야 하며, 1,000원보다 적은 금액을 지원해 줄 수는 없습니다.

부서별로 신청한 금액이 들어있는 배열 d와 예산 budget이 매개변수로 주어질 때, 최대 몇 개의 부서에 물품을 지원할 수 있는지 return 하도록 solution 함수를 완성해주세요.

2) 제한 사항

  • d는 부서별로 신청한 금액이 들어있는 배열이며, 길이(전체 부서의 개수)는 1 이상 100 이하입니다.
  • d의 각 원소는 부서별로 신청한 금액을 나타내며, 부서별 신청 금액은 1 이상 100,000 이하의 자연수입니다.
  • budget은 예산을 나타내며, 1 이상 10,000,000 이하의 자연수입니다.

3) 풀이

d를 오름차순 정렬한 후에 budget이 오버되기 직전까지 차근차근 넣었다. 오버되는 순간 break로 반복문을 탈출하였다.

4) 소스 코드

import java.util.*;
class Solution {
    public int solution(int[] d, int budget) {
        int answer = 0;
        
        Arrays.sort(d);
        for(int i : d){
            budget -=i;
            answer +=1;
            if(budget<0){
                budget +=i;
                answer -=1;
                break;
            }
        }
        return answer;
    }
}
테스트 1 통과 (0.56ms, 86.7MB)
테스트 2 통과 (0.37ms, 86.6MB)
테스트 3 통과 (0.46ms, 79.2MB)
테스트 4 통과 (0.46ms, 77.5MB)
테스트 5 통과 (0.34ms, 76.2MB)
테스트 6 통과 (0.53ms, 73.1MB)
테스트 7 통과 (0.50ms, 78MB)
테스트 8 통과 (0.52ms, 75.5MB)
테스트 9 통과 (0.47ms, 78.7MB)
테스트 10 통과 (0.50ms, 82.7MB)
테스트 11 통과 (0.53ms, 72.5MB)
테스트 12 통과 (0.44ms, 79.2MB)
테스트 13 통과 (0.37ms, 72.9MB)
테스트 14 통과 (0.40ms, 73.9MB)
테스트 15 통과 (0.47ms, 76.8MB)
테스트 16 통과 (0.38ms, 75.7MB)
테스트 17 통과 (0.47ms, 80.8MB)
테스트 18 통과 (0.54ms, 81.6MB)
테스트 19 통과 (0.37ms, 75.5MB)
테스트 20 통과 (0.51ms, 80.5MB)
테스트 21 통과 (0.49ms, 75.5MB)
테스트 22 통과 (0.44ms, 77.1MB)
테스트 23 통과 (0.34ms, 74.5MB)

6. 최대공약수와 최소공배수

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

1) 문제 설명

두 수를 입력받아 두 수의 최대공약수와 최소공배수를 반환하는 함수, solution을 완성해 보세요. 배열의 맨 앞에 최대공약수, 그다음 최소공배수를 넣어 반환하면 됩니다. 예를 들어 두 수 3, 12의 최대공약수는 3, 최소공배수는 12이므로 solution(3, 12)는 [3, 12]를 반환해야 합니다.

2) 제한 사항

  • 두 수는 1이상 1000000이하의 자연수입니다.

3) 풀이

최대공약수는 공약수의 리스트를 먼저 구한 다음 그 중 제일 큰 값을 꺼내서 사용하였다. 공약수 리스트는 첫 번째의 약수를 구해서 전부 HashMap에 키값으로 넣은 후에, 두 번째의 약수들 중 key값과 겹치는 게 있으면 리스트에 넣는 식으로 구하였다.

 

최소공배수는 양쪽 값을 최대공약수로 나누어 서로소로 만든 후 서로소와 최대공약수를 곱해서 구하였다.

 

(이건 최소공배수 구하는 방법을 모르면 너무 빡센 문제일듯..?)

4) 소스 코드

import java.util.*;
class Solution {
    public int[] solution(int n, int m) {
        //max는 최대공약수, min은 최소공배수
        int max = getGreatestCommonDivisor(n, m);
        int min = (n/max) * (m/max) * max;

        int[] answer = {max, min};
        return answer;
    }
    
    //최대공약수 구하기
    public int getGreatestCommonDivisor(int num1, int num2){
        Map<Integer, Integer> map = new HashMap<>();
        List<Integer> list = new ArrayList<>();
        for(int i=1;i<=num1;i++){
            if(num1%i==0){
                map.put(i,1);
            }
        }

        for(int i=1;i<=num2;i++){
            if(num2%i==0){
                if(map.containsKey(i)){
                    list.add(i);
                }
            }
        }
        Collections.sort(list);
        int result = list.get(list.size()-1);
        return result;
    }
}
테스트 1 통과 (0.34ms, 81.9MB)
테스트 2 통과 (0.31ms, 74MB)
테스트 3 통과 (0.26ms, 74.6MB)
테스트 4 통과 (0.28ms, 68.7MB)
테스트 5 통과 (0.36ms, 74.3MB)
테스트 6 통과 (0.29ms, 75.8MB)
테스트 7 통과 (0.24ms, 76MB)
테스트 8 통과 (0.28ms, 78.1MB)
테스트 9 통과 (0.29ms, 71.6MB)
테스트 10 통과 (0.29ms, 73.8MB)
테스트 11 통과 (0.52ms, 71.5MB)
테스트 12 통과 (0.48ms, 75.6MB)
테스트 13 통과 (0.40ms, 76.9MB)
테스트 14 통과 (0.34ms, 77.1MB)
테스트 15 통과 (0.33ms, 81.4MB)
테스트 16 통과 (0.39ms, 74.6MB)

'알고리즘 풀이' 카테고리의 다른 글

221124 알고리즘 풀이 1문제  (2) 2022.11.24
221123 알고리즘 풀이 6문제  (0) 2022.11.23
221121 알고리즘 풀이 6문제  (2) 2022.11.21
221119 알고리즘 풀이 8문제  (2) 2022.11.19
221118 알고리즘 풀이 1  (0) 2022.11.18