미숙한 블로그 주인이 코딩테스트 문제를 풀어가는 과정을 담은 글입니다. 이 풀이가 효율적인 풀이가 아닐 수 있으며, 부정확한 정보가 많이 있을 수 있습니다. 보완해야할 점이 있다면 댓글로 남겨주세요!
https://programmers.co.kr/learn/courses/30/lessons/87377
교점에 별 만들기
문제
Ax + By + C = 0으로 표현할 수 있는 n개의 직선이 주어질 때, 이 직선의 교점 중 정수 좌표에 별을 그리려 합니다.
예를 들어, 다음과 같은 직선 5개를
- 2x - y + 4 = 0
- -2x - y + 4 = 0
- -y + 1 = 0
- 5x - 8y - 12 = 0
- 5x + 8y + 12 = 0
좌표 평면 위에 그리면 아래 그림과 같습니다.
이때, 모든 교점의 좌표는 (4, 1), (4, -4), (-4, -4), (-4, 1), (0, 4), (1.5, 1.0), (2.1, -0.19), (0, -1.5), (-2.1, -0.19), (-1.5, 1.0)입니다. 이 중 정수로만 표현되는 좌표는 (4, 1), (4, -4), (-4, -4), (-4, 1), (0, 4)입니다.
만약 정수로 표현되는 교점에 별을 그리면 다음과 같습니다.위의 그림을 문자열로 나타낼 때, 별이 그려진 부분은 *, 빈 공간(격자선이 교차하는 지점)은 .으로 표현하면 다음과 같습니다.
"..........." ".....*....." "..........." "..........." ".*.......*." "..........." "..........." "..........." "..........." ".*.......*." "..........."
이때 격자판은 무한히 넓으니 모든 별을 포함하는 최소한의 크기만 나타내면 됩니다.
따라서 정답은
"....*...." "........." "........." "*.......*" "........." "........." "........." "........." "*.......*"
입니다.
직선 A, B, C에 대한 정보가 담긴 배열 line이 매개변수로 주어집니다. 이때 모든 별을 포함하는 최소 사각형을 return 하도록 solution 함수를 완성해주세요.
제한사항
- line의 세로(행) 길이는 2 이상 1,000 이하인 자연수입니다.
- line의 가로(열) 길이는 3입니다.
- line의 각 원소는 [A, B, C] 형태입니다.
- A, B, C는 -100,000 이상 100,000 이하인 정수입니다.
- 무수히 많은 교점이 생기는 직선 쌍은 주어지지 않습니다.
- A = 0이면서 B = 0인 경우는 주어지지 않습니다.
- 정답은 1,000 * 1,000 크기 이내에서 표현됩니다.
- 별이 한 개 이상 그려지는 입력만 주어집니다.
풀이
입출력 예시
풀이
먼저 교점이 존재하는지, 존재하면 어디인지를 확인할 방법은 문제의 마지막에 주어져있다.
AD - BC = 0인 경우 두 직선은 평행 또는 일치한다.
이를 이용해 AD - BC 가 0이 아니면서 교점이 정수일 때에만 그 위치에 '*'을 찍어준다. answer에 표현할 때에는 x는 작은 값, y는 큰 값부터 적용되어야 한다.
주의할 사항은 A, B, C가 -100,000 이상 100,000 이하의 수가 들어온다는 점이다. 즉, 모든 곱셈의 결과가 int 형의 최댓값(또는 최솟값)을 넘기는 경우가 발생할 수 있다는 점이다. 그러므로, long long 형을 사용해 오버플로우(또는 언더플로우)에 대비해야 한다. (27번과 28번이 아마 이 부분에 관한 테스트 케이스 였던 것 같다.)
#include <string>
#include <vector>
#include <set>
#include <utility>
#include <algorithm>
using namespace std;
vector<string> solution(vector<vector<int>> line) {
vector<string> answer;
set<pair<long long, long long>> pos;
for (int i = 0; i < line.size() - 1; i++) {
for (int j = i + 1; j < line.size(); j++) {
long long AD_BC = (long long)line[i][0] * line[j][1] - (long long)line[i][1] * line[j][0];
if (AD_BC != 0) {
double x = ((double)line[i][1] * line[j][2] - (double)line[i][2] * line[j][1]) / AD_BC;
double y = ((double)line[i][2] * line[j][0] - (double)line[i][0] * line[j][2]) / AD_BC;
if (x - (long long)x == 0 && y - (long long)y == 0) {
pos.insert({ x, y });
}
}
}
}
long long min_x = 9223372036854775807;
long long max_x = -9223372036854775808;
long long min_y = 9223372036854775807;
long long max_y = -9223372036854775808;
for (const auto& p : pos) {
min_x = min(p.first, min_x);
min_y = min(p.second, min_y);
max_x = max(p.first, max_x);
max_y = max(p.second, max_y);
}
for (long long y = min_y; y <= max_y; y++) {
string tmp = "";
for (long long x = min_x; x <= max_x; x++) {
tmp += ".";
}
answer.push_back(tmp);
}
for (const auto& p : pos) {
answer[abs(p.second - max_y)][abs(p.first - min_x)] = '*';
}
return answer;
}
'코딩 테스트(Coding test) > Lv. 2' 카테고리의 다른 글
[프로그래머스/C++] 멀리 뛰기 (0) | 2022.06.02 |
---|---|
[프로그래머스/C++] 숫자 블록 (0) | 2022.06.02 |
[프로그래머스/C++] 양궁대회 (0) | 2022.05.25 |
[프로그래머스/C++] 피로도 (0) | 2022.05.24 |
[프로그래머스/C++] 주차 요금 계산 (0) | 2022.05.12 |