회고

입력이 무려 백만!! 헐헐헐 1,000,000!!
기존 O(n²) 알고리즘으로는 불가능 하다.
텅 빈 수열에서 시작해 숫자를 하나씩 추가해 나가며 각 길이를 갖는 증가 수열 중 가장 마지막 수가 작은 것은 무엇인지를 추적한다.

즉, dp[i] = 지금까지 만든 부분 배열이 갖는 길이 i 인 증가 부분 수열 중 최소의 마지막 값.
이분검색을 하는 과정이 필요하므로, O(nlgn) 으로 가능

풀이


문제

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {1020, 10, 30, 20, 50} 이고, 길이는 4이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다.

둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000,000)

출력

첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.

예제 입력 1 

6
10 20 10 30 20 50

예제 출력 1 

4






































소스


회고

재귀함수 리턴값이 수열의 길이가 아닌, 수열의 합

입력의 크기가 1,000 이하이므로 O(n²) 으로 가능



풀이


문제

수열 A가 주어졌을 때, 그 수열의 증가 부분 수열 중에서 합이 가장 큰 것을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {1, 100, 2, 50, 60, 3, 5, 6, 7, 8} 인 경우에 합이 가장 큰 증가 부분 수열은 A = {1, 100, 25060, 3, 5, 6, 7, 8} 이고, 합은 113이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000)

출력

첫째 줄에 수열 A의 합이 가장 큰 증가 부분 수열의 합을 출력한다.

예제 입력 1 

10
1 100 2 50 60 3 5 6 7 8

예제 출력 1 

113





































소스

https://github.com/JK921/icandoit/blob/develop/dp/src/Solution11055.java


회고

입력의 크기가 1,000 이하 이므로 O(n²) 의 알고리즘으로 가능.
dp[n] = max(dp[n], dp[n+k] + 1) (if, num[n] < dp[n+k])

memoization 시, 초기값을 -1 로 채워서, 꼭 계산 여부를 체크하도록..

풀이

문제

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {1020, 10, 30, 20, 50} 이고, 길이는 4이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000)

출력

첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.


예제 입력 1 

6
10 20 10 30 20 50

예제 출력 1 

4




























소스

https://github.com/JK921/icandoit/blob/develop/dp/src/Solution11053.java

탐욕법 (greedy method)

가장 직관적인 알고리즘 설계 패러다임

우리가 원하는 답을 재귀 호출과 똑같이 여러 개의 조각으로 쪼개고,
각 단계마다 답의 한 부분을 만들어 간다는 점에서 완전 탐색이나 동적 계획법 알고리즘과 다를 것이 없다.
But, 탐욕법은 각 단계마다 지금 당장 가장 좋은 방법만을 선택 하는 방법.

주의할점
탐욕적 알고리즘은 많은 경우 최적해를 찾지 못함.

탐욕적 알고리즘이 사용되는 경우

  1. 탐욕법을 사용해도 항상 최적해를 구할 수 있는 문제를 만난 경우
    탐욕법은 동적 계획법보다 수행 시간이 훨씬 빠르기 때문에 유용함.

  2. 시간이나 공간적 제약으로 인해 다른 방법으로 최적해를 찾기가 너무 어려운 경우
    최적해 대신 적당히 괜찮은 답(근사해)을 찾는 것으로 타협할 수 있음.


프로그래밍 대회에서는 주로 1번 용도로만 사용됨.
=> 근사해를 찾는 문제는 주어지지 않음..


탐욕법 vs 동적 계획법

사실, 탐욕법으로 최적해를 찾을 수 있는 많은 문제들은 동적 계획법으로도 풀 수 있음.

 탐욕법

 

 동적 계획법

하나의 경우만 고려해서 답을 얻는 방법

  

모든 경우의 수를 다 찾아 답을 얻는 방법


따라서 동적 계획법으로 탐욕법이 고려하는 경우를 커버하기 때문에 가능함.

하지만 동적 계획법에 필요한 메모리나 시간이 과도하게 큰 경우는 탐욕법을 사용해야 할 수도 있음.

'스터디 > 알고리즘 정리' 카테고리의 다른 글

동적 계획법 테크닉 (not yet)  (0) 2018.12.02
동적 계획법 문제 풀이 (not yet)  (0) 2018.12.02
동적 계획법  (0) 2018.12.01
분할 정복  (0) 2018.11.27
알고리즘 시간 복잡도  (0) 2018.11.26


'스터디 > 알고리즘 정리' 카테고리의 다른 글

탐욕법  (0) 2018.12.02
동적 계획법 문제 풀이 (not yet)  (0) 2018.12.02
동적 계획법  (0) 2018.12.01
분할 정복  (0) 2018.11.27
알고리즘 시간 복잡도  (0) 2018.11.26


'스터디 > 알고리즘 정리' 카테고리의 다른 글

탐욕법  (0) 2018.12.02
동적 계획법 테크닉 (not yet)  (0) 2018.12.02
동적 계획법  (0) 2018.12.01
분할 정복  (0) 2018.11.27
알고리즘 시간 복잡도  (0) 2018.11.26

동적 계획법

현재 문제를 작은 문제로 나눈 뒤 작은 문제의 답을 구하고,
작은 문제로부터 현재 문제의 답을 구하는 알고리즘

분할정복 vs 동적 계획법

동적 계획법은 현재 문제를 부분문제로 나눈 뒤 현재 문제의 답을 구한다는 점에서 분할정복과 비슷하지만


분할 정복은 부분문제를 한번만 계산하게 되는 반면,

동적 계획법은 같은 부분문제를 여러 차례 계산한다.


따라서 중복적인 계산을 피하기 위해 메모이제이션 기법이 반드시 필요하며, 

두번 이상 계산되는 부분문제를 중복되는 부분문제 (overlapping subproblems) 라고 부른다.



(a)는 분할 정복 (b)는 동적 계획법



메모이제이션

동적 계획법의 반복적인 부분 문제 계산 예


bino(2, 1)은 

  • bino(3, 1) 을 계산할 때 필요
  • bino(2, 1) 을 계산할 때도 필요


입력 n과 r 이 정해져 있을 떄 bino(n, r) 의 반환값이 일정


∴ 한번 계산한 값을 저장해 뒀다가 재활용하는 최적화 기법을 사용해야 함


이와 같이 

두번이상 반복 계산되는 부분 문제들의 답을 미리 저장함으로써, 속도의 향상을 꾀하는 알고리즘 설계 기법을 동적 계획법이라고 한다.



메모이제이션 주의 할 점

메모하려는 값이 참,거짓 이어도 불리언 타입으로 메모이제이션을 하면 안됨.
불리언 배열을 캐시로 사용해서는 아직 계산되지 않은 상태인지 아닌지 알 수 없기 때문.
따라서 캐싱을 정수형으로 1, 0 값을 가진다고 설계하고 -1 로 초기화 하여 사용.



최적화 동적 계획법 레시피

  1. 모든 답을 만들어 보고 그 중 최적해의 점수를 반환하는 완전 탐색 알고리즘을 설계한다.
  2. 전체의 값을 반환하는 것이 아니라, 앞으로 남은 선택들에 해당하는 값 만을 반환하도록 부분 문제 정의를 바꾼다.
  3. 재귀 호출의 입력에 이전 선택에 관련된 정보가 있다면 꼭 필요한 것만 남기고 줄인다.
    문제가 최적 부분 구조에 성립할 경우에는 이전 선택에 관련된 정보를 완전히 없앨 수도 있다.
    입력의 정보가 줄어들면 줄어들수록 더 많은 부분 문제가 중복되고, 따라서 메모이제이션을 최대한 활용할 수 있다.
  4. 입력이 배열이거나 문자열인경우 가능하다면 적절한 변환을 통해 메모이제이션을 이용할 수 있도록 한다.
  5. 메모이제이션을 적용한다.



'스터디 > 알고리즘 정리' 카테고리의 다른 글

탐욕법  (0) 2018.12.02
동적 계획법 테크닉 (not yet)  (0) 2018.12.02
동적 계획법 문제 풀이 (not yet)  (0) 2018.12.02
분할 정복  (0) 2018.11.27
알고리즘 시간 복잡도  (0) 2018.11.26

p. 175 ~ p. 205


분할 정복

  1. 주어진 문제를 둘 이상의 부분문제로 나눈 뒤, (Divide)
  2. 각 문제의 답을 재귀호출을 통해 계산 후 (Merge)
  3. 각 답으로부터 원래 문제의 답을 계산하는 알고리즘 (Base case)

순수 재귀호출 방식과 다른 점

 재귀호출

 분할 정복

 1 문제 + 나머지 (재귀호출)

 부분문제 (재귀호출) + 부분문제 (재귀호출)

 1 ~ N 합

 N 번의 호출

 lgN 번의 호출

  sum(n-1) + n

  •  2 * sum(n / 2) + (n / 2) * (n / 2)  (if, n 짝수)
  •  sum(n - 1) + n                         (if, n 홀수)



병합 정렬과 퀵 정렬

 병합 정렬 (Merge Sort)

퀵 정렬 (Quick Sort)

 O(nlgn)

 O(nlgn)

 병합 단계에서 연산 수행

 분할 단계에서 연산 수행

 

 pivot 잘못 선택 시 최악의 경우 O(n²) 이 될 수 있음






문제

쿼드 트리 뒤집기





울타리 잘라내기





'스터디 > 알고리즘 정리' 카테고리의 다른 글

탐욕법  (0) 2018.12.02
동적 계획법 테크닉 (not yet)  (0) 2018.12.02
동적 계획법 문제 풀이 (not yet)  (0) 2018.12.02
동적 계획법  (0) 2018.12.01
알고리즘 시간 복잡도  (0) 2018.11.26

+ Recent posts