programmers.co.kr/learn/courses/30/lessons/12901

 

코딩테스트 연습 - 2016년

2016년 1월 1일은 금요일입니다. 2016년 a월 b일은 무슨 요일일까요? 두 수 a ,b를 입력받아 2016년 a월 b일이 무슨 요일인지 리턴하는 함수, solution을 완성하세요. 요일의 이름은 일요일부터 토요일까

programmers.co.kr

문제 설명

2016년 1월 1일은 금요일입니다. 2016년 a월 b일은 무슨 요일일까요? 두 수 a ,b를 입력받아 2016년 a월 b일이 무슨 요일인지 리턴하는 함수, solution을 완성하세요. 요일의 이름은 일요일부터 토요일까지 각각 SUN,MON,TUE,WED,THU,FRI,SAT

입니다. 예를 들어 a=5, b=24라면 5월 24일은 화요일이므로 문자열 TUE를 반환하세요.

제한 조건

  • 2016년은 윤년입니다.
  • 2016년 a월 b일은 실제로 있는 날입니다. (13월 26일이나 2월 45일같은 날짜는 주어지지 않습니다)

입출력 예

abresult

5 24 TUE

 

 

 

 

 

 

풀이 .

class Solution {
    public String solution(int a, int b) {
        String answer = "";

        int[] months = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        String[] days = {"THU", "FRI", "SAT", "SUN", "MON", "TUE", "WED"};
        int total = 0;
        for(int i = 0; i < a; i++) {
            total += months[i];
        }
        total += b;
        answer = days[total % 7];

        return answer;
    }
}

public class Main {
    public static void main(String[] args) {
        Solution sol = new Solution();
    }
}

 

평범한 날짜 계산 문제.

 

딱히 코멘트가 필요 없다.

'알고리즘 문제 > 프로그래머스' 카테고리의 다른 글

[PG] 괄호 변환 JAVA  (0) 2021.02.26
[PG] 카카오프렌즈 컬러링북 JAVA  (0) 2021.02.25
[PG] 삼각 달팽이 JAVA  (0) 2021.02.19
[PG] 멀쩡한 사각형 JAVA  (0) 2021.02.19
[PG] 124 나라의 숫자 JAVA  (0) 2021.02.19

programmers.co.kr/learn/courses/30/lessons/68645

 

코딩테스트 연습 - 삼각 달팽이

5 [1,2,12,3,13,11,4,14,15,10,5,6,7,8,9] 6 [1,2,15,3,16,14,4,17,21,13,5,18,19,20,12,6,7,8,9,10,11]

programmers.co.kr

문제 설명

정수 n이 매개변수로 주어집니다. 다음 그림과 같이 밑변의 길이와 높이가 n인 삼각형에서 맨 위 꼭짓점부터 반시계 방향으로 달팽이 채우기를 진행한 후, 첫 행부터 마지막 행까지 모두 순서대로 합친 새로운 배열을 return 하도록 solution 함수를 완성해주세요.


제한사항

  • n은 1 이상 1,000 이하입니다.

입출력 예

nresult

4 [1,2,9,3,10,8,4,5,6,7]
5 [1,2,12,3,13,11,4,14,15,10,5,6,7,8,9]
6 [1,2,15,3,16,14,4,17,21,13,5,18,19,20,12,6,7,8,9,10,11]

 

 

 

 

 

 

 

풀이 .

class Solution {
    public int[] solution(int n) {
        int max = 0;
        for(int i = 1; i <= n; i++) {
            max += i;
        }
        int[] answer = new int[max];
        int[][] arr = new int[n][n];

        int row = 0, col = 0, input = 1;
        arr[row][col] = input;
        while(input < max) {
            // 상 -> 하 (row++)
            while(row + 1 < n && arr[row+1][col] == 0) {
                arr[++row][col] = ++input;
            }
            // 좌 -> 우 (col++)
            while(col + 1 < n && arr[row][col+1] == 0) {
                arr[row][++col] = ++input;
            }
            // 우하 -> 좌상 (row--, col--)
            while(row - 1 > 0 && col - 1 > 0 && arr[row-1][col-1] == 0) {
                arr[--row][--col] = ++input;
            }
        }

        int idx = 0;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j <= i; j++) {
                answer[idx++] = arr[i][j];
            }
        }
        return answer;
    }
}

public class Main {
    public static void main(String[] args) {
        Solution sol = new Solution();
    }
}

 

이차원 배열로 삼각형을 표현할 수 있다.

(대각선을 그었을 때 아래쪽 삼각형에 해당하는 좌표만 사용)

 

문제의 경우에서 이동할 수 있는 방향은 총 세 가지.

1. 위쪽에서 아래쪽으로 수직 이동

2. 왼쪽에서 오른쪽으로 수평 이동

3. 오른쪽 아래에서 왼쪽 위로 대각 이동

 

각 경우에 대한 while()문을 만들어 준다.

 

처음에는 이전 좌표의 값에 +1을 해주려고 했었는데 이렇게 하려니 이동 방향을 꺾을 때마다 이전 좌표 값을 다르게 찾아야 하는 방식이 까다로웠다.

 

배열에 할당하는 최대 숫자 max를 먼저 구하고 input : 1 ~ max 를 할당하도록 하여 이 문제를 해결했다.

 

 

 

 

'알고리즘 문제 > 프로그래머스' 카테고리의 다른 글

[PG] 카카오프렌즈 컬러링북 JAVA  (0) 2021.02.25
[PG] 2016년 JAVA  (0) 2021.02.19
[PG] 멀쩡한 사각형 JAVA  (0) 2021.02.19
[PG] 124 나라의 숫자 JAVA  (0) 2021.02.19
[PG] 두 개 뽑아서 더하기 JAVA  (0) 2021.02.18

programmers.co.kr/learn/courses/30/lessons/62048

 

코딩테스트 연습 - 멀쩡한 사각형

가로 길이가 Wcm, 세로 길이가 Hcm인 직사각형 종이가 있습니다. 종이에는 가로, 세로 방향과 평행하게 격자 형태로 선이 그어져 있으며, 모든 격자칸은 1cm x 1cm 크기입니다. 이 종이를 격자 선을

programmers.co.kr

문제 설명

가로 길이가 Wcm, 세로 길이가 Hcm인 직사각형 종이가 있습니다. 종이에는 가로, 세로 방향과 평행하게 격자 형태로 선이 그어져 있으며, 모든 격자칸은 1cm x 1cm 크기입니다. 이 종이를 격자 선을 따라 1cm × 1cm의 정사각형으로 잘라 사용할 예정이었는데, 누군가가 이 종이를 대각선 꼭지점 2개를 잇는 방향으로 잘라 놓았습니다. 그러므로 현재 직사각형 종이는 크기가 같은 직각삼각형 2개로 나누어진 상태입니다. 새로운 종이를 구할 수 없는 상태이기 때문에, 이 종이에서 원래 종이의 가로, 세로 방향과 평행하게 1cm × 1cm로 잘라 사용할 수 있는 만큼만 사용하기로 하였습니다.
가로의 길이 W와 세로의 길이 H가 주어질 때, 사용할 수 있는 정사각형의 개수를 구하는 solution 함수를 완성해 주세요.

제한사항

  • W, H : 1억 이하의 자연수

입출력 예

WHresult

8 12 80

입출력 예 설명

입출력 예 #1
가로가 8, 세로가 12인 직사각형을 대각선 방향으로 자르면 총 16개 정사각형을 사용할 수 없게 됩니다. 원래 직사각형에서는 96개의 정사각형을 만들 수 있었으므로, 96 - 16 = 80 을 반환합니다.

 

 

 

 

 

 

풀이 .

 

->

 

 

예제를 바탕으로 조건을 찾아보고자 했다.

 

예제의 경우 w : h = 8 : 12 이고, 이걸 최대공약수 4로 나누면 2 : 3이 된다.

즉, 전체 map에서 선분이 지나가는 2 x 3 크기의 덩어리가 gcd개 존재하게 된다.

 

하지만 이 6칸의 사각형이 모두 선분에 걸치는 것은 아니다. 살릴 수 있는 부분도 존재한다. 이걸 계산하는 게 관건인 듯 하다.

 

라고 여기까지 생각했는데.. 자세히 생각해보니 굳이 w : h가 1이 아닌 최대공약수를 갖도록 맞아떨어지는 수가 주어진다는 보장이 없다. (이걸 굳이 여러 블럭으로 나누려고 할 필요가 없었다)

 

결국 다시 원점이다.

 

 

나누어 떨어지지 않는 경우에 대한 조건을 떠올리기 위해 w : h = 8 : 5 로 직접 그려보았다.

 

끝 열이 겹치는 형태로 2 x 1, 3 x 1의 3, 2개씩 반복되었다.

여기에서 규칙을 찾을 수 없을까?

(틀린 접근법이었다)

 

 

 

여기에서 더 나아가지 못하고 답을 확인했다.

 

우선 딱 나누어 떨어지지 않는 경우(gcd = 1인 경우)는 그냥 w x h사이즈의 블록이 gcd개 만큼 반복된다고 보면 된다.

즉,  (w / gcd) * (h / gcd) 사이즈가 gcd번 반복되는 일반식을 세우면 되는 것이다.

 

위에서 관건이라고 언급했던 이 gcd개의 덩어리에서 선분을 지나는 칸을 구하는 것도 일반식을 세울 수 있었다.

이 w/gcd = w', h/gcd = h' 으로 두어 이 덩어리의 사이즈가 w' x h' 라고 두었을 때, 선분이 지나는 칸의 개수는 w' + h' - 1개가 된다.

일반식이기 때문에 gcd가 몇이든 항상 동일하게 적용된다.

 

어떻게 이런 식이 도출되는가?

->

(w' x h')블록 안에서 선분은 항상 행, 열 중 하나에 대해서만 이동한다. 행과 열을 동시에 이동하는 경우, 즉, 대각선 방향으로 한 번에 이동하는 경우는 없다는 것이다. 

(전체를 놓고 봤을 때 대각선 방향으로 이동하는 경우가 있긴 하지만 이건 다음 (w' x h')블록으로 이동하는 것이다. 즉, 위의 빨간 글씨의 문장은 항상 성립하게 된다.)

 

그럼 결국 선분은 (w' x h')블록 안에서 행을 h'번, 열을 w'번 이동하게 된다. 하지만 블록의 맨 왼쪽위 칸은 첫번째 행과 첫번째 행을 동시에 표현하기 때문에 이 중복에 대한 처리로 -1을 해줘야 한다.

 

이렇게 w' + h' - 1 이란 식을 도출할 수 있게 된다.

 

결국 전체 맵에서 손상되지 않은 사각형의 개수는

(w * h) - (w' + h' - 1) * gcd 이라는 식을 통해 구할 수 있게 된다. (단, w' = w / gcd, h' = h / gcd)

 

 

 

 

 

 

class Solution {
    public int gcd(int a, int b) {
        if(b == 0) return a;
        else return gcd(b, a % b);
    }

    public long solution(int w, int h) {
        long answer = 0;
        int gcd = gcd(w, h);
        answer = ((long)w * (long)h) - (((long)w / gcd) + ((long)h / gcd) - 1) * gcd;
        return answer;
    }
}

public class Main {
    public static void main(String[] args) {
        Solution sol = new Solution();
    }
}

 

풀이를 찾아보며 BigInteger 클래스를 사용해서 gcd를 좀 더 편하게 구할 수 있는 방법이 있단 걸 알았다.

사실 원래 방식도 별 거 없어서 그게 그거이긴 하다.

(속도는 원래 방식이 아주 조금 더 빠른 듯 하다)

 

    import java.math.BigInteger;
    
    public int gcd(int a, int b) {
        BigInteger bi1 = BigInteger.valueOf(a);
        BigInteger bi2 = BigInteger.valueOf(b);
        BigInteger gcd = bi1.gcd(bi2);
        return gcd.intValue();
    }

 

 

 

 

 

'알고리즘 문제 > 프로그래머스' 카테고리의 다른 글

[PG] 2016년 JAVA  (0) 2021.02.19
[PG] 삼각 달팽이 JAVA  (0) 2021.02.19
[PG] 124 나라의 숫자 JAVA  (0) 2021.02.19
[PG] 두 개 뽑아서 더하기 JAVA  (0) 2021.02.18
[PG] 크레인 인형뽑기 게임 JAVA  (0) 2021.02.18

programmers.co.kr/learn/courses/30/lessons/12899

 

코딩테스트 연습 - 124 나라의 숫자

 

programmers.co.kr

문제 설명

124 나라가 있습니다. 124 나라에서는 10진법이 아닌 다음과 같은 자신들만의 규칙으로 수를 표현합니다.

  1. 124 나라에는 자연수만 존재합니다.
  2. 124 나라에는 모든 수를 표현할 때 1, 2, 4만 사용합니다.

예를 들어서 124 나라에서 사용하는 숫자는 다음과 같이 변환됩니다.

10진법124 나라10진법124 나라

1 1 6 14
2 2 7 21
3 4 8 22
4 11 9 24
5 12 10 41

자연수 n이 매개변수로 주어질 때, n을 124 나라에서 사용하는 숫자로 바꾼 값을 return 하도록 solution 함수를 완성해 주세요.

제한사항

  • n은 500,000,000이하의 자연수 입니다.

입출력 예

nresult

1 1
2 2
3 4
4 11

 

 

 

 

 

 

 

풀이 .

class Solution {
    public String solution(int n) {
        StringBuilder sb = new StringBuilder();
        while(n > 0) {
            int mod = n % 3;
            if(mod == 0) {
                mod = 4;
                n = n / 3 - 1;
            } else
                n /= 3;
            sb.insert(0, String.valueOf(mod));
        }
        return sb.toString();
    }
}

public class Main {
    Solution sol = new Solution();

}

 

문제를 보자마자 3진법을 사용하면 되겠다는 생각까지는 도달했다.

 

처음에는 단순히 3진법으로 나온 0, 1, 2를 각각 크기 순서대로 1, 2, 4로 치환하면 될 것이라고 생각했지만 잘못된 풀이였다.

 

n을 나눈 나머지가 1, 2일 때는 그걸 그대로 쓰면 되지만 0이 나올 떄는 몫을 -1 하고 나머지를 4로 바꿔줘야 한다.

(솔직히 왜 그래야 하는지 제대로 이해 못 했다.)

 

 

 

 

programmers.co.kr/learn/courses/30/lessons/68644

 

코딩테스트 연습 - 두 개 뽑아서 더하기

정수 배열 numbers가 주어집니다. numbers에서 서로 다른 인덱스에 있는 두 개의 수를 뽑아 더해서 만들 수 있는 모든 수를 배열에 오름차순으로 담아 return 하도록 solution 함수를 완성해주세요. 제한

programmers.co.kr

문제 설명

정수 배열 numbers가 주어집니다. numbers에서 서로 다른 인덱스에 있는 두 개의 수를 뽑아 더해서 만들 수 있는 모든 수를 배열에 오름차순으로 담아 return 하도록 solution 함수를 완성해주세요.


제한사항

  • numbers의 길이는 2 이상 100 이하입니다.
    • numbers의 모든 수는 0 이상 100 이하입니다.

입출력 예

numbersresult

[2,1,3,4,1] [2,3,4,5,6,7]
[5,0,2,7] [2,5,7,9,12]

입출력 예 설명

입출력 예 #1

  • 2 = 1 + 1 입니다. (1이 numbers에 두 개 있습니다.)
  • 3 = 2 + 1 입니다.
  • 4 = 1 + 3 입니다.
  • 5 = 1 + 4 = 2 + 3 입니다.
  • 6 = 2 + 4 입니다.
  • 7 = 3 + 4 입니다.
  • 따라서 [2,3,4,5,6,7] 을 return 해야 합니다.

입출력 예 #2

  • 2 = 0 + 2 입니다.
  • 5 = 5 + 0 입니다.
  • 7 = 0 + 7 = 5 + 2 입니다.
  • 9 = 2 + 7 입니다.
  • 12 = 5 + 7 입니다.
  • 따라서 [2,5,7,9,12] 를 return 해야 합니다.

 

 

 

 

 

 

풀이 .

import java.util.ArrayList;
import java.util.Collections;

class Solution {
    ArrayList<Integer> answer = new ArrayList<>();

    public void dfs(int idx, int cnt, int sum, int[] numbers) {
        if(cnt == 2) {
            if(!answer.contains(sum)) {
                answer.add(sum);
            }
            return;
        }
        if(idx != numbers.length) {
            dfs(idx + 1, cnt + 1, sum + numbers[idx], numbers);
            dfs(idx + 1, cnt, sum, numbers);
        }
    }

    public ArrayList<Integer> solution(int[] numbers) {
        dfs(0, 0, 0, numbers);
        Collections.sort(answer);
        return answer;
    }
}

public class Main {
    public static void main(String[] args) {
        Solution sol = new Solution();
        int[] numbers = {2, 1, 3, 4, 1};
        ArrayList<Integer> ans = sol.solution(numbers);
        System.out.println(ans);
    }
}

 

DFS를 사용해 배열의 원소 2개에 대한 조합을 모두 구한다.

 

중복 값을 허용하지 않는 조건을 추가하여 정답 형식에 맞춰준다.

 

Set을 사용하려고 했는데 오름차순된 배열을 반환해야해서 ArrayList에서 contains로 검사했다.

 

 

 

 

'알고리즘 문제 > 프로그래머스' 카테고리의 다른 글

[PG] 멀쩡한 사각형 JAVA  (0) 2021.02.19
[PG] 124 나라의 숫자 JAVA  (0) 2021.02.19
[PG] 크레인 인형뽑기 게임 JAVA  (0) 2021.02.18
[PG] 가장 먼 노드 JAVA  (0) 2021.01.06
[PG] 입국심사 JAVA  (0) 2021.01.04

programmers.co.kr/learn/courses/30/lessons/64061

 

코딩테스트 연습 - 크레인 인형뽑기 게임

[[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]] [1,5,3,5,1,2,1,4] 4

programmers.co.kr

문제 설명

게임개발자인 죠르디는 크레인 인형뽑기 기계를 모바일 게임으로 만들려고 합니다.
죠르디는 게임의 재미를 높이기 위해 화면 구성과 규칙을 다음과 같이 게임 로직에 반영하려고 합니다.

게임 화면은 1 x 1 크기의 칸들로 이루어진 N x N 크기의 정사각 격자이며 위쪽에는 크레인이 있고 오른쪽에는 바구니가 있습니다. (위 그림은 5 x 5 크기의 예시입니다). 각 격자 칸에는 다양한 인형이 들어 있으며 인형이 없는 칸은 빈칸입니다. 모든 인형은 1 x 1 크기의 격자 한 칸을 차지하며 격자의 가장 아래 칸부터 차곡차곡 쌓여 있습니다. 게임 사용자는 크레인을 좌우로 움직여서 멈춘 위치에서 가장 위에 있는 인형을 집어 올릴 수 있습니다. 집어 올린 인형은 바구니에 쌓이게 되는 데, 이때 바구니의 가장 아래 칸부터 인형이 순서대로 쌓이게 됩니다. 다음 그림은 [1번, 5번, 3번] 위치에서 순서대로 인형을 집어 올려 바구니에 담은 모습입니다.

만약 같은 모양의 인형 두 개가 바구니에 연속해서 쌓이게 되면 두 인형은 터뜨려지면서 바구니에서 사라지게 됩니다. 위 상태에서 이어서 [5번] 위치에서 인형을 집어 바구니에 쌓으면 같은 모양 인형 두 개가 없어집니다.

크레인 작동 시 인형이 집어지지 않는 경우는 없으나 만약 인형이 없는 곳에서 크레인을 작동시키는 경우에는 아무런 일도 일어나지 않습니다. 또한 바구니는 모든 인형이 들어갈 수 있을 만큼 충분히 크다고 가정합니다. (그림에서는 화면표시 제약으로 5칸만으로 표현하였음)

게임 화면의 격자의 상태가 담긴 2차원 배열 board와 인형을 집기 위해 크레인을 작동시킨 위치가 담긴 배열 moves가 매개변수로 주어질 때, 크레인을 모두 작동시킨 후 터트려져 사라진 인형의 개수를 return 하도록 solution 함수를 완성해주세요.

[제한사항]

  • board 배열은 2차원 배열로 크기는 5 x 5 이상 30 x 30 이하입니다.
  • board의 각 칸에는 0 이상 100 이하인 정수가 담겨있습니다.
    • 0은 빈 칸을 나타냅니다.
    • 1 ~ 100의 각 숫자는 각기 다른 인형의 모양을 의미하며 같은 숫자는 같은 모양의 인형을 나타냅니다.
  • moves 배열의 크기는 1 이상 1,000 이하입니다.
  • moves 배열 각 원소들의 값은 1 이상이며 board 배열의 가로 크기 이하인 자연수입니다.

입출력 예

boardmovesresult

[[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]] [1,5,3,5,1,2,1,4] 4

입출력 예에 대한 설명

입출력 예 #1

인형의 처음 상태는 문제에 주어진 예시와 같습니다. 크레인이 [1, 5, 3, 5, 1, 2, 1, 4] 번 위치에서 차례대로 인형을 집어서 바구니에 옮겨 담은 후, 상태는 아래 그림과 같으며 바구니에 담는 과정에서 터트려져 사라진 인형은 4개 입니다.

 

 

 

 

 

 

 

풀이 .

import java.util.Arrays;
import java.util.Stack;

class Solution {
    public int solution(int[][] board, int[] moves) {
        int answer = 0;
        int n = board.length;
        int[] topOfCol = new int[n];
        Arrays.fill(topOfCol, n);

        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                // 각 열마다 인형이 처음 나오는 row 찾는다.
                // 끝까지 topOfCol[idx] == n 이면 비어있는 열
                if(board[i][j] != 0 && topOfCol[j] == n) {
                    topOfCol[j] = i;
                }
            }
        }

        Stack<Integer> stk = new Stack<>();
        for(int i = 0; i < moves.length; i++) {
            int col = moves[i] - 1;  // 열 인덱스 맞춰줘야 함
            if(topOfCol[col] == n) continue;  // 해당 열에 인형이 없는 경우
            int row = topOfCol[col];

            int doll = board[row][col];
            topOfCol[col] += 1;
            if(stk.isEmpty()) {
                stk.push(doll);
            }else {
                if(stk.peek() == doll) {
                    stk.pop();
                    answer += 2;
                }else {
                    stk.push(doll);
                }
            }
        }
        return answer;
    }
}

public class Main {
    public static void main(String[] args) {
        Solution sol = new Solution();
        int[][] board = {{0,0,0,0,0}, {0,0,1,0,3}, {0,2,5,0,1}, {4,2,4,4,2}, {3,5,1,3,1}};
        int[] moves = {1, 5, 3, 5, 1, 2, 1, 4};
        int ans = sol.solution(board, moves);
        System.out.println(ans);
    }
}

 

각 열마다 가장 위에 있는 인형의 위치(row)를 표시하기 위해 int[] topOfCol를 사용했다.

 

스택을 사용해 해결.

 

 

 

 

'알고리즘 문제 > 프로그래머스' 카테고리의 다른 글

[PG] 124 나라의 숫자 JAVA  (0) 2021.02.19
[PG] 두 개 뽑아서 더하기 JAVA  (0) 2021.02.18
[PG] 가장 먼 노드 JAVA  (0) 2021.01.06
[PG] 입국심사 JAVA  (0) 2021.01.04
[PG] 여행경로 JAVA  (0) 2021.01.04

www.acmicpc.net/problem/2143

 

2143번: 두 배열의 합

첫째 줄에 T(-1,000,000,000 ≤ T ≤ 1,000,000,000)가 주어진다. 다음 줄에는 n(1 ≤ n ≤ 1,000)이 주어지고, 그 다음 줄에 n개의 정수로 A[1], …, A[n]이 주어진다. 다음 줄에는 m(1≤m≤1,000)이 주어지고, 그 다

www.acmicpc.net

문제

한 배열 A[1], A[2], …, A[n]에 대해서, 부 배열은 A[i], A[i+1], …, A[j-1], A[j] (단, 1 ≤ i ≤ j ≤ n)을 말한다. 이러한 부 배열의 합은 A[i]+…+A[j]를 의미한다. 각 원소가 정수인 두 배열 A[1], …, A[n]과 B[1], …, B[m]이 주어졌을 때, A의 부 배열의 합에 B의 부 배열의 합을 더해서 T가 되는 모든 부 배열 쌍의 개수를 구하는 프로그램을 작성하시오.

예를 들어 A = {1, 3, 1, 2}, B = {1, 3, 2}, T=5인 경우, 부 배열 쌍의 개수는 다음의 7가지 경우가 있다.

T(=5) = A[1] + B[1] + B[2] = A[1] + A[2] + B[1] = A[2] + B[3] = A[2] + A[3] + B[1] = A[3] + B[1] + B[2] = A[3] + A[4] + B[3] = A[4] + B[2]

입력

첫째 줄에 T(-1,000,000,000 ≤ T ≤ 1,000,000,000)가 주어진다. 다음 줄에는 n(1 ≤ n ≤ 1,000)이 주어지고, 그 다음 줄에 n개의 정수로 A[1], …, A[n]이 주어진다. 다음 줄에는 m(1≤m≤1,000)이 주어지고, 그 다음 줄에 m개의 정수로 B[1], …, B[m]이 주어진다. 각각의 배열 원소는 절댓값이 1,000,000을 넘지 않는 정수이다.

출력

첫째 줄에 답을 출력한다. 가능한 경우가 한 가지도 없을 경우에는 0을 출력한다.

예제 입력 1

5

4

1 3 1 2

3

1 3 2

예제 출력 1

7

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static ArrayList<Integer> subA, subB;
    static int[] A, B;
    static int T, N, M;

    public static int upperBound(ArrayList<Integer> list, int target) {
        int min = 0;
        int max = list.size();
        while(min < max) {
            int mid = (min + max) / 2;
            if(list.get(mid) <= target) {
                min = mid + 1;
            }else {
                max = mid;
            }
        }
        return max;
    }

    public static int lowerBound(ArrayList<Integer> list, int target) {
        int min = 0;
        int max = list.size();
        while(min < max) {
            int mid = (min + max) / 2;
            if(list.get(mid) >= target) {
                max = mid;
            }else {
                min = mid + 1;
            }
        }
        return max;
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        T = Integer.parseInt(br.readLine());

        // A[] 전처리
        N = Integer.parseInt(br.readLine());
        A = new int[N];
        st = new StringTokenizer(br.readLine());
        for(int i = 0; i < N; i++) {
            A[i] = Integer.parseInt(st.nextToken());
        }

        // B[] 전처리
        M = Integer.parseInt(br.readLine());
        B = new int[M];
        st = new StringTokenizer(br.readLine());
        for(int i = 0; i < M; i++) {
            B[i] = Integer.parseInt(st.nextToken());
        }

        // 각 배열에 대한 부분배열의 합
        subA = new ArrayList<>();
        for(int i = 0; i < N; i++) {
            int sum = A[i];
            subA.add(sum);
            for(int j = i + 1; j < N; j++) {
                sum += A[j];
                subA.add(sum);
            }
            sum = 0;
        }
        Collections.sort(subA);

        subB = new ArrayList<>();
        for(int i = 0; i < M; i++) {
            int sum = B[i];
            subB.add(sum);
            for(int j = i + 1; j < M; j++) {
                sum += B[j];
                subB.add(sum);
            }
            sum = 0;
        }
        Collections.sort(subB);

        // 이분탐색으로 정답 찾기
        long ans = 0;
        for(int i = 0; i < subA.size(); i++) {
            ans += upperBound(subB, T - subA.get(i)) - lowerBound(subB, T - subA.get(i));
        }
        System.out.println(ans);
    }
}

 

처음에는 부분배열의 합을 담는 배열 subA, subB를 구하기 위해 DFS를 짰었다.

근데 굳이 그럴 필요 없이 이중 for문을 사용해서 모든 부분배열의 합을 구할 수 있었다.

 

부분배열의 합을 모두 구하고 이분탐색을 사용해 정답 케이스의 개수를 헤아렸다.

 

 

위 방법 말고도 HashMap을 이용해서도 처리가 가능할 듯 하다.

subA, subB에 대한 HashMap에 (숫자, 개수)를 담고 탐색만 하는 것.

귀찮아서 짜보지는 않았다.

 

subA, subB에 대한 투포인터로 탐색도 가능할 듯.

 

 

 

 

www.acmicpc.net/problem/7453

 

7453번: 합이 0인 네 정수

첫째 줄에 배열의 크기 n (1 ≤ n ≤ 4000)이 주어진다. 다음 n개 줄에는 A, B, C, D에 포함되는 정수가 공백으로 구분되어져서 주어진다. 배열에 들어있는 정수의 절댓값은 최대 228이다.

www.acmicpc.net

문제

정수로 이루어진 크기가 같은 배열 A, B, C, D가 있다.

A[a], B[b], C[c], D[d]의 합이 0인 (a, b, c, d) 쌍의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 배열의 크기 n (1 ≤ n ≤ 4000)이 주어진다. 다음 n개 줄에는 A, B, C, D에 포함되는 정수가 공백으로 구분되어져서 주어진다. 배열에 들어있는 정수의 절댓값은 최대 228이다.

출력

합이 0이 되는 쌍의 개수를 출력한다.

예제 입력 1

6

-45 22 42 -16

-41 -27 56 30

-36 53 -37 77

-36 30 -75 -46

26 -38 -10 62

-32 -54 -6 45

예제 출력 1

5

 

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static int[] A, B, C, D, AB, CD;
    static int N;

    public static int upperBound(int[] arr, int target) {
        int min = 0;
        int max = arr.length;
        while(min < max) {
            int mid = (min + max) / 2;
            if(arr[mid] <= target) {
                min = mid + 1;
            }else {
                max = mid;
            }
        }
        return max;
    }

    public static int lowerBound(int[] arr, int target) {
        int min = 0;
        int max = arr.length;
        while(min < max) {
            int mid = (min + max) / 2;
            if(CD[mid] >= target) {
                max = mid;
            }else {
                min = mid + 1;
            }
        }
        return max;
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine());

        A = new int[N];
        B = new int[N];
        C = new int[N];
        D = new int[N];

        // N
        for(int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            A[i] = Integer.parseInt(st.nextToken());
            B[i] = Integer.parseInt(st.nextToken());
            C[i] = Integer.parseInt(st.nextToken());
            D[i] = Integer.parseInt(st.nextToken());
        }

        // N^2
        AB = new int[N * N];
        CD = new int[N * N];
        int idx = 0;
        for(int i = 0; i < N; i++){
            for(int j = 0; j < N;j++) {
                AB[idx] = A[i] + B[j];
                CD[idx] = C[i] + D[j];
                idx += 1;
            }
        }
        Arrays.sort(AB);
        Arrays.sort(CD);

        // N^2 * 2 * logN
        long ans = 0;
        for(int num : AB) {
            ans += upperBound(CD, -num) - lowerBound(CD, -num);
        }
        System.out.println(ans);
    }
}

 

N^4로 완전탐색해서 구할 수 있지만 시간초과가 나버린다.

 

A와B, C와D에 대해서 2N짜리 크기의 배열을 만들고 그 둘로 검사를 실행한다.

A + B + C + D = 0 을 A + B = -(C + D)로 바꿔서 CD배열에서 -AB를 찾는 것이다.

 

AB에 대해서는 이분탐색을 실행하지 않기 때문에 CD만 정렬을 했는데 시간초과가 발생헀다.

다시 AB까지 정렬을 실행하고 돌리니까 정답 처리.

 

일을 더 오래 했는데 통과되는 기이한 현상?

-> 둘 다 정렬을 하고 실행하면 공간 지역성에 의해 오히려 더 빨리 처리된다고 한다.

 

내 수준에서 문제를 풀면서 지역성의 영향까지 받게될 줄은 몰랐다..

 

 

 

위 방법 말고도 HashMap을 이용해서도 처리가 가능할 듯 하다.

AB, CD에 대한 HashMap에 (숫자, 개수)를 담고 탐색만 하는 것.

귀찮아서 짜보지는 않았다.

 

AB, CD에 대한 투포인터로 탐색도 가능할 듯.

 

+ Recent posts