[js] 평행

sookyoung.k·2024년 7월 16일
1
post-thumbnail

점 네 개의 좌표를 담은 이차원 배열 dots가 다음과 같이 매개변수로 주어집니다.

  • [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]

주어진 네 개의 점을 두 개씩 이었을 때, 두 직선이 평행이 되는 경우가 있으면 1을 없으면 0을 return 하도록 solution 함수를 완성해보세요.

제한사항

  • dots의 길이 = 4
  • dots의 원소는 [x, y] 형태이며 x, y는 정수입니다.
    - 0 ≤ x, y ≤ 100
  • 서로 다른 두개 이상의 점이 겹치는 경우는 없습니다.
  • 두 직선이 겹치는 경우(일치하는 경우)에도 1을 return 해주세요.
  • 임의의 두 점을 이은 직선이 x축 또는 y축과 평행한 경우는 주어지지 않습니다.

나의 풀이

const isParallel = (dot) => {
    let [dot1, dot2, dot3, dot4] = dot;
    // dot1과 dot2를 이은 선분의 기울기
    let line1 = Math.abs(dot2[1]-dot1[1]) / Math.abs(dot2[0] - dot1[0]);
    // dot3과 dot4를 이은 선분의 기울기
    let line2 = Math.abs(dot4[1]-dot3[1]) / Math.abs(dot4[0]-dot3[0]);

    return line1 === line2 ? true : false;
}

function solution(dots) {
    // x좌표를 기준으로 배열을 정렬하기 
    let x = dots.sort((a, b) => {
        a = a[0];
        b = b[0];
        return a - b;
    });
    // y좌표를 기준으로 배열을 정렬하기 
    let y = dots.sort((a, b) => {
        a = a[1];
        b = b[1];
        return a - b;
    });

    return isParallel(x) ? 1 : isParallel(y) ? 1 : 0;
}
  1. isParallel() 이라는 기울기 판단 함수를 만들었다.
    • 4개의 점을 받아 서로 평행을 이루는지 확인한다.
    • 선분의 기울기를 계산하여 두 선분의 기울기가 같은지 확인한다.
    • 기울기가 같으면 평행하다고 판단하여 true를, 그렇지 않으면 false를 반환한다.

* 개선사항
자... 먼저! Math.abs()는 필요가 없다. 선분의 기울기가 음수여도 평행한 선분으로 판단될 수 있기 때문이다. 그리고 삼항연산자의 사용도 불필요하다.

const isParallel = (dot) => {
    let [dot1, dot2, dot3, dot4] = dot;
    // dot1과 dot2를 이은 선분의 기울기
    let line1 = (dot2[1] - dot1[1]) / (dot2[0] - dot1[0]);
    // dot3과 dot4를 이은 선분의 기울기
    let line2 = (dot4[1] - dot3[1]) / (dot4[0] - dot3[0]);

    return line1 === line2;
}

이렇게 수정해주어도 좋을 것.

  1. x좌표와 y좌표를 기준으로 정렬한다. isParallel() 함수를 호출하여 x배열과 y배열이 각각 평행한지 확인한 후 둘 중 하나라도 평행하면 1, 둘 다 평행하지 않으면 0을 반환한다.

* 정렬의 문제
그런데 말입니다...! 정렬은 필요가 없다고 한다. 당시에 생각할 때는 정렬이 필요할 거라고 생각했는데... 왜 정렬을 안 해도 되는거지...?

먼저 일차적으로 sort()를 두 번 사용한 것은 정말 틀린 풀이였다. sort()는 원본 배열을 바꾼다! 몇 번 얘기 들었었는데도 늘 까먹음 ㅠ 이래서 배열 메서드 한 번 정리를 싹 해야 하는데 시간이 안 난다. 그렇기 때문에 배열을 한 번만 써도 된다.

처음엔 정렬을 아예 없애도 되지 않겠냐는 제안을 받았다.

function solution(dots) {
    // x좌표를 기준으로 배열을 정렬할 필요 없음
    // let x = dots.sort((a, b) => {
    //     a = a[0];
    //     b = b[0];
    //     return a - b;
    // });
    // y좌표를 기준으로 배열을 정렬할 필요 없음
    // let y = dots.sort((a, b) => {
    //     a = a[1];
    //     b = b[1];
    //     return a - b;
    // });

    return isParallel(dots) ? 1 : 0;
}

실제로 이렇게 제출했을 때 문제없이 통과하긴 했다. 하지만 이건 선분끼리 겹치지 않을 수 있도록 dots 배열이 신경 써서 주어졌을 때(?) 가능한 거 아닐까?

예를 들어 [[0, 0], [5, 4], [2, 1], [3, 3]]이 주어진다고 생각했을 때 주어진 dot의 순서대로 선분을 이을 경우 선분끼리 교차해서 평행이라고 판단하지 못하는 경우가 생긴다. 문제 자체에서는 주어진 네 개의 점을 두 개씩 이은다고 써있는 것이 그냥 순서대로 잇는다는 표현이었는지 몰라도, 모든 경우의 수를 확인해야 한다면 이것을 정렬하여 푸는 것이 맞다는 생각을 했다.

그래서 나의 최종 답안은 이렇게 정리하도록 하겠다!

const isParallel = (dots) => {
    let [dot1, dot2, dot3, dot4] = dot;
    // dot1과 dot2를 이은 선분의 기울기
    let line1 = (dot2[1] - dot1[1]) / (dot2[0] - dot1[0]);
    // dot3과 dot4를 이은 선분의 기울기
    let line2 = (dot4[1] - dot3[1]) / (dot4[0] - dot3[0]);

    return line1 === line2;
}

function solution(dots) {
    let x = dots.sort((a, b) => {
        a = a[0];
        b = b[0];
        return a - b;
    });

    return isParallel(x) ? 1 : 0;
}

다른 풀이 1

function solution(dots) {
    if (calculateSlope(dots[0], dots[1]) === calculateSlope(dots[2], dots[3]))
        return 1;
    if (calculateSlope(dots[0], dots[2]) === calculateSlope(dots[1], dots[3]))
        return 1;
    if (calculateSlope(dots[0], dots[3]) === calculateSlope(dots[1], dots[2]))
        return 1;
    return 0;
}

function calculateSlope(arr1, arr2) {
    return (arr2[1] - arr1[1]) / (arr2[0] - arr1[0]);
}

이 풀이는 isParallel 함수를 사용하지 않고도 동일한 결과를 얻을 수 있다.

  1. 주어진 4개의 점을 모든 가능한 조합으로 두 개씩 선택한다.
  2. caculateSlope() 함수를 통해서 각 두 점 사이의 기울기를 계산한다.
  3. 세 가지 경우의 기울기를 비교한다.
    • 첫 점과 두 점, 그리고 마지막 두 점
    • 첫 점과 세 번째 점, 나머지 두 점
    • 첫 점과 마지막 점, 나머지 두 점
  4. 위의 세 가지 경우 중 하나라도 만족하면 1을 반환하고 그렇지 않으면 0을 반환한다.

점들의 순서를 정렬할 필요 없이, 가능한 모든 경우를 검사하여 평행을 확인한다.
이게 더 간단하군...!

다른 풀이 2

function solution(dots) {
    const leans = []

    for(let i = 0; i < dots.length; i++) {
        const dotA = dots[i];
        for(let j = i + 1; j < dots.length; j++) {
            const dotB = dots[j]
            const lean = (dotB[1] - dotA[1])  / (dotB[0] - dotA[0])

            if(leans.includes(lean)) return 1
            else leans.push(lean)
        }
    }

    return 0;
}
  1. 모든 쌍의 기울기를 계산한다.
  2. 계산한 기울기를 leans 배열에 저장한다.
  3. 기울기를 계산할 때마다 leans 배열에 이미 같은 기울기가 있는지 확인한다.
  4. 같은 기울기가 있다면 1을 반환하고 그렇지 않다면 0을 반환한다.

훨씬 더 효율적으로, 모든 경우를 검사하지 않고도 답을 낼 수 있었다! 굿!

profile
영차영차 😎

0개의 댓글