반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 프로그래머스
- 네이버 검색 시스템
- 알고리즘
- GitHub Desktop
- baekjoon
- SRE
- Ultimate Search
- 격리수준
- 백준
- python3
- Algorithmus
- 알고리즘 종류 정리
- Python
- Github
- programmers
- 리트코드
- algorithm
- git
- 자소서
- C++
- 제노블레이드 2
- 취준
- 프로콘 갈림현상
- 백트래킹
- 코딩테스트
- DP
- ASF-110
- Pro-Con
- 프로콘
- LeetCode
Archives
- Today
- Total
산타는 없다
[백준 / BAEKJOON] 1208번 부분수열의 합2 - Python 본문
반응형
문제 원문
조건
시간 제한 : 1초
메모리 제한 : 256 MB문제
N개의 정수로 이루어진 수열이 있을 때, 크기가 양수인 부분수열 중에서 그 수열의 원소를 다 더한 값이 S가 되는 경우의 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 40, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.
출력
첫째 줄에 합이 S가 되는 부분수열의 개수를 출력한다.
예제
풀이
이 문제의 경우 주어지는 정수의 개수가 최대 40개 이므로 나올 수 있는 조합의 수를 계산하면 2^40이 됩니다.
(이항정리의 파생 공식으로 nC₀ + nC₁ + nC₂ + nC₃ + nC₄ + nC₅.... + nCn = 2^n)
2^40는 약 1조가 넘는 숫자로 모든 조합의 수를 계산하면 시간이 초과됩니다.
따라서 이 문제는 주어진 배열을 절반으로 나누어 각각 조합의 합을 구하고 구해진 두 배열의 합끼리 더하여 목표 값이 있는지 확인해야합니다.
이 때도 그냥 반복문으로 확인하면 시간이 오래걸리기 때문에 투 포인터를 활용한 이분탐색으로 확인합니다.
풀이과정은 다음과 같습니다.
- 입력된 배열을 절반으로 나눈다 (왼쪽, 오른쪽)
- 각각의 배열에서 나올 수 있는 조합의 합을 딕셔너리에 저장한다.
- 각각의 딕셔너리에 목표 값이 있는지 확인한다. (오른쪽 인자을 포함하지 않거나 왼쪽 인자을 포함하지 않는 경우)
- 각각의 딕셔너리의 value(합한 결과)를 정렬하여 리스트로 저장한 후 왼쪽은 index를 증가시키면서 오른쪽은 index를 감소시키면서 탐색한다.
- 이때 각 배열이 포함되지 않는 경우는 3번 과정에서 확인 하였으므로 두 인덱스 중 하나라도 범위에서 벗어나면 반복을 종료한다.
- 탐색 중 목표값과 일치하는 경우가 있다면 왼쪽의 해당 수의 갯수와 오른쪽의 해당 수의 갯수를 곱하여 결과에 더해준다.
성공 코드
import string
import sys
sys.setrecursionlimit(10**9)
input = sys.stdin.readline
arrSize, target = map(int, input().split())
fullArr = list(map(int, input().split()))
leftArr = fullArr[:arrSize//2]
rightArr = fullArr[arrSize//2:]
count = 0
#크기와 합한 결과만 넘긴다
def BT(sumDict, numArr, count = 0, lastIndex = -1, sumResult = 0):
if count != 0:
if sumResult in sumDict:
sumDict[sumResult] += 1
else:
sumDict[sumResult] = 1
for index in range(lastIndex + 1, len(numArr)):
sumResult += numArr[index]
BT(sumDict, numArr, count + 1, index, sumResult)
sumResult -= numArr[index]
#왼쪽과 오른쪽 배열의 조합의 합을 계산한다
leftSum = dict()
rightSum = dict()
BT(leftSum, leftArr)
BT(rightSum, rightArr)
#왼쪽이나 오른쪽에서 해당하는 값이 있는지 찾아서 결과에 반영
if target in leftSum:
count += leftSum[target]
if target in rightSum:
count += rightSum[target]
#왼쪽과 오른쪽을 더해서 목표값이 되는 경우를 이분탐색으로 찾아 결과에 반영
leftResult = sorted(leftSum.keys())
rightResult = sorted(rightSum.keys())
leftIndex = 0
rightIndex = len(rightResult) - 1
while leftIndex < len(leftResult) and rightIndex >= 0:
sumVal = leftResult[leftIndex] + rightResult[rightIndex]
if sumVal == target:
count += leftSum[leftResult[leftIndex]] * rightSum[rightResult[rightIndex]]
if sumVal < target:
leftIndex += 1
else:
rightIndex -= 1
print(count)
결과
Github - github.com/ledpear
반응형
'코딩테스트 > 백준' 카테고리의 다른 글
[백준 / BAEKJOON] 1562번 계단 수 - c++ (0) | 2021.08.16 |
---|---|
[백준 / BAEKJOON] 1509번 팰린드롬 분할 - Python (0) | 2021.08.15 |
[백준 / BAEKJOON] 17144번 미세먼지 안녕! - C++ (0) | 2021.07.30 |
[백준 / BAEKJOON] 17070번 파이프 옮기기 - C++ (0) | 2021.07.30 |
[백준 / BAEKJOON] 9935번 문자열 폭발 - C++ (0) | 2021.07.29 |
Comments