주녘공부일지

[프로그래머스 C#] Lv.2 교점에 별 만들기 본문

Programmers - C#/CodingTest Lv.2

[프로그래머스 C#] Lv.2 교점에 별 만들기

주녘 2024. 3. 18. 18:56
728x90

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

 

프로그래머스

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

programmers.co.kr

1. 정답코드 및 핵심 아이디어, 유의사항

주어진 직선 그래프들의 정수 교점 좌표를 구하는 문제

- 두개의 직선 그래프의 교점을 구하는 방법은 문제에 제시됨

- 무수히 많은 교점을 가지는 직선 그래프는 주어지지 않음

 

풀이 순서

1. 정수 좌표인 교점을 구하여 list에 담기

 

2. 받은 list들의 각 교점 좌표의 최소, 최대 값을 구함 ( 격자판 범위 구하기 )

 - 최소 값이 무조건 0이 되지 않을 수 있음!

 

3. 구한 좌표 범위를 가지고 bool타입 2차원 배열을 세팅

 - 교점이 있을 경우에 true

 - 인덱스에 맞춰 최소 값을 0으로 만들어주어야 함

 

4. 만들어진 bool타입 2차원 배열을 가지고 출력할 격자판 배열을 구성

 

+ 자료형의 범위 벗어남 주의!

- 주어진 케이스가 만약 주어진 범위의 최대 값으로만 주어지는 경우를 생각해야 함!

 

주석 참조

    using System;
    using System.Text;
    using System.Collections.Generic;

    public class Solution
    {
        // 교점의 위치 (y, x)
        public class Pos
        {
            public int y;
            public int x;
            public Pos(int y, int x)
            {
                this.y = y;
                this.x = x;
            }
        }

        public string[] solution(int[,] line)
        {
            var list = new List<Pos>(); // 교점좌표모음

            // 교점 좌표 받아오기
            for (int i = 0; i < line.GetLength(0); i++)
            {
                for (int j = i + 1; j < line.GetLength(0); j++)
                {
                    Pos pos = Function(line[i, 0], line[i, 1], line[i, 2], line[j, 0], line[j, 1], line[j, 2]);
                    if (pos != null)
                        list.Add(pos);
                }
            }

            // 출력할 격자판의 범위 구하기
            int minY = list[0].y, maxY = list[0].y, minX = list[0].x, maxX = list[0].x;
            foreach (Pos p in list)
            {
                minY = Math.Min(minY, p.y);
                maxY = Math.Max(maxY, p.y);
                minX = Math.Min(minX, p.x);
                maxX = Math.Max(maxX, p.x);
            }

            // 가장 작은 수를 0으로 만드는 기준으로 변경 (인덱스 맞추기)
            maxY -= minY;
            maxX -= minX;
            for (int i = 0; i < list.Count; i++)
            {
                list[i].y -= minY;
                list[i].x -= minX;
            }

            // 교점이 존재하는 좌표 = true
            var boolArray = new bool[maxY + 1, maxX + 1];
            foreach (Pos p in list)
                boolArray[p.y, p.x] = true;

            // 세팅된 정보를 주어진 조건에 맞춰 격자판으로 세팅
            var answerList = new List<string>();
            for (int y = 0; y < boolArray.GetLength(0); y++)
            {
                var sb = new StringBuilder();
                for (int x = 0; x < boolArray.GetLength(1); x++)
                    sb.Append(boolArray[y, x] ? "*" : ".");

                answerList.Add(sb.ToString());
            }

            //역순으로 담기게 되므로 뒤집기
            answerList.Reverse();
            return answerList.ToArray();
        }

        // 교점의 정수 좌표를 반환하는 메서드 (ax + by + e = 0, cx + dy + f = 0)
        // 없을 경우 null을 반환함
        public Pos Function(long a, long b, long e, long c, long d, long f)
        {
            // 문제 참고사항에 주어진 교점 구하는 공식 재료(?)
            long num = (a * d) - (b * c);
            long y1 = (e * c) - (a * f);
            long x1 = (b * f) - (e * d);

            // 교점이 없는 경우
            if (num == 0)
                return null;

            // 정수 좌표를 지나지 않는 경우
            if (y1 % num != 0 || x1 % num != 0)
                return null;

            // 교점 좌표 구하기
            int y = (int)(y1 / num);
            int x = (int)(x1 / num);

            return new Pos((int)y, (int)x);
        }
    }

+

728x90