본문 바로가기

카테고리 없음

2023.08.22 TIL - 알고리즘 문제

문자열 내 마음대로 정렬하기

문자열 배열과 정수를 입력받아 문자열의 정수번째 문자를 기준으로 정렬하는 문제이다.

import java.util.*;
class Solution {
    public String[] solution(String[] strings, int n) {
        String[] answer = new String[strings.length];
        answer[0]=strings[0];
        for(int i = 1;i<strings.length;i++){
            int j;
            for(j = i-1;j>=0;j--){
                if (strings[i].charAt(n)<answer[j].charAt(n))
                    answer[j+1]=answer[j];
                else if (strings[i].charAt(n)==answer[j].charAt(n))
                {  
                    if(strings[i].compareTo(answer[j])>0)   
                        break;
                    else answer[j+1]=answer[j];
                }
                else break;
            }
            answer[j+1]=strings[i];
        }
        return answer;
    }
}

정렬된 배열에 새 요소를 삽입할 때 배열을 처음부터 탐색해 조건에 맞는 위치를 찾는 삽입 정렬 기법을 역순으로 적용해 문제를 풀었다. 만약 정수번째 문자가 동일하다면 문자열 비교연산 메소드인 String.compareTo를 활용해 사전 순서대로 입력될 수 있게 설정하였다.

 

 

숫자 문자열과 영단어

영어 단어와 숫자의 합으로 이루어진 숫자를 정수형으로 반환하는 문제이다.

import java.util.*;
class Solution {
    public int solution(String s) {
        List<String> dict = new ArrayList<>();
        dict.add("zero");
        dict.add("one");
        dict.add("two");
        dict.add("three");
        dict.add("four");
        dict.add("five");
        dict.add("six");
        dict.add("seven");
        dict.add("eight");
        dict.add("nine");
        int numberint = (int)'0';
        int answer = 0;
        String number = "";
        for (int i =0; i<s.length();i++){
            char tmp = s.charAt(i);
            if((int)tmp>=numberint && (int)tmp<numberint+10){
                answer=answer*10+Integer.parseInt(Character.toString(tmp));
            }
            else{
                number+=tmp;
                int ind = dict.indexOf(number);
                if(ind!=-1){
                    answer=answer*10+ind;
                    number="";
                }
            }
        }
        return answer;
    }
}

indexOf 메소드를 활용하기 위해 List 자료구조를 활용했다. Key를 영어 단어, Value를 정수로 받는 Map 자료 구조를 활용해도 동일하다.

문자열의 charAt 메소드를 활용해, 먼저 해당 문자의 아스키 코드 값이 '0' 이상 '9' 이하일 경우 이 문자는 자연수이기에 이를 정수형으로 바꿔준 뒤 answer 뒤에 붙여주었다. 또한 문자가 알파벳일 경우, List에서 완성된 영어 단어를 찾을 때까지 붙이고, 찾는다면 그 단어의 index를 호출해 answer뒤에 붙여주고 완성된 영어 단어가 저장된 변수는 초기화해 주었다.

 

 

 

K번째수

배열을 i번째부터 j번째까지 자르고 정렬한 뒤 k번째 숫자를 구하는 문제이다.

import java.util.*;
class Solution {
    public int[] solution(int[] array, int[][] commands) {
        int[] answer = new int[commands.length];
        int t = 0;
        for(int[] iar:commands){
            int[] tmp = Arrays.copyOfRange(array,iar[0]-1,iar[1]);
            Arrays.sort(tmp);
            answer[t] = tmp[iar[2]-1];
            t++;
        }
        return answer;
    }
}

Array의 copyOfRange 메소드로 배열을 쉽게 자를 수 있고, sort 메소드를 통해 정렬할 수 있다. 이후에는 조건에 맞게 index를 설정한 후 이를 반환하면 쉽게 문제를 해결할 수 있다.

 

 

두 개 뽑아서 더하기

배열에서 서로 다른 위치의 두 수를 더해 만들 수 있는 모든 수를 오름차순인 배열로 반환하는 문제이다.

import java.util.*;
class Solution {
    public int[] solution(int[] numbers) {
        List<Integer> ans = new ArrayList<>();
        for(int i = 0;i<numbers.length-1;i++){
            for (int j = i+1;j<numbers.length;j++){
                ans.add(numbers[i]+numbers[j]);
            }
        }
        return ans.stream().distinct().sorted().mapToInt(i->i).toArray();
    }
}

처음에는 배열 내에서 서로 다른 두 수로 잘못 판단해 numbers에서 중복값을 제거하고 실행했었는데, 이 때문에 처음에는 틀린 코드라는 결과를 받았다. for 문을 이용해 배열에서 두 수를 더한 값들을 전부 저장한 후, stream 기능을 활용해 중복 제거와 정렬을 진행한 후, 다시 배열로 바꾸어 반환하였다.

 

 

가장 가까운 같은 글자

문자열을 받아 해당 문자열의 문자가 몇 번 전에 출력되었는지를 배열로 만들어 반환하는 문제이다.

import java.util.*;
class Solution {
    public int[] solution(String s) {
        Map<Character,Integer> arr = new HashMap<>();
        List<Integer> ans = new ArrayList<>();
        for(int i = 0;i<s.length();i++){
            char tmp = s.charAt(i);
            int tmp2 = arr.get(tmp)!=null?arr.get(tmp):-1;            
            ans.add(tmp2==-1?tmp2:i-tmp2);
            arr.put(tmp,i);
        }
        return ans.stream().mapToInt(i->i).toArray();
    }
}

먼저 문자와 그 문자의 위치를 저장할 Map 자료구조를 생성한다. 문자열의 문자마다 해당 Map에서 문자를 key로 위치를 찾은 뒤, 만약 찾을 수 없다면 -1을 저장하고 찾았다면 해당 위치와 현재 위치를 뺀 값을 저장한 후, Map에는 현재 위치를 저장한다. 처음에는 파이썬 리스트의 find와 착각해 -1을 출력할 것으로 생각했던 Map.get() 함수가 null을 반환해 수정해야 했다. 자바에서 Map 자료구조는 파이썬에서 dictionary 자료구조와 동일한데, dictionary도 없는 key 값을 기준으로 값을 찾을 경우 Key Error가 호출된다는 것을 잊고 있었다.

 

 

푸드 파이트 대회

배열의 각 요소는 해당 번호의 음식이 준비된 갯수이고, 이를 양측에 동일하게 배치하는 문제이다.

class Solution {
    public String solution(int[] food) {
        int[] arr = new int[food.length];
        String answer = "";
        for(int i = 0;i<food.length;i++){
            answer += String.format("%s", i).repeat(food[i]/2);
        }
        String arr1 = new StringBuilder().append(answer).reverse().toString();
        answer=answer+"0"+arr1;
        return answer;
    }
}

준비된 음식 갯수를 2로 나눈 몫이 한 쪽에 놓여질 갯수가 되고, 따라서 각 요소의 절반에 해당하는 수치만큼 문자를 반복해 입력한 후, 이를 뒤집으면 반대측의 음식 배치가 나오게 된다. StringBuilder를 사용해 이를 뒤집어준 후, 양 측 사이에 "0"을 넣어 반환해주면 문제에서 원하는 데이터를 얻을 수 있다.

 

 

콜라 문제

빈 병을 a개 가져다 주면 새 콜라 b개를 준다고 했을 때, n개의 콜라를 갖고 있다면 총 몇 병을 마실 수 있는지 반환하는 문제이다.

class Solution {
    public int solution(int a, int b, int n) {
        int swit = n/a*b;
        int carry = n%a;
        if(a>n) return 0;
        return swit + solution(a,b,swit+carry);
    }
}

n개의 콜라병이 있다면 n/a회 가져다 줄 수 있고, 1회 가져다 줄 때마다 b개를 받을 수 있기에 총 n/a*b개의 새 콜라를 얻을 수 있다. 새 콜라를 얻은 것 또한 빈 병을 가져다 줄 수 있고, n/a*b개의 새 빈병과 기존에 반환하지 못한 n%a개의 빈병을 합했을 때 다시 몇 개의 콜라를 얻을 수 있는지를 재귀 함수를 통해 호출하였다. 또한 a>n일 경우에는 반환이 불가능하기에 0을 반환해 주었고 위 과정을 통해 재귀 함수를 성공적으로 구현해 낼 수 있었다.