[백준] 2143: 두 배열의 합 - JAVA

https://www.acmicpc.net/problem/2143

풀이

배열 2개가 주어지고 배열들의 부 배열들을 합하여 T를 만들는 경우의 수를 찾는 문제이다.

두 가지 방법으로 풀 수 있는 문제였다.

첫 번째로 생각한 방법은 Map을 사용해 containsKey를 이용하는 방법이었다.

배열 A의 부 배열들의 합을 map에 저장해 놓는다.

배열 B의 부 배열의 합을 구하면서 T에서 뺀 값이 A의 map에 있다면 map의 value 만큼 카운트하여 더해준다.

이 방법으로 제출하고 다른 풀이들을 보니 이분 탐색으로 푸는 방법도 있었다.

List에 부 배열들을 저장하고 이분 탐색을 위해 정렬한다.

ListA에서 값을 꺼내면서 T - 꺼낸 값을 찾을 값으로 하여 ListB에서 이분탐색을 통해 찾는다.

개수가 여러 개 있을 수 있으므로 키값이 처음으로 나오는 인덱스와 키값보다 처음으로 커지는 인덱스를 찾아 두 수의 차이를 개수로 하여 더해준다.


Map

메모리: 58104KB

시간: 388ms

언어: Java 11

코드

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        int n = Integer.parseInt(br.readLine());
        int[] arrA = new int[n];
        StringTokenizer st = new StringTokenizer(br.readLine());
        for(int i = 0; i < n; i++) {
            arrA[i] = Integer.parseInt(st.nextToken());
        }
        int m = Integer.parseInt(br.readLine());
        int[] arrB = new int[m];
        st = new StringTokenizer(br.readLine());
        for(int i = 0; i < m; i++) {
            arrB[i] = Integer.parseInt(st.nextToken());
        }

        Map<Integer, Integer> mapA = new HashMap<>();
        for(int i = 0; i < n; i++) {
            int sum = 0;
            for(int j = i; j < n; j++) {
                sum += arrA[j];
                mapA.put(sum, mapA.getOrDefault(sum, 0) + 1);
            }
        }

        long ans = 0;
        for(int i = 0; i < m; i++) {
            int sum = 0;
            for(int j = i; j < m; j++) {
                sum += arrB[j];
                int key = T - sum;
                if(mapA.containsKey(key)) {
                    ans += mapA.get(key);
                }
            }
        }

        System.out.println(ans);
    }

}

List + 이분 탐색

메모리: 47800KB

시간: 908ms

언어: Java 11

코드

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        int n = Integer.parseInt(br.readLine());
        int[] arrA = new int[n];
        StringTokenizer st = new StringTokenizer(br.readLine());
        for (int i = 0; i < n; i++) {
            arrA[i] = Integer.parseInt(st.nextToken());
        }
        int m = Integer.parseInt(br.readLine());
        int[] arrB = new int[m];
        st = new StringTokenizer(br.readLine());
        for (int i = 0; i < m; i++) {
            arrB[i] = Integer.parseInt(st.nextToken());
        }

        List<Integer> listA = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            int sum = 0;
            for (int j = i; j < n; j++) {
                sum += arrA[j];
                listA.add(sum);
            }
        }

        List<Integer> listB = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            int sum = 0;
            for (int j = i; j < m; j++) {
                sum += arrB[j];
                listB.add(sum);
            }
        }

        // Collections.sort(listA);
        Collections.sort(listB);

        long ans = 0;
        for (int sumA : listA) {
            int key = T - sumA;
            int lb = lower_bound(key, listB);
            int ub = upper_bound(key, listB);

            ans += (ub - lb);
        }

        System.out.println(ans);
    }

    private static int upper_bound(int key, List<Integer> listB) {
        // key보다 큰 값이 처음으로 나타나는 인덱스

        int left = 0;
        int right = listB.size();

        while (left < right) {
            int mid = (left + right) / 2;

            if (listB.get(mid) > key) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }

        return left;
    }

    private static int lower_bound(int key, List<Integer> listB) {
        // key와 같은 값이 처음으로 나타나는 인덱스

        int left = 0;
        int right = listB.size();

        while (left < right) {
            int mid = (left + right) / 2;

            if (listB.get(mid) >= key) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }

        return left;
    }

}