프로그래머스(위클리) | LV.2 교점에 별 만들기 - 구현 문풀 (Java)

728x90

⬛ 프로그래머스(위클리) | LV.2 교점에 별 만들기 - 구현 문풀 (Java)

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제 설명
그림 설명
설명
문제 설명
문제 힌트


💚문제 접근 방식

  • 주어진 직선 정보와 두 직선의 교점 구하는 공식을 활용해서 모든 두 직선 간의 교점을 차례로 구하되, 그 중 (정수로 표현되는) 교점에 한해서 담고, 끝없이 펼쳐진 좌표평면 중 교점을 표현할 정도의 크기로만 잘라서 출력하라는 문제였다.

[주의] long 타입으로 선언한 이유는 A, B, C 각각 (-10^5 ~ 10^5)까지 들어올 수 있는데, 교점 구하는 공식에서 얘들끼리 곱하면 int형 범위를 넘어설 수 있기 때문이다.

   1) 입력으로 들어온 line에 대해 이중for문을 돌면서 모든 직선에 대하여 두 직선씩 교점을 구하고자 시도한다.

 

   2) 문제에서 주어진 교점 공식을 구하기 위해 공통 분모와 각 분자를 구하고 교점공식 대입하여 (정수 교점) list 담음

이때 분모가 0인 경우는 (기울기 같아서 교점X)이므로 분모가 0이 아닌 경우에 한해서 (정수로 표현가능한) 교점만 list에 담는다.

(이와 동시에 min, max 양 끝단의 x, y 좌표 각각을 갱신하며 구해둔다.)

 

   3) boolean[][] 에서 max-min+1 로 표현될 좌표평면 크기 지정하고, * 찍을 값에만 true처리를 할 거다.

 

   4) StringBuilder에 flag값 true, false 조건 나눠서 교점에만 * 찍고 answer를 세팅한다.


💚 제출 코드

import java.util.*;
class Solution {
    
    public String[] solution(int[][] line) {
        String[] answer = {};
        List<long[]> list = new ArrayList<>();
        long minX = Long.MAX_VALUE;
        long maxX = Long.MIN_VALUE;
        long minY = Long.MAX_VALUE;
        long maxY = Long.MIN_VALUE;
        
        //인접한 두 직선에 대한 교점 좌표 구하기 
        for(int i=0; i<line.length; i++){
            long a = line[i][0];
            long b = line[i][1];
            long e = line[i][2];
            
            for(int j=i+1; j<line.length; j++){
                long c = line[j][0];
                long d = line[j][1];
                long f = line[j][2];
                
                //분자 각각 구하고, 공통 분모 구하기 
                long curDown = a*d - b*c;
                
                long xUp = b*f - e*d;
                long yUp = e*c - a*f;
                
                //분모가 0인 경우 두 직선 기울기 평행이라 (교점X)
                if(curDown != 0){
                    double x = xUp / (double) curDown;
                    double y = yUp / (double) curDown;
                    
                    if(x == Math.ceil(x) && y == Math.ceil(y)){ //즉, 정수로 표현되는 좌표에 한해서
                        list.add(new long[] {(long) x, (long) y});
                        //좌표 경계 양끝단 구할 용도 
                        minX = Math.min(minX, (long)x);
                        maxX = Math.max(maxX, (long)x);
                        minY = Math.min(minY, (long)y);
                        maxY = Math.max(maxY, (long)y );
                    }
                }
            }
        }
        
        //list에는 정수표현된 교점 좌표만 담긴 상태
        //-> boolean[][]  에 교점 찍히는 부분만 true 처리
        int N = (int) (maxY - minY + 1);
        int M = (int) (maxX - minX + 1);
        
        boolean[][] flag = new boolean[N][M];
        
        for(long[] points : list){
            int x = (int) (points[0] - minX);//좌표 재정돈
            int y = (int) (points[1] - maxY);
            
            flag[Math.abs(y)][Math.abs(x)] = true;
        }
        
        answer = new String[flag.length];
        
        int i = 0;
        
        for(boolean[] t : flag){
            StringBuilder sb = new StringBuilder();
            for(boolean s : t){
                if(s==true){
                    sb.append("*");
                }else{
                    sb.append(".");
                }
            }
            answer[i] = sb.toString();
            i++;
        }

        return answer;
    }
}

💚회고

전반적인 로직의 구성은 의외로 단순하지만, 완벽히 내 힘으로 풀지는 못해서 아쉽다. 

728x90