문자열 밀기

문자열 "hello"에서 각 문자를 오른쪽으로 한 칸씩 밀고 마지막 문자는 맨 앞으로 이동시키면 "ohell"이 됩니다. 이것을 문자열을 민다고 정의한다면 문자열 AB가 매개변수로 주어질 때, A를 밀어서 B가 될 수 있다면 밀어야 하는 최소 횟수를 return하고 밀어서 B가 될 수 없으면 -1을 return 하도록 solution 함수를 완성해보세요.

function solution(A, B) {
    let answer = 0;
    let aArr = A.split('');

    for(let i = 0; i < A.length; i++) {
        if(aArr.toString().replaceAll(',', '') === B) break;

        aArr.unshift(aArr[A.length - 1]);
        aArr.pop();
        answer += 1;

        if(answer === A.length) answer = -1;
    }

    return answer;
}

종이 자르기

머쓱이는 큰 종이를 1 x 1 크기로 자르려고 합니다. 예를 들어 2 x 2 크기의 종이를 1 x 1 크기로 자르려면 최소 가위질 세 번이 필요합니다.

정수 M, N이 매개변수로 주어질 때, M x N 크기의 종이를 최소로 가위질 해야하는 횟수를 return 하도록 solution 함수를 완성해보세요.

function solution(M, N) {
    var answer = 0;
    return (M - 1) + ((N - 1) * M);
}

연속된 수의 합

연속된 세 개의 정수를 더해 12가 되는 경우는 3, 4, 5입니다. 두 정수 numtotal이 주어집니다. 연속된 수 num개를 더한 값이 total이 될 때, 정수 배열을 오름차순으로 담아 return하도록 solution함수를 완성해보세요.

function solution(num, total) {
    let div = Math.floor(total / num);
    let sum = 0;

    while(true) {
        for(let i = 0; i < num; i++) {
            sum += div + i;
        }

        if(sum === total) {
            break;
        } else if(sum < total) {
            div += 1;
            sum = 0;
        } else if(sum > total) {
            div -= 1;
            sum = 0;
        }
    }

    let answer = [];

    for(let i = 0; i < num; i++) {
        answer.push(div + i);
    }

    return answer;
}

다음에 올 숫자

등차수열 혹은 등비수열 common이 매개변수로 주어질 때, 마지막 원소 다음으로 올 숫자를 return 하도록 solution 함수를 완성해보세요.

function solution(common) {
    /*
     * 등차수열 혹은 등비수열이 아닌 경우가 없고,
     * 등비수열인 경우 공비는 0이 아닌 정수
     */
    return common[1] - common[0] === common[2] - common[1] ? common[common.length - 1] + (common[1] - common[0]) : common[common.length - 1] * (common[1] / common[0]);
}

중간중간 일정 때문에 못푸는 날이 있었는데, 아무튼 프로그래머스 입문캘린더 종료.

'코딩테스트' 카테고리의 다른 글

뇌주름 살리기 - 21  (0) 2025.02.08
뇌주름 살리기 - 20  (0) 2025.02.06
뇌주름 살리기 - 19  (0) 2025.02.04
뇌주름 살리기 - 18  (0) 2025.02.02
뇌주름 살리기 - 17  (0) 2025.01.31

비즈니스 요구사항 정리

데이터는 회원ID와 이름, 기능은 회원 등록과 조회만 있고 아직 DB가 선정되지 않은 가상의 시나리오이다.

일반적인 웹 애플리케이션의 계층 구조이다.

  • Controller : 웹 MVC의 컨트롤러 역할을 한다.
  • Service : 핵심 비즈니스 로직을 구현한다.
  • Repository : DB에 접근하며, 도메인 객체를 DB에 저장하고 관리한다.
  • Domain : 비즈니스 도메인 객체(예 : 회원, 주문, 쿠폰 등)로 주로 DB에 저장하고 관리한다.

클래스 의존 관계이다. 아직 DB가 선정되지 않아 인터페이스로 구현 클래스를 변경할 수 있도록 설계하며, DB는 RDB, NoSQL 등 다양한 저장소를 고민 중인 상황이다. 개발 진행을 위해 초기 개발 단계에서는 구현체로 가벼운 메모리 기반의 데이터 저장소를 사용한다. 여기서 인터페이스는 '클래스가 따라야 할 설계도' 역할로 다음과 같은 특징을 가진다.

  • 구성 요소
    • 추상 메소드 : 인터페이스에 선언된 메소드는 기본적으로 abstract이며, 구현 클래스에서 반드시 구현해야 한다.
    • 상수 : 인터페이스에 선언된 변수는 자동으로 public static final이 된다.
    • 기타 메소드 : Java 8 부터 default 메소드와 static 메소드를 포함할 수 있다.
  • 다중 상속 지원 : 클래스는 하나의 부모 클래스만 상속할 수 있지만, 인터페이는 여러개를 구현할 수 있다.
  • 객체 생성 불가 : 인터페이스 자체로는 객체를 생성할 수 없으며, 이를 구현한 클래스만 인스턴스화가 가능하다.
  • 유연한 참조 : 인터페이스 타입의 참조변수를 통해 구현 객체를 다룰 수 있어, 코드 변경 없이 다양한 객체를 교체할 수 있다.

회원 도메인과 리포지토리 만들기

Member.java
package hello.hello_spring.domain;

public class Member {

    private Long id;
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}
MemberRepository.java
package hello.hello_spring.repository;

import hello.hello_spring.domain.Member;

import java.util.List;
import java.util.Optional;

public interface MemberRepository {
    //저장
    Member save(Member member);
    //Id로 찾기
    Optional<Member> findById(Long id);
    //이름으로 찾기
    Optional<Member> findByName(String name);
    //모든 회원 찾기
    List<Member> findAll();
}
MemoryMemberRepository.java
package hello.hello_spring.repository;

import hello.hello_spring.domain.Member;

import java.util.*;

public class MemoryMemberRepository implements MemberRepository {

    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L;

    @Override
    public Member save(Member member) {
        member.setId(++sequence);
        store.put(member.getId(), member);
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        return Optional.ofNullable(store.get(id));
    }

    @Override
    public Optional<Member> findByName(String name) {
        return store.values().stream()
                .filter(member -> member.getName().equals(name))
                .findAny();
    }

    @Override
    public List<Member> findAll() {
        return new ArrayList<>(store.values());
    }
}

회원 리포지토리 테스트 케이스 작성

MemoryMemberRepositoryTest.java
public class MemoryMemberRepositoryTest {

    MemoryMemberRepository repository = new MemoryMemberRepository();

    @AfterEach
    public void afterEach() {
        repository.clearStore();
    }

    @Test
    public void save() {
        Member member = new Member();
        member.setName("spring");

        repository.save(member);

        Member result = repository.findById(member.getId()).get();
        assertThat(member).isEqualTo(result);
    }

    @Test
    public void findByName() {
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring1");
        repository.save(member2);

        Member result = repository.findByName("spring1").get();

        assertThat(result).isEqualTo(member1);
    }

    @Test
    public void findAll() {
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring1");
        repository.save(member2);

        List<Member> result = repository.findAll();

        assertThat(result.size()).isEqualTo(2);
    }
}

JUnit을 활용한 테스트이다. main 디렉토리 아래가 아닌 test 디렉토리 아래에 테스트를 위한 클래스를 작성하면 된다. 테스트 메소드가 여러개 있을 때 코드에 작성된 대로 순차적으로 실행되지 않기 때문에 변수 등에 저장된 값에 의해 의도치 않은 실패가 발생할 수 있다. 이를 방지하기 위해 @AfterEach 어노테이션을 통해 각 테스트 메소드가 종료되면 실행하는 메소드를 작성하면 된다. 여기서는 HashMap을 clear한다.

테스트는 언제나 중요하며, 개발 → 테스트가 아닌 반대의 경우도 있다. 이를 테스트 주도 개발(Test-Driven Development, TDD)라고 한다. TDD는 테스트 코드를 먼저 작성한 후 이를 통과하는 실제 코드를 구현하는 방식이다.코드 품질 향상, 유지보수 용이성 등의 장점이 있으면서 초기 시간 투자 증가, 학습 곡선 등의 단점도 있다.

회원 서비스 개발

MemberService.java
public class MemberService {

    private final MemberRepository memberRepository = new MemoryMemberRepository();

    //회원 가입
    public Long join(Member member) {
        //중복 회원 불가
        validateDuplicateMember(member);
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
            .ifPresent(m -> {
                throw new IllegalStateException("이미 존재하는 회원입니다.");
            });
    }

    //전체 회원 조회
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }

    //특정 회원 조회
    public Optional<Member> findOne(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

서비스는 실제 비즈니스 로직을 구현한다.

회원 서비스 테스트

클래스에 대해 테스트 클래스를 쉽게 생성하는 방법은 윈도우 기준 Ctrl + Shift + T 단축키를 누르면 된다.

MemberService.java
class MemberServiceTest {

    MemberService memberService;
    MemoryMemberRepository memberRepository;

    @BeforeEach
    public void beforeEach() {
        memberRepository = new MemoryMemberRepository();
        memberService = new MemberService(memberRepository);
    }

    @AfterEach
    public void afterEach() {
        memberRepository.clearStore();
    }

    @Test
    void 회원가입() {
        //given
        Member member = new Member();
        member.setName("hello");
        //when
        Long saveId = memberService.join(member);

        //then
        Member findMember = memberService.findOne(saveId).get();
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }

    @Test
    public void 중복회원가입() {
        //given
        Member member1 = new Member();
        member1.setName("spring");

        Member member2 = new Member();
        member2.setName("spring");

        //when
        memberService.join(member1);
        IllegalStateException e = Assertions.assertThrows(IllegalStateException.class, () -> memberService.join(member2));

        assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
        /*
        try {
            memberService.join(member2);
            fail();
        } catch (IllegalStateException e) {
            assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
        }
        */
    }

    @Test
    void 전체회원조회() {
        Member member1 = new Member();
        member1.setName("spring1");
        memberRepository.save(member1);

        Member member2 = new Member();
        member2.setName("spring1");
        memberRepository.save(member2);

        List<Member> result = memberRepository.findAll();

        assertThat(result.size()).isEqualTo(2);
    }

    @Test
    void 회원조회() {
        Member member1 = new Member();
        member1.setName("spring1");
        memberRepository.save(member1);

        Member result = memberRepository.findByName("spring1").get();

        assertThat(result).isEqualTo(member1);
    }
}

테스트를 작성할 때는 given(어떤 환경에서), when(어떤 조건이 발생했을때), then(어떤 결과가 나오는지)의 3단계로 작성하면 쉽다. @BeforeEach 어노테이션으로 테스트 시에도 같은 MemberRepository를 사용하기 위해 의존성 주입 형태로 변경했다. 의존성 주입(Dependency Injection, DI)은 객체 간의 의존 관계를 외부에서 주입하여 관리하는 설계 패턴이다. 의존성 주입에 대해서는 다음에 자세히 알아보겠다.

'스터디 > Spring' 카테고리의 다른 글

Spring 스터디 - 6  (0) 2025.02.18
Spring 스터디 - 5  (0) 2025.02.17
Spring 스터디 - 4  (0) 2025.02.16
Spring 스터디 - 2  (0) 2025.02.10
Spring 스터디 - 1  (0) 2025.02.04

정적 컨텐츠

정적 컨텐츠(Static Content)는 기본적으로 /static 경로 아래에 있는 파일을 그대로 보여준다.

 

index.html을 호출하면 먼저 Controller에서 매핑된 게 있는지 확인하고, 없으면 /static에서 확인한다.
정정 컨텐츠는 프로그램(계산한 값을 가진다거나 등) 할 수 없다.

MVC와 템플릿 엔진

MVC는 Model, View, Controller의 각 앞 글자를 딴 것이다.

  • Controller
//Controller
@Controller
public class HelloController {

    @GetMapping("hello")
    public String hello(Model model) {
        model.addAttribute("data", "hello");
        return "hello";
    }
}
  • View
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Hello</title>
</head>
<body>
<p th:text="'안녕하세요. ' + ${data}">안녕하세요. 손님</p>
</body>
</html>

View는 보여지는 역할이며, Model이나 Controller는 내부에서 비즈니스 로직을 처리하는 역할이다.

    @GetMapping("hello-mvc")
    public String helloMvc(@RequestParam("name") String name, Model model) {
        model.addAttribute("name", name);
        return "hello-template";
    }

/hello-mvc?name=hong을 호출하면 Controller에서 hello-mvc와 매핑된 걸 찾고, 입력 받은 name 파라미터를 받아서 hello-template로 View에전달하면, View는 ${name}을 파라미터로 치환한다. 여기서 템플릿 엔진인 Thymeleaf가 템플릿 양식과 데이터를 결합한 최종 HTML을 생성해서 클라이언트에 전달하는 방식이다.

API

@GetMapping("hello-api")
    @ResponseBody
    public Hello helloApi(@RequestParam("name") String name) {
        Hello hello = new Hello();
        hello.setName(name);
        return hello;
    }

    static class Hello {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

@ResponseBody 어노테이션을 사용하면 위 템플릿 엔진과 다르게 HTTP Body에 JSON 형식의 데이터가 그대로 전달된다. /hello-api?name=hong을 호출하면 Controller에서 hello-api와 매핑된 걸 찾고, @ResponseBody를 확인하면 viewResolver 대신 HttpMessageConverter가 동작하면서 JSON 형식으로 전달하는 것이다.

'스터디 > Spring' 카테고리의 다른 글

Spring 스터디 - 6  (0) 2025.02.18
Spring 스터디 - 5  (0) 2025.02.17
Spring 스터디 - 4  (0) 2025.02.16
Spring 스터디 - 3  (0) 2025.02.12
Spring 스터디 - 1  (0) 2025.02.04

치킨 쿠폰

프로그래머스 치킨은 치킨을 시켜먹으면 한 마리당 쿠폰을 한 장 발급합니다. 쿠폰을 열 장 모으면 치킨을 한 마리 서비스로 받을 수 있고, 서비스 치킨에도 쿠폰이 발급됩니다. 시켜먹은 치킨의 수 chicken이 매개변수로 주어질 때 받을 수 있는 최대 서비스 치킨의 수를 return하도록 solution 함수를 완성해주세요.

function solution(chicken) {
    let answer = 0;

    const coupon = function(x) {
        if(x < 10) return 0;
        console.log(x);
        return Math.floor(x / 10) + coupon(Math.floor(x / 10) + (x % 10));
    }

    return coupon(chicken);
}

이진수 더하기

이진수를 의미하는 두 개의 문자열 bin1bin2가 매개변수로 주어질 때, 두 이진수의 합을 return하도록 solution 함수를 완성해주세요.

function solution(bin1, bin2) {
    let answer = '';
    let bin = Number('0b' + bin1) + Number('0b' + bin2);

      //2진수 변환
    while(bin > 0) {
        answer += (bin % 2).toString();
        bin = Math.floor(bin / 2);
    }

    let binStr = answer.split('').reverse().toString().replaceAll(',', '');
      //0은 0으로 만들기
    if(binStr === '') binStr = '0';

    return binStr[0] === 0 && binStr.length > 1 ? binStr.splice(1, -1) : binStr;
}

A로 B 만들기

문자열 beforeafter가 매개변수로 주어질 때, before의 순서를 바꾸어 after를 만들 수 있으면 1을, 만들 수 없으면 0을 return 하도록 solution 함수를 완성해보세요.

function solution(before, after) {
    return before.split('').sort().toString() === after.split('').sort().toString() ? 1 : 0;
}

k의 개수

1부터 13까지의 수에서, 1은 1, 10, 11, 12, 13 이렇게 총 6번 등장합니다. 정수 i, j, k가 매개변수로 주어질 때, i부터 j까지 k가 몇 번 등장하는지 return 하도록 solution 함수를 완성해주세요.

function solution(i, j, k) {
    let answer = 0;

    for(let n = i; n <= j; n++) {
        answer += n.toString().split('').filter((x) => x === k.toString()).length;
    }

    return answer;
}

'코딩테스트' 카테고리의 다른 글

뇌주름 살리기 - 22 (입문캘린더 종료)  (0) 2025.02.16
뇌주름 살리기 - 20  (0) 2025.02.06
뇌주름 살리기 - 19  (0) 2025.02.04
뇌주름 살리기 - 18  (0) 2025.02.02
뇌주름 살리기 - 17  (0) 2025.01.31

등수 매기기

영어 점수와 수학 점수의 평균 점수를 기준으로 학생들의 등수를 매기려고 합니다. 영어 점수와 수학 점수를 담은 2차원 정수 배열 score가 주어질 때, 영어 점수와 수학 점수의 평균을 기준으로 매긴 등수를 담은 배열을 return하도록 solution 함수를 완성해주세요.

function solution(score) {
    //기존 인덱스와 평균을 가진 배열로 바꾸고 평균을 기준으로 정렬
    let scoreSort = score.map(function (x, idx) {
        return [idx, (x[0] + x[1]) / 2]
    }).sort((x, y) => y[1] - x[1]);

    let answer = new Array(score.length);
    let rank = 1;
    let rankDup = 0;

    for(let i = 0; i < scoreSort.length - 1; i++) {
        answer[scoreSort[i][0]] = rank;

        //중복되면 중복카운트만 올리고, 
        //다음 숫자가 달라지면 중복카운트도 같이 더하기
        if(scoreSort[i][1] === scoreSort[i + 1][1]) {
            rankDup += 1;
        } else {
            rank += 1 + rankDup;
            rankDup = 0;
        }
    }

    answer[scoreSort[scoreSort.length - 1][0]] = rank;

    return answer;
}

옹알이 (1)

머쓱이는 태어난 지 6개월 된 조카를 돌보고 있습니다. 조카는 아직 "aya", "ye", "woo", "ma" 네 가지 발음을 최대 한 번씩 사용해 조합한(이어 붙인) 발음밖에 하지 못합니다. 문자열 배열 babbling이 매개변수로 주어질 때, 머쓱이의 조카가 발음할 수 있는 단어의 개수를 return하도록 solution 함수를 완성해주세요.

function solution(babbling) {
    //네 가지 발음을 공백으로 치환하고,
    //남아있는게 없다면 발음할 수 있는 단어
    return babbling.map((x) => x.replaceAll(/(aya)|(ye)|(woo)|(ma)/g, '')).filter((x) => x === '').length;
}

로그인 성공?

머쓱이는 프로그래머스에 로그인하려고 합니다. 머쓱이가 입력한 아이디와 패스워드가 담긴 배열 id_pw와 회원들의 정보가 담긴 2차원 배열 db가 주어질 때, 다음과 같이 로그인 성공, 실패에 따른 메시지를 return하도록 solution 함수를 완성해주세요.

  • 아이디와 비밀번호가 모두 일치하는 회원정보가 있으면 "login"을 return합니다.
  • 로그인이 실패했을 때 아이디가 일치하는 회원이 없다면 “fail”를, 아이디는 일치하지만 비밀번호가 일치하는 회원이 없다면 “wrong pw”를 return 합니다.
function solution(id_pw, db) {
    let answer = {};

    //객체로 만들기
    for(let i of db) {
        answer[i[0]] = i[1];
    }

    return answer[id_pw[0]] === id_pw[1] ? 'login' : answer[id_pw[0]] === undefined ? 'fail' : 'wrong pw';
}

'코딩테스트' 카테고리의 다른 글

뇌주름 살리기 - 22 (입문캘린더 종료)  (0) 2025.02.16
뇌주름 살리기 - 21  (0) 2025.02.08
뇌주름 살리기 - 19  (0) 2025.02.04
뇌주름 살리기 - 18  (0) 2025.02.02
뇌주름 살리기 - 17  (0) 2025.01.31

스터디 시작

김영한 Spring 로드맵의 첫 번째인 스프링 입문 강의를 보며 각자의 블로그에 정리하고 이를 교환 해 서로의 지식을 공유하기로 했다.

Java 및 IDE(IntelliJ) 설치

Java 21 설치

https://www.oracle.com/kr/java/technologies/downloads/#jdk21-windows

오라클 회원가입 하고 x64 Installer로 다운로드 후 설치 진행
(환경 변수 설정까지 해주면 좋다.)

IntelliJ 설치

https://www.jetbrains.com/idea/download/?section=windows
위에는 유료 버전이라 더 많은 기능을 쓸 수 있고, 학생 인증 등 특정 조건 충족하면 할인이 있다.
살짝 내리면 무료 버전인 Community Edition이 있어 이걸로 다운로드 후 설치 진행

Spring Boot 프로젝트 생성

https://start.spring.io
Spring Boot 프로젝트 생성을 도와준다.

  • Project
    • Gradle(Groovy), Gradle(Kotlin), Maven
      • Gradle(Groovy) : 빌드 스크립트를 Groovy로 작성하며, 간결하고 유연한 구문. 기본 설정.
      • Gradle(Kotlin) : 빌드 스크립트를 Kotlin으로 작성하며, 정적 타입 검사와 IDE 지원의 강력함.
      • Maven : 빌드 스크립트를 XML로 작성하며, 명확한 구조와 표준화된 설정 방식. 의존성 관리와 플러그인 구성이 직관적.
  • Language
    • Java, Kotlin, Groovy
  • Spring Boot
    • SNAPTSHOT은 개발 버전, M은 마일스톤 버전으로 둘 다 정식 릴리즈 전 버전이므로 괄호가 없는 버전으로 선택.
  • Project Metadata
    • Group : 프로젝트의 그룹 ID. 일반적으로 조직이나 도메인 이름을 역순으로 작성. 패키지 네임스페이스와 관련.
    • Artifact : 생성될 프로젝트의 이름 또는 빌드 파일의 기본 이름.
    • Name : 프로젝트의 이름. 기본적으로 Artifact와 동일.
    • Description : 프로젝트에 대한 간단한 설명. 메타데이터로만 사용.
    • Package name : Java/Kotlin 패키지 이름. 기본적으로 Group + Artifact 조합.
    • Packaging : Jar (독립 실행형 애플리케이션) | War (웹 애플리케이션)
    • Java : 23 | 21 | 17
  • Dependencies
    • 프로젝트에서 사용할 라이브러리나 Spring 관련 모듈 선택으로, 여기서 설정하면 필요한 의존성을 자동으로 추가해서 호환성 보장과 초기 개발 시간을 단축할 수 있다. 강의에서 선택한 내용은 Spring WebThymeleaf 두 가지다.

설정을 마치고 하단의 Generate 버튼을 클릭하면 프로젝트가 자동으로 다운로드된다.

Spring Boot 프로젝트 실행

'열기'로 방금 다운로드 된 프로젝트 폴더를 연다.

9번째 라인에서 main 메소드의 빌드 버튼을 누르거나, 윈도우 기준 Shift + F10로 프로젝트 빌드를 누른다.

에러 발생. 찾아보니 프로젝트에 한글이 있어서 발생했고, 영어로 바꿔줬다.

정상적으로 실행됐다. Spring에 내장된 Tomcat이 8080 포트로 웹 애플리케이션을 실행한다.

'스터디 > Spring' 카테고리의 다른 글

Spring 스터디 - 6  (0) 2025.02.18
Spring 스터디 - 5  (0) 2025.02.17
Spring 스터디 - 4  (0) 2025.02.16
Spring 스터디 - 3  (0) 2025.02.12
Spring 스터디 - 2  (0) 2025.02.10

특이한 정렬

정수 n을 기준으로 n과 가까운 수부터 정렬하려고 합니다. 이때 n으로부터의 거리가 같다면 더 큰 수를 앞에 오도록 배치합니다. 정수가 담긴 배열 numlist와 정수 n이 주어질 때 numlist의 원소를 n으로부터 가까운 순서대로 정렬한 배열을 return하도록 solution 함수를 완성해주세요.

function solution(numlist, n) {
    let answer = [];

    //n이 numlist에 없으면 넣어주고, 있으면 answer에 넣어주기
    if(numlist.indexOf(n) === -1) {
        numlist.push(n);
    } else {
        answer.push(n);
    }

    numlist.sort((x, y) => x - y);

    //left와 right의 끝은 각각 -1과 length로 구분
    let length = numlist.length;
    let left = numlist.indexOf(n) === 0 ? -1 : numlist.indexOf(n) - 1;
    let right = numlist.indexOf(n) === length - 1 ? length : numlist.indexOf(n) + 1;

    let absL = 0;
    let absR = 0;
    let isEndL = left < 0 ? true : false;
    let isEndR = right === length ? true : false;

    while(!isEndL || !isEndR) {
        if(isEndL) { //left 끝이니까 right만 진행
            answer.push(numlist[right]);
            right += 1;

            if(right === length) isEndR = true;
        } else if(isEndR) { //right 끝이니까 left만 진행
            answer.push(numlist[left]);
            left -= 1;

            if(left < 0) isEndL = true;
        } else {
            //left와 right의 절대값 크기 비교로 정렬 수행
            absL = Math.abs(n - numlist[left]);
            absR = Math.abs(n - numlist[right]);

            if(absL === absR) {
                answer.push(numlist[right]);
                answer.push(numlist[left]);
                right += 1;
                left -= 1;

                if(left < 0) isEndL = true;
                if(right === length) isEndR = true;
            } else if(absL < absR) {
                answer.push(numlist[left]);
                left -= 1;

                if(left < 0) isEndL = true;
            } else if(absL > absR) {
                answer.push(numlist[right]);
                right += 1;

                if(right === length) isEndR = true;
            }
        }
    }

    return answer;
}

'코딩테스트' 카테고리의 다른 글

뇌주름 살리기 - 21  (0) 2025.02.08
뇌주름 살리기 - 20  (0) 2025.02.06
뇌주름 살리기 - 18  (0) 2025.02.02
뇌주름 살리기 - 17  (0) 2025.01.31
뇌주름 살리기 - 16  (0) 2025.01.25

유한소수 판별하기

소수점 아래 숫자가 계속되지 않고 유한개인 소수를 유한소수라고 합니다. 분수를 소수로 고칠 때 유한소수로 나타낼 수 있는 분수인지 판별하려고 합니다. 유한소수가 되기 위한 분수의 조건은 다음과 같습니다.

  • 기약분수로 나타내었을 때, 분모의 소인수가 2와 5만 존재해야 합니다.

두 정수 ab가 매개변수로 주어질 때, a/b가 유한소수이면 1을, 무한소수라면 2를 return하도록 solution 함수를 완성해주세요.

function solution(a, b) {
    const GCD = (x, y) => y === 0 ? x : GCD(y, x % y);

    //분모를 최대공약수로 나눠서 소인수분해 
    let den = b / GCD(a, b);
    let answer = [];
    while(den > 1) {
        for(let i = 2; i <= den; i++) {
            if(den % i === 0) {
                if(!answer.includes(i)) answer.push(i);
                den /= i;
                break;
            }
        }
    }

    //소인수에 2와 5가 아닌 소수가 있으면 무한소수
    return answer.filter((x) => x !== 2 && x !== 5).length > 0 ? 2 : 1;
}

저주의 숫자 3

3x 마을 사람들은 3을 저주의 숫자라고 생각하기 때문에 3의 배수와 숫자 3을 사용하지 않습니다. 3x 마을 사람들의 숫자는 다음과 같습니다.

10진법 3x 마을 10진법 3x 마을
1 1 6 8
2 2 7 10
3 4 8 11
4 5 9 14
5 7 10 16

정수 n이 매개변수로 주어질 때, n을 3x 마을에서 사용하는 숫자로 바꿔 return하도록 solution 함수를 완성해주세요.

function solution(n) {
    const curse = function(x) {
        //1이나 2면 그대로 리턴
        if(x <= 2) {
            return x;
        }

        //재귀로 바로 앞 숫자가 몇으로 바뀌는지 확인하여 +1
        let reNum = curse(x - 1) + 1;
        while(1 === 1) {
            //숫자가 3의 배수면 +1
            //숫자에 3이라는게 있으면 +1
            //둘 다 해당 안 되면 탈출
            if(reNum % 3 === 0) {
                reNum += 1;
                continue;
            } else if(reNum.toString().split('').filter((x) => x === '3').length > 0) {
                reNum += 1;
                continue;
            } else {
                break;
            }
        }

        return reNum;
    }

    return curse(n);
}

'코딩테스트' 카테고리의 다른 글

뇌주름 살리기 - 20  (0) 2025.02.06
뇌주름 살리기 - 19  (0) 2025.02.04
뇌주름 살리기 - 17  (0) 2025.01.31
뇌주름 살리기 - 16  (0) 2025.01.25
뇌주름 살리기 - 15  (0) 2025.01.24

겹치는 선분의 길이

선분 3개가 평행하게 놓여 있습니다. 세 선분의 시작과 끝 좌표가 [[start, end], [start, end], [start, end]] 형태로 들어있는 2차원 배열 lines가 매개변수로 주어질 때, 두 개 이상의 선분이 겹치는 부분의 길이를 return 하도록 solution 함수를 완성해보세요.

function solution(lines) {
    //각 선분의 [a, b]를 오름차순으로 정렬
    let lSort = lines.map((x) => x.sort((x, y) => x- y));

    //점 a와 b를 이엇을 때 인덱스 a가 1이 되도록 각 선분 초기화
    //0번은 [-100, -99], 1번은 [-99, -98]
    //동일하게 198번은 [98, 99], 199번은 [199, 200]
    let l = [new Array(200), new Array(200), new Array(200)];
    let a = 0;
    let b = 0;
    for(let i = 0; i < 3; i++) {
        //음수 처리를 위해 100 기준으로 계산
        a = lSort[i][0] < 0 ? 100 - Math.abs(lSort[i][0]) : 100 + lSort[i][0];
        b = lSort[i][1] < 0 ? 100 - Math.abs(lSort[i][1]) : 100 + lSort[i][1];

        for(let j = 0; j < 200; j++) {
            if(j >= a && j < b) {
                l[i][j] = 1;
            }
        }
    }

    //3개의 각 선분 비교 후 겹치는 부분이 1이 됨
    let lOver = new Array(200);
    for(let i = 0; i < 2; i++) {
        for(let j = i + 1; j < 3; j++) {
            for(let k = 0; k < 200; k++) {
                if(l[i][k] === 1 && l[i][k] === l[j][k]) {
                    lOver[k] = 1;
                }
            }
        }
    }

    //null이 아닌 1의 개수가 겹치는 선분의 길이
    return lOver.filter((x) => x === 1).length;
}

 

문제 제약조건에 모든 점은 정수라는 조건도 없고... 길이가 아닌 점을 기준으로 풀다보니 [[1,2],[2,3],[3,4]] 같은 케이스 해결이 안 되서 결국 다른 사람한테 힌트 받고 해결했다; 생각의 전환을 못하고 괜히 시간만 오래 잡아먹었네. 혹시나 중첩 for문을 줄이고 실행속도를 더 빠르게할 방안이 있을지 고민해보기.

'코딩테스트' 카테고리의 다른 글

뇌주름 살리기 - 19  (0) 2025.02.04
뇌주름 살리기 - 18  (0) 2025.02.02
뇌주름 살리기 - 16  (0) 2025.01.25
뇌주름 살리기 - 15  (0) 2025.01.24
뇌주름 살리기 - 14  (0) 2025.01.24

외계어 사전

PROGRAMMERS-962 행성에 불시착한 우주비행사 머쓱이는 외계행성의 언어를 공부하려고 합니다. 알파벳이 담긴 배열 spell과 외계어 사전 dic이 매개변수로 주어집니다. spell에 담긴 알파벳을 한번씩만 모두 사용한 단어가 dic에 존재한다면 1, 존재하지 않는다면 2를 return하도록 solution 함수를 완성해주세요.

function solution(spell, dic) {
    let answer = [];
    let dup = 0;

    //indexOf()와 lastIndexOf()가 같으면 한번 사용
    //같은데 -1이면 미사용, 다르면 두번 이상 사용 
    dic.forEach(function(x) {
        dup = 0;

        for(let j of spell) {
            if(x.indexOf(j) !== x.lastIndexOf(j)) {
                dup += 1;
                break;
            } else {
                if(x.indexOf(j) === -1) {
                    dup += 1;
                    break;
                }
            }
        }

        if(dup === 0) {
            answer.push(x);
        }
    });

    return answer.length > 0 ? 1 : 2;
}

평행

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

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

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

function solution(dots) {
    let answer = [];

    let x = 0;
    let y = 0;

    //직선의 기울기 (y2 - y1) / (x2 - x1)
    //x1과 x2가 같을 때 기울기는 y1
    for(let i = 0; i < 3; i++) {
        x = 0;
        y = 0;

        for(let j = i + 1; j < 4; j++) {
            x = dots[j][0] - dots[i][0];
            y = dots[j][1] - dots[i][1];

            //answer[점12, 점13, 점14, 점23, 점24, 점34]
            if(x === 0) {
                answer.push(0);
            } else {
                answer.push(y / x);
            }
        }
    }

    //서로 다른 두개의 점을 이을 경우에만 확인
    return answer[0] === answer[5] || answer[1] === answer[4] || answer[2] === answer[3] ? 1 : 0;
}

'코딩테스트' 카테고리의 다른 글

뇌주름 살리기 - 18  (0) 2025.02.02
뇌주름 살리기 - 17  (0) 2025.01.31
뇌주름 살리기 - 15  (0) 2025.01.24
뇌주름 살리기 - 14  (0) 2025.01.24
뇌주름 살리기 - 13  (1) 2025.01.22

+ Recent posts