comparing에 대하여

byeol·2023년 5월 1일
0

스터디원을 통해 새롭게 알게된 comparing을 적용한 풀이법을 정리하려고 합니다.

문제 1

연속된 부분 수열의 합

이 문제는 스터디원을 통해 새롭게 알게된 comparing을 적용한 풀이법과
제가 원래 풀었던 풀이법 두 가지를 정리하겠습니다.

먼저 새롭게 알게된 comparing입니다.
자바8의 람다를 이용한 다중조건 정렬입니다.
아래와 같이 길어진 코드를

    //2. comparator
        
        Comparator<Cost> comp = new Comparator<>(){
           
            @Override
            public int compare(Cost c1, Cost c2){
                if(c1.length != c2.length){
                     return c1.length - c2.length;
                }else{
                    return c1.x-c2.x;                    
                }       
            }
        };
        
        Collections.sort(list,comp);

아래와 같이 간단하게 표현할 수 있습니다.

// 길이 오름차순, 길이가 같으면 x 오름차순
 list.sort(Comparator.comparing(Cost::getLength).thenComparing(Apple::getX));

물론 이와 같이 표현하려면 아래와 같은 내부 클래스에 메서드를 선언해야 합니다.

class Solution {
    
    static class Cost{
        int x;
        int y;
        int length;
        public Cost(int x, int y, int length){
            this.x=x;
            this.y=y;
            this.length = length;
        }

        public int getLength(){
               return length;
         }

        public int getX(){
               return x;
         }
    }
    
 ...

나의 풀이

import java.util.*;
class Solution {
    
    static class Cost{
        int x;
        int y;
        int length;
        public Cost(int x, int y, int length){
            this.x=x;
            this.y=y;
            this.length = length;
        }
    }
    
    
    public ArrayList<Integer> solution(int[] sequence, int k) {
        ArrayList<Cost> list = new ArrayList<>();
        ArrayList<Integer> answer = new ArrayList<>();
        
        // 기존 수열에서 임의의 두 인덱스의 원소와 그 사이의 원소를 모두 포함하는 부분 수열
        // 부분 수열의 합은 k
        // 합이 k인 부분 수열이 여러 개인 경우 길이가 짧은
        // 길이가 짧은 수열 여러게 앞쪽에 나오는 수열
        // 시작 인덱스와 마지막 인덱스 
        
        //1. 투포인터
        int r=0;
        int l=0;
        int sum = sequence[0];
        
        while(true){
          if(sum==k){
              list.add(new Cost(l,r,r-l+1));
          }
            
          if(r == sequence.length && l == sequence.length) break; 
            
         if(sum<= k && r< sequence.length){
             r++;
             if(r<sequence.length){
               sum+=sequence[r];
             }    
          }else{
              if(l<sequence.length) sum-=sequence[l];
              l++;
          }
        }
        //2. comparator
        
        Comparator<Cost> comp = new Comparator<>(){
           
            @Override
            public int compare(Cost c1, Cost c2){
                if(c1.length != c2.length){
                     return c1.length - c2.length;
                }else{
                    return c1.x-c2.x;                    
                }       
            }
        };
        
        Collections.sort(list,comp);
        
        Cost target = list.get(0);
        
        answer.add(target.x);
        answer.add(target.y);
       
        
        
        return answer;
    }
}

스터디원의 피드백으로 comparing()을 적용한 풀이

import java.util.*;
class Solution {
    
    static class Cost{
        int x;
        int y;
        int length;
        public Cost(int x, int y, int length){
            this.x=x;
            this.y=y;
            this.length = length;
        }
         public int getLength(){
               return length;
         }

        public int getX(){
               return x;
         }
    }
    
    
    public ArrayList<Integer> solution(int[] sequence, int k) {
        ArrayList<Cost> list = new ArrayList<>();
        ArrayList<Integer> answer = new ArrayList<>();
        
        // 기존 수열에서 임의의 두 인덱스의 원소와 그 사이의 원소를 모두 포함하는 부분 수열
        // 부분 수열의 합은 k
        // 합이 k인 부분 수열이 여러 개인 경우 길이가 짧은
        // 길이가 짧은 수열 여러게 앞쪽에 나오는 수열
        // 시작 인덱스와 마지막 인덱스 
        
        //1. 투포인터
        int r=0;
        int l=0;
        int sum = sequence[0];
        
        while(true){
          if(sum==k){
              list.add(new Cost(l,r,r-l+1));
          }
            
          if(r == sequence.length && l == sequence.length) break; 
            
         if(sum<= k && r< sequence.length){
             r++;
             if(r<sequence.length){
               sum+=sequence[r];
             }    
          }else{
              if(l<sequence.length) sum-=sequence[l];
              l++;
          }
        }
        //2. comparing()
        list.sort(Comparator.comparing(Cost::getLength).thenComparing(Cost::getX));
        
       
        
        Cost target = list.get(0);
        
        
       
        answer.add(target.x);
        answer.add(target.y);
       
        
        
        return answer;
    }
}

문제 2 (두 개의 조건의 정렬 방식이 섞인 경우)

[3차] 방금그곡

이 문제에서 comparing()이 하나가 내림차순이고 그 값이 같으면 오름차순이다를 적용하기 위한 방법을 소개해보려고 합니다.

두 개의 조건의 정렬 방식이 섞인 경우에 어떻게 표현해야 할까요?

다음과 같이 내부 클래스가 선언되어져 있고

import java.util.*;
class Solution {
    
    static int MaxTime = 24*60;
    
    static class Music{
         //재생시간, 위치, 제목
        int time;
        int index;
        String title;
        public Music(int time, int index, String title){
            this.time = time;
            this.index= index;
            this.title = title;
        }
        public int getTime(){
            return time;
        }
        public int getIndex(){
            return index;
        }
    }

길이가 내림차순, 순서 오름차순이라면

Comparator<Music> reversedComparator = Comparator.comparing(Music::getTime).reversed();
list.sort(reversedComparator.thenComparing(Music::getIndex));
        

반대라면

// 무게 오름차순 정렬 (무게가 같으면 색 내림차순 정렬)
Comparator<Apple> reversedColorComparator =Comparator.comparing(Apple::getColor).reversed();
inventory.sort(Comparator.comparing(Apple::getWeight).thenComparing(reversedColorComparator));

풀이

import java.util.*;
class Solution {
    
    static int MaxTime = 24*60;
    
    static class Music{
         //재생시간, 위치, 제목
        int time;
        int index;
        String title;
        public Music(int time, int index, String title){
            this.time = time;
            this.index= index;
            this.title = title;
        }
        public int getTime(){
            return time;
        }
        public int getIndex(){
            return index;
        }
    }
    
    
    public String solution(String m, String[] musicinfos) {
        String answer = "";
        // TV, 라디오 등에서 나온 음악에 관해 제목 등의 정보를 제공
        
        // 음악 제목, 재생이 시작되고 끝난시각, 악보 
        // 사용되는 음 : C, C#, D, D#, E, F, F#, G, G#, A, A#, B - 1분에 1개씩 재생
        // 음악의 길이 < 재생된 시간 - 음악이 끊김 없이 처음부터 반복 재생
        // 음악 길이 > 재생된 시간 - 음악이 처음부터 시간만큼만 재생
        // 음악이 00:00 넘어서 재생안됨
        // 조건이 일치하는 음악 여러개-> 라디오에서 재생된 시간이 제일 긴 음악 제목 -> 재생된 시간이 같을 경우 -> 먼저 입력
        
        // 조건 일치하는 음악 X->'(NONE)'
    
        //m: 음 
        //musicinfos : 100개 이하의 곡 - 음악 시작 시각, 끝난 시각, 음악제목, 악보 정보
        
        
        // 1. 재생된 시각과 끝난 시각을 계산해서 악보를 만든다
        // 2. 같은 문장이 등장하면 길,재생시간, 위치, 제목 (여기서 같은 문장이라는 것은 ABC#의 경우도 생각할 것)
    
        ArrayList<Music> list = new ArrayList<>();
        
        for(int i=0;i<musicinfos.length;i++){
            
            String[] music = musicinfos[i].split(",");
            
            // 시작 시간
            String[] start_time = music[0].split(":");
            int start=  Integer.parseInt(start_time[0])*60 + Integer.parseInt(start_time[1]);
            // 끝나는 시간
            String[] end_time = music[1].split(":");
            int end = Integer.parseInt(end_time[0])*60 + Integer.parseInt(end_time[1]);
           
            
            //재생시간
            int totalTime = end-start;
            if(totalTime> MaxTime) totalTime = MaxTime;
            
            //#을 대체 문자로 바꿔버리기
            m = removeShap(m);
            music[3]=removeShap(music[3]);
            
            // 악보 만들기
            String sheet = makeSheet(totalTime,music[3]);
            
            // 악보에 기억한 음악이 들어있으면
            if(searchM(m,sheet)){
                list.add(new Music(totalTime,i,music[2]));
            }
            
        }
          
        //기억한 음악이 악보에 없는 경우
        if(list.size()==0) return "(None)";
        
        //길이가 내림차순, 순서 오름차순
        Comparator<Music> reversedComparator = Comparator.comparing(Music::getTime).reversed();
        list.sort(reversedComparator.thenComparing(Music::getIndex));
        
     
        return list.get(0).title;
    }
    
    //# 붙어있는 음 대체하기
    static String removeShap(String input){
        
        input=input.replace("C#","H");
        input=input.replace("D#","I");
        input=input.replace("F#","J");
        input=input.replace("G#","K");
        input=input.replace("A#","L");
        
        return input;
    }
    
    
    //악보만들기
    static String makeSheet(int totalTime, String music){
     
        StringBuilder sb = new StringBuilder();
        String sheet="";
        sb.append(music);
        while(true){
            if(totalTime<=sb.length()){
                sheet=sb.substring(0,totalTime);
                break;
            }else{
                sb.append(music);
            }
        }
        
        return sheet ; 
    }
    
    // 기억한 음악이 악보에 있는지 확인
    static boolean searchM(String m, String sheet){
        
        //제거된 개수
        int remove = sheet.length() - sheet.replace(m,"").length();
        
        //제거된 개수가 기억한 음악의 길이와 같거나 크다면 등장한 것이다!
        if(remove>=m.length()) return true;
        
        return false;
        
    }
    
}

reference

https://broduck.tistory.com/6

profile
꾸준하게 Ready, Set, Go!

0개의 댓글