기록방

Java 코딩 테스트 교재 #4 본문

CS/알고리즘

Java 코딩 테스트 교재 #4

Soom_1n 2022. 9. 29. 16:02

Do it! 알고리즘 코딩 테스트 - 자바 편

 

http://www.easyspub.co.kr/20_Menu/BookView/500/PUB

 

www.easyspub.co.kr

 

03-3 투 포인터


알고리즘이 간단하므로 문제로 알아보자

[연습문제 #006 :연속된 자연수의 합 구하기 (boj_2018)]

문제

어떠한 자연수 N은, 몇 개의 연속된 자연수의 합으로 나타낼 수 있다. 당신은 어떤 자연수 N(1 ≤ N ≤ 10,000,000)에 대해서, 이 N을 몇 개의 연속된 자연수의 합으로 나타내는 가지수를 알고 싶어한다. 이때, 사용하는 자연수는 N이하여야 한다.

예를 들어, 15를 나타내는 방법은 15, 7+8, 4+5+6, 1+2+3+4+5의 4가지가 있다. 반면에 10을 나타내는 방법은 10, 1+2+3+4의 2가지가 있다.

N을 입력받아 가지수를 출력하는 프로그램을 작성하시오.

입력

첫 줄에 정수 N이 주어진다.

출력

입력된 자연수 N을 몇 개의 연속된 자연수의 합으로 나타내는 가지수를 출력하시오

제한

  • 제한시간 2초

01단계 문제 분석하기

  • 제한시간은 2초인데 N의 최대값은 1000만으로 매우 크게 잡혀있다
  • → O(nlogn)을 사용하면 시간초과이므로 O(n)의 시간 복잡도 알고리즘을 사용해야 함
  • 이 경우 자주 사용하는 방법이 투 포인터
    • 이 문제의 경우 연속된 자연수의 합을 구하는 것이므로 시작, 끝 인덱스를 투 포인터로 지정

02단계 손으로 풀어보기

  1. N을 입력받은 후 start_index, end_index, sum, count를 모두 1로 초기화
    1. count를 1로 초기화 하는 이유는 무조건 N자기자신으로 만들 수 있기 때문
  2. end_index가 N이 될 때까지 투 포인터를 이동해가며 계산 후 count를 증가시킴
    1. sum > N : sum -= start_index; start_index++;
    2. sum < N : end_index++; sum += end_index;
    3. sum == N : end_index++; sum += end_index; count++;

<03단계 슈도코드 작성하기 생략>

<04단계 코드 구현하기 포스팅>

[연습문제 #007 : 주몽의 명령 (boj_1940)]

문제

주몽은 철기군을 양성하기 위한 프로젝트에 나섰다. 그래서 야철대장을 통해 철기군이 입을 갑옷을 만들게 하였다. 야철대장은 주몽의 명에 따르기 위하여 연구에 착수하던 중 아래와 같은 사실을 발견하게 되었다.

갑옷을 만드는 재료들은 각각 고유한 번호를 가지고 있다. 갑옷은 두 개의 재료로 만드는데 두 재료의 고유한 번호를 합쳐서 M(1 ≤ M ≤ 10,000,000)이 되면 갑옷이 만들어 지게 된다. 야철대장은 자신이 만들고 있는 재료를 가지고 갑옷을 몇 개나 만들 수 있는지 궁금해졌다. 이러한 궁금증을 풀어 주기 위하여 N(1 ≤ N ≤ 15,000) 개의 재료와 M이 주어졌을 때 몇 개의 갑옷을 만들 수 있는지를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 재료의 개수 N(1 ≤ N ≤ 15,000)이 주어진다. 그리고 두 번째 줄에는 갑옷을 만드는데 필요한 수 M(1 ≤ M ≤ 10,000,000) 주어진다. 그리고 마지막으로 셋째 줄에는 N개의 재료들이 가진 고유한 번호들이 공백을 사이에 두고 주어진다. 고유한 번호는 100,000보다 작거나 같은 자연수이다.

출력

첫째 줄에 갑옷을 만들 수 있는 개수를 출력한다.

제한

  • 제한시간 2초

01단계 문제 분석하기

  • 두 재료의 번호의 합. 즉, 크기를 비교하므로 정렬하면 더 쉽게풀 수 있음
    • N의 최대 범위가 15,000 이므로 O(nlongn)을 사용할 수 있음 (정렬은 일반적으로 시간 복잡도가 O(nlongn))
  • 정렬 후 약쪽 끝 위치를 투 포인터로 지정해 접근

02단계 손으로 풀어보기

  1. 재료 데이터를 A[n]에 저장한 후 오름차순 정렬
  2. 투 포인터 i, j를 양쪽 끝 위치에 위치시킨 후 문제에 적합한 포인터 이동 규칙을 활용해 탐색
    1. A[i] + A[j] > M : j--; (번호의 합이 M보다 크므로 큰 번호 index를 내림)
    2. A[i] + A[j] < M : i++; (번호의 합이 M보다 작으므로 작은 번호 index를 올림)
    3. A[i] + A[j] == M : i++; j--; count++; (양쪽 포인터 모두 이동시키고 count 증가)

<03단계 슈도코드 작성하기 생략>

<04단계 코드 구현하기 포스팅>

[연습문제 #008 : ‘좋은 수’ 구하기 (boj_1253)]

문제

N개의 수 중에서 어떤 수가 다른 수 두 개의 합으로 나타낼 수 있다면 그 수를 “좋다(GOOD)”고 한다.

N개의 수가 주어지면 그 중에서 좋은 수의 개수는 몇 개인지 출력하라.

수의 위치가 다르면 값이 같아도 다른 수이다.

입력

첫째 줄에는 수의 개수 N(1 ≤ N ≤ 2,000), 두 번째 줄에는 i번째 수를 나타내는 Ai가 N개 주어진다. (|Ai| ≤ 1,000,000,000, Ai는 정수)

출력

좋은 수의 개수를 첫 번째 줄에 출력한다.

제한

  • 제한시간 2초

01단계 문제 분석하기

  • 시간 복잡도
    • N의 개수가 최대값 2,000이라 가정해도 좋은 수 하나를 찾는 알고리즘의 시간 복잡도는 N^2보다 작아야 한다. (N^2 를 사용하면 다시 N번 반복해서 최종 시간 복잡도는 N^3가 되기 때문)
    • 좋은 수 하나를 찾는 알고리즘은 최소 O(nlongn)이어야 한다. 정렬과 투 포인터 알고리즘 사용
  • 정렬된 데이터에서 자기 자신을 좋은 수 만들기에 포함하지 않도록 주의

02단계 손으로 풀어보기

  1. N개의 수를 입력받아 정렬한다. N은 최대 10억이므로 N과 arr를 long형으로 선언한다.
  2. 투 포인터 i, j를 배열 arr 양쪽 끝에 위치시키고 투 포인터 이동 원칙을 활용해 탐색한다.
    • A[i] + A[j] > K : j--;
    • A[i] + A[j] < K : i++;
    • A[i] + A[j] == K : i++; j--; count++;
  3. arr의 인덱스 0부터 N-1 까지 투 포인터로 탐색한다.
    • 투 포인터가 자기자신(K) 가 되지 않도록 주의한다.

<03단계 슈도코드 작성하기 생략>

<04단계 코드 구현하기 포스팅>

 

원본 노션 정리 글

 

Java 코딩 테스트 교재 #4

03-3 투 포인터

probable-legume-162.notion.site

 

728x90

'CS > 알고리즘' 카테고리의 다른 글

시간 복잡도  (0) 2023.06.15
그리디(Greedy; 탐욕) 알고리즘  (0) 2023.02.17
Java 코딩 테스트 교재 #3  (0) 2022.09.21
Java 코딩 테스트 교재 #2  (0) 2022.09.20
Java 코딩 테스트 교재 #1  (0) 2022.09.20