728x90

알고리즘을 풀면서 문제를 초기에 구상을 했을 때는, 더 빠른 방법이지 않을까 생각했는데, 직접해보니 오히려 추가 작업만 늘어나게 되었던 경우를 포스팅하려고 합니다.
//  https://school.programmers.co.kr/learn/courses/30/lessons/87389

 

프로그래머스

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

programmers.co.kr

위 문제는 나머지가 1이 되는 수를 찾는 문제입니다.

초기 구상 단계

 

1. 나머지가 1이되는 최소의 수를 구하는 것이기에, 차라리 n-1이 소수인지만 확인 
2. 그렇지 않다면  해당 수를 반환 .. 해당 수의 약수가 존재한다면 최소공약수를 반환
3. 범위는 타겟의 제곱근까지만 확인( 그 이상은 확인할 필요가 없으므로)
이라고 생각했다. 그렇기에 소수를 구하는 에란토스체를 사용하면 런타임을 최소화 할 수 있지 않을까 생각했습니다.

 

우선 간단하게 타겟 수의 제곱근보다 작은수들로 n-1을 나누어 보았습니다.

function solution2(n) {
  const min = n - 1;
  for (let i = 2; i < Math.sqrt(n); i++) {
    if (min % i === 0) {
      return i;
    }
  }
  return min;
}

 

이후 이전에 학습했던 에란토스체를 사용해서 나누어 보았습니다.

 

function solution2(n) {
  const min = n - 1;
  const prime = new Array(n + 1).fill(1);

  for (let i = 2; i < Math.sqrt(n); i++) {
    if (prime[i]) {
      if (min % i === 0) {
        return i;
      }
      // 배수값들 거르는 작업
      for (let j = i ** 2; j <= n; j += i) {
        if (prime[j]) prime[j] = 0;
      }
    }
  }
  return min;
}

 

오히려 더 느려졌네요.. 왜 그럴까요? 에란토스체를 소수를 판별하는 가장 빠른 방법인데?

 

결론부터 말하면 부가적인 작업이 오히려 많이 생겼기 떄문입니다.

 

문제의 목적은 사실 n-1의 최소공약수를 구하는 문제입니다.  n의 제곱근보다 작은 모든 소수를 구한 다음에 나눌 필요가 없는거죠. 

 

소수를 구하는 단계에서는 각각의 수가 소수인지 일일이 확인하는 것보다, 미리 소수의 배수들을 제외시키면 소수인지 판별하기 훨신 쉽습니다.

하지만 이 경우 n-1이 소수인지만 판별하면 되는데, 부가적인 작업이 오히려 더 많이 생긴 것 입니다.
그렇기에 오히려 간단한 첫 번쨰 코드의 성능이 가장 좋았던 것이죠.



추가적으로  위 코드에서는 Math.sqrt의 계산을  반복문 내에서 수행할 필요 없이, 반복문 밖에서 한 번만 계산하도록 최적화 할 수 있습니다.


function solution3(n) {
  const min = n - 1;
  const prime = new Array(n + 1).fill(1);
  const limit = Math.sqrt(n);
  for (let i = 2; i < limit; i++) {
    if (prime[i]) {
      if (min % i === 0) {
        return i;
      }
      // 배수값들 거르는 작업
      for (let j = i ** 2; j <= n; j += i) {
        if (prime[j]) prime[j] = 0;
      }
    }
  }
  return min;
}

 

따라서 첫 번째 정답도 가장 최적화를 한다면 아래 코드가 됩니다.

function solution(n) {
  const min = n - 1;
const limit =  Math.sqrt(n);
  for (let i = 2; i <limit; i++) {
    if (min % i === 0) {
      return i;
    }
  }
  return min;
}

728x90

프로젝트를 하다보면 issue를 통해서 팀원과 소통하는 일이 생긴다.


우리 조는 GITHUB을 통하여서 issue 이름과 내용을 작성하고,  pull request 시에 해당 이슈를 태그하는 방식으로 이슈 추적을 하려고 했다. 하지만 이때 개개인이 다르게 issue를 작성한다면 이슈 내용 파악에 불편함을 느낄 수 있다.

따라서 통일된 Templates를 통해서 가이드라인을 제시한다면 팀원끼리 소통하는데 조금 더 수월할 수 있다.

Issue Templates 생성하기

 

깃헙에서 내 issue를 생성하고 싶은 레퍼지토리에 들어가서 setting을 누르고 스크롤 하면

Features에  Set up templates를 찾을 수 있다.

 

해당 버튼을 누르면 기초 템플릿을 설정할 수 있다.

 

결국 커스텀 가능하지만, 기본적인 모양이 갖춰져 있는 Feature request를 선택하고 수정하는 것을 추천합니다. (버그 수정용 템플릿이라면 위에껄 선택)

 

 

기본적인 양식은 위와 같은데 제목옆에 연필 버튼을 누르면 수정이 가능합니다.

위의 템플릿이 어떤 형식으로 되었는지 볼 수 있습니다. 위 코드와 비교해보면 **이 굵게 한다는것도 알 수 있네요

 

꾸미는 자세한 방법

https://docs.github.com/ko/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax 에서 확인할 수 있습니다.

 


작성을 완료하고 issue를 처음 발행하려고 하면 템플릿 설정창이 뜹니다.

해당 파일을 선택하면  내가 작성했던 템플릿이 issue 작성시마다 불러와 지는것을 확인할 수 있습니다.



 

하지만 이렇게 만들 경우에는
매번 getStarted를 통해서 작성하는 불편함이 생긴다. 레포지토리를 보면 아래와 같은 구조로 되어있다.
(해당 폴더안에 있는 파일들을 자동으로 제안함)

이를 default 값을 미리 설정하고 싶다면 작성했단 이슈 파일명을 issue_template.md 로 변경하고 , 이전에 생성했던 폴더를 제거하면 된다.


pull_request_template 또한 동일한 과정을 거쳐 작업하면 된다.

728x90

이런 모양의  달력을 라이브러리를 통해서 간단하게 만들 수 있다.

 

해당 라이브러리의 깃헙주소는 https://www.npmjs.com/package/fullcalendar 이다.

설치 

해당 라이브러리를 시작하기 위해서는 우선 세 가지를 인스톨 해야한다.

npm install --save  @fullcalendar/core @fullcalendar/react @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/list

npm install --save @fullcalendar/interaction

npm install --save-dev css-loader

  

이후 프로젝트에서 사용하면 된다.

 

저는 프로젝트를 만든 이후 , component 폴더에 달력과 관련 css파일만 추가해서 실행하였습니다.

 

 

이제 코드를 보겠습니다. 

import React, { useRef } from "react";
import FullCalendar from "@fullcalendar/react";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import listMonth from "@fullcalendar/list";
import interactionPlugin from "@fullcalendar/interaction";

import "./Calendar.css";

const Calendar = () => {
  const calendarRef = useRef();
  // event 추가
  const onEventAdd = (e) => {
    const api = calendarRef.current.getApi();
    api.addEvent({
      title: "이사장님과의 약속",
      date: "2023-08-24 12:30",
      constraint: "약속",
    });
  };
  // 이벤트 클릭시
  const eventCLick = (info) => {
    // alert("eventClick");
    // alert(JSON.stringify(info.event.start));

    let date = new Date(info.event.start);
    let year = date.getFullYear();
    let month = date.getMonth();
    let day = date.getDate();
    let hour = date.getHours();
    let minute = date.getMinutes();
    let promise = `날짜 : ${year}${month + 1}${day}${hour}${minute}분
`;
    promise += "제목 : " + info.event.title + "\n";
    promise += "내용 : " + info.event.constraint;
    alert(promise);
  };

  // 날짜를 클릭시
  const handleDateClick = (args) => {
    let date = new Date(args.dateStr);
    let year = date.getFullYear();
    let month = date.getMonth() + 1 + "";
    if (month.length < 2) {
      month = "0" + month;
    }
    let day = date.getDate() + "";
    if (day.length < 2) {
      day = "0" + day;
    }
    let selectDate = year + "-" + month + "-" + day;
    alert(selectDate);
  };

  return (
    <div className="calendar">
      <FullCalendar
        headerToolbar={{
          left: "prev next today", // 좌측버튼
          center: "title",
          end: "dayGridMonth timeGridWeek timeGridDay listMonth",
        }}
        locale={"ko"} // 한국어
        navLinks={true} // 오른쪽 상단의 day 클릭 대신 날짜를 클릭
        businessHours={true} // 주말을 다른 색으로
        plugins={[dayGridPlugin, timeGridPlugin, listMonth, interactionPlugin]}
        initialView="dayGridMonth"
        eventClick={eventCLick}
        ref={calendarRef}
        dateClick={handleDateClick}
        events={[
          {
            title: "점심약속",
            date: new Date(), //'2023-08-16
          },
          {
            title: "미팅",
            start: "2023-08-14", //'2023-08-16 까지 적으면 줄이 김
          },
          {
            title: "미팅2",
            start: "2023-08-14 12:30", //'2023-08-16 까지 적으면 줄이 김
          },

          {
            title: "비지니스",
            start: "2023-08-18 12:30:00",
            constraint: "김사장과 복싱",
            end: "2023-08-20 12:30",
          },
          {
            title: "워크샵",
            start: "2023-08-17 12:30:00",
            constraint: "팔협지 또 일등이야",
            end: "2023-08-22 12:30",
          },
          {
            title: "데이트",
            start: "2023-08-27 12:30:00",
            constraint: "영화관람",
            backgroundColor: "#ff0000",
          },
        ]}
      />

      <br />
      <button onClick={onEventAdd} className="btn btn-primary">
        일정추가
      </button>
    </div>
  );
};

export default Calendar;

약식으로 만든 파일이기 때문에 위와 같이 작성을 하였습니다.
FullCalendar를 제외한 플러그인은 컴퍼넌트가 아니기에 소문자로 import 했고
FullCalendar는 대문자로 import해야합니다

 

그리고 현재는 서버와의 통신없이 코드를 작성하였기에 , 

 const onEventAdd = (e) => {
    const api = calendarRef.current.getApi();
    api.addEvent({
      title: "이사장님과의 약속",
      date: "2023-08-24 12:30",
      constraint: "약속",
    });
  };

에서 임의의 더미데이터를 넣어 작성하였지만, 서버와 연결을 할 거면 axios를 통해서 데이터를 전송하시면 됩니다.

 

이제 라이브러리에 대해 설명하겠습니다.

<FullCalendar
        headerToolbar={{
          left: "prev next today", // 좌측버튼
          center: "title",
          end: "dayGridMonth timeGridWeek timeGridDay listMonth",
        }}
        locale={"ko"} // 한국어
        navLinks={true} // 오른쪽 상단의 day 클릭 대신 날짜를 클릭
        businessHours={true} // 주말을 다른 색으로
        plugins={[dayGridPlugin, timeGridPlugin, listMonth, interactionPlugin]}
        initialView="dayGridMonth"
        eventClick={eventCLick}
        ref={calendarRef}
        dateClick={handleDateClick}
        events={[
          {
            title: "점심약속",
            date: new Date(), //'2023-08-16
          },
          {
            title: "미팅",
            start: "2023-08-14", //'2023-08-16 까지 적으면 줄이 김
          },
          {
            title: "미팅2",
            start: "2023-08-14 12:30", //'2023-08-16 까지 적으면 줄이 김
          },

          {
            title: "비지니스",
            start: "2023-08-18 12:30:00",
            constraint: "김사장과 복싱",
            end: "2023-08-20 12:30",
          },
          {
            title: "워크샵",
            start: "2023-08-17 12:30:00",
            constraint: "팔협지 또 일등이야",
            end: "2023-08-22 12:30",
          },
          {
            title: "데이트",
            start: "2023-08-27 12:30:00",
            constraint: "영화관람",
            backgroundColor: "#ff0000",
          },
        ]}
      />

headerToolbar 의 경우 헤더에 있는 버튼들을 정의해줍니다. 이때 prev 와 next 는 화살표 모양으로 달력이동, today는 현재 날짜로 돌아오게 합니다.  left title right는 해당 버튼들의 위치를 정의하고,  dayGridMonth timeGridWeek timeGridDay listMonth 는 각각 월 주 일 일정리스트별 정렬을 해줍니다.

week을 클릭할 경우

 

locale은 언어 설정,

navlinks는 day대신 날짜 클릭 (false하는게 좋다고 생각합니다), 

businessHours는 주말은 다른색,

plugins에 위에 import한 plugin들을 연결하고,

initial view는 시작시 보여줄 달력의 모양,
dateClick은 달력의 날짜 클릭시 효과,

eventClick은 일정 클릭시 효과입니다.

 

+ Recent posts