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
- 이분 매칭
- Gradle
- 달팽이
- 완전 탐색
- 비트마스킹
- Zuul
- docker-compose
- 이분 탐색
- 주울
- 다익스트라
- 구현
- BFS
- Java
- spring cloud
- Logback
- 메모이제이션
- spring boot
- 구간 트리
- Spring Cloud Config
- 스프링 시큐리티
- 트리
- dp
- 도커
- 유레카
- 게이트웨이
- 백트래킹
- 플로이드 와샬
- 서비스 디스커버리
- 스택
- ZuulFilter
Archives
- Today
- Total
Hello, Freakin world!
[백준 1208번][Java] 부분수열의 합 2 - 중간에서 만나기? 본문
1208번: 부분수열의 합 2
첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 40, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.
www.acmicpc.net
풀이 방법
전체 배열을 반으로 나눠 완전탐색을 통해 모든 부분수열의 합을 찾아내 각각 leftList, rightList에 저장합니다.
그리고 부분수열의 합이 저장된 leftList, rightList를 크기순으로 정렬합니다. (저는 하나는 오름차순, 다른 하나는 내림차순 정렬했습니다.)
인덱스를 조정해가면서 N^2 복잡도로 모든 합을 검색하는게 아니라 스위핑 방식으로 N의 복잡도로 개수를 찾아냅니다.
import java.io.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.StringTokenizer;
/*
부분수열의 합2
https://www.acmicpc.net/problem/1208
*/
public class Main {
static int n,s;
static int[] nums;
public static void main(String[] args) throws IOException {
// InputReader reader = new InputReader();
InputReader reader = new InputReader("testcase.txt");
StringTokenizer st = new StringTokenizer(reader.readLine());
n = Integer.parseInt(st.nextToken());
s = Integer.parseInt(st.nextToken());
nums = new int[n];
st = new StringTokenizer(reader.readLine());
for (int i = 0; i < n; i++) {
nums[i] = Integer.parseInt(st.nextToken());
}
List<Integer> left = new ArrayList<>();
getSumList(0, n/2,0,left);
List<Integer> right = new ArrayList<>();
getSumList(n/2, n,0,right);
left.sort(Comparator.reverseOrder());
right.sort(Comparator.naturalOrder());
long cnt = countIfEqualsSumS(left, right);
if(s == 0) cnt--;
System.out.println(cnt);
}
private static long countIfEqualsSumS(List<Integer> left, List<Integer> right) {
long cnt = 0;
int li = 0, ri = 0;
while(li < left.size() && ri < right.size()) {
// System.out.format("li : %d, ri : %d\n", li, ri);
int leftSum = left.get(li);
int rightSum = right.get(ri);
int sum = leftSum + rightSum;
if(sum > s) {
li++;
continue;
}
if(sum < s) {
ri++;
continue;
}
if(sum == s) {
long leftCnt = 0l, rightCnt = 0l;
while(ri < right.size() && leftSum + right.get(ri) == s) {
ri++;
rightCnt++;
}
while(li < left.size() && rightSum + left.get(li) == s) {
li++;
leftCnt++;
}
cnt += leftCnt * rightCnt;
}
}
return cnt;
}
public static void getSumList(int i, int end, int acc, List<Integer> sumList) {
if(i == end) {
sumList.add(acc);
return;
}
//포함하지 않는 경우
getSumList(i+1,end, acc, sumList);
//포함하는 경우
getSumList(i+1, end, acc+nums[i], sumList);
}
}
class InputReader {
private BufferedReader br;
public InputReader() {
br = new BufferedReader(new InputStreamReader(System.in));
}
public InputReader(String filepath) {
try {
br = new BufferedReader(new FileReader(filepath));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public List<Character> readLineIntoCharList() throws IOException {
List<Character> l = new ArrayList<>();
while(true) {
int readVal = br.read();
if(readVal == '\n' || readVal == -1) break;
l.add((char)readVal);
}
return l;
}
public boolean ready() throws IOException {
return br.ready();
}
public String readLine() throws IOException {
return br.readLine();
}
public int readInt() throws IOException {
return Integer.parseInt(readLine());
}
public Long readLong() throws IOException {
return Long.parseLong(readLine());
}
}
'알고리즘 > PS' 카테고리의 다른 글
[백준 1068번][Java] 트리 - 리프노드 세기, 노드 지우기 (0) | 2020.10.09 |
---|---|
[백준 1967번][Java] 트리의 지름 - 재귀 호출 전/후 함수 호출 (0) | 2020.10.09 |
[백준 1389번][Java] 케빈 베이컨의 6단계 법칙 - 플로이드 와샬 (0) | 2020.10.07 |
[백준 11403번][Java] 경로 찾기 - [모든 정점 간 최단 거리 찾기 : 플로이드 와샬] (0) | 2020.10.07 |
[백준 11286번][Java] 절댓값 힙 - 힙 구현하기[응용편] (0) | 2020.10.07 |
Comments