2003 수들의 합 2

DONGJIN IM·2022년 3월 7일
0

코딩 테스트

목록 보기
38/137

문제 이해

숫자 배열이 주어진다.
이 때 A[i] + A[i+1] + ... + A[j] = M이 되는 (i,j) 쌍의 총 개수를 구하는 문제이다.


문제 풀이

처음에는 쉽게 생각했다.
left= 0, right = 0으로 설정 후, ans = A[left]로 설정하였다.
이후 아래와 같은 상황으로 포인터를 움직였다.

  1. ans > M : ans를 줄여야 할 필요가 있다. 따라서 구간을 줄여야 한다. 즉 left를 1증가시킨다

  2. ans = M : 정답인 상황이다. left를 1증가시켜도 되고, right를 1 증가시켜도 되지만, 나는 right를 1 증가시켰다.(만약, A[x]가 0을 포함하고 있다면 상황이 복잡해지겠지만, 다행히도 A[x]는 자연수이다)

  3. ans < M : ans를 키울 필요가 있다. 따라서 구간을 늘려야 한다. 즉 right를 1 증가시킨다.

문제는 아래의 조건에서 생겼다.

"만약 left = right인 경우는 어떻게 처리할 것인가?"

A[left] <= M일 경우는 그나마 다행이지만, 만약 A[right]>M일 경우 left를 1증가시키므로 left > right인 상황이 벌어진다.
따라서 이 부분을 처리해 줄 필요가 있었다.

먼저 ans에는 현재 A[left] 값이 저장되어 있을 것이다.
따라서, 먼저 ans = M인지를 확인하고, 만약 그럴 경우 경우의 수를 하나 더 해준다.
이후 right 포인터를 무조건 한칸 오른쪽으로 이동시킨 후 해당 값을 ans에 더해준다.
마지막으로 다음 반복문의 시행으로 건너 뛰어 right = left + 1인 상황에서 검사를 다시하는 방법으로 이 문제를 해결하였다.

이 때, right이 배열 범위를 벗어나더라도 left는 움직일 수 있지 않을까 생각할 수도 있을 것이다.
하지만, right이 배열의 범위를 넘어가는 경우는 총 2가지 경우이다.

  1. A[left] + ... + A[right-1] <= M : A[left]가 빠지면 무조건 M 미만이 되므로 고려할 필요가 없다.

  2. left = right & A[left] <=M : A[left]가 빠지면 구간이 존재하지 않으므로 구간합 또한 존재하지 않는다. 따라서 고려하지 않아도 된다.

위와 같은 이유로 따로 left를 추가적으로 움직여줄 필요는 없다.


코드

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

public class Main {
	
	static int N;
	static long M;
	static int[] arr;
	
	static void two_pointer() {
		int left = 0;
		int right = 0;
		long ans = arr[right];
		long num = 0;
		
		while(true) {
			if(left==right) {
            // left = right일 경우
            // ans = M(즉, arr[left]=arr[right]=M)인지를 확인
            // 이후, right = left + 1로 만들어준 뒤 다시 while문을 통해 
            // ans를 확인
				if(ans==M) num++;
				right++;
				if(right >= N) break;
				else {
					ans += arr[right];
				}
				continue;
			}
			
			if(ans > M) {
                // ans > M이여서 구간합을 줄여야 하는 경우
                // left 포인터를 1증가시킨다.
				ans -= arr[left];
				left++;
			}
			else if(ans==M) {
				num++;
				right++;
				if(right >= N) break;
				else {
					ans += arr[right];
				}
			}
			else {
                // ans < M이여서 구간합을 늘려야 하는 경우
                // right 포인터를 이동시키는 모든 곳에서는 
                // 아래와 같은 로직을 사용해야 한다.
				right++;
				if(right >= N) break;
				else {
					ans += arr[right];
				}
			}
		}
		
		System.out.println(num);
	}
	
	public static void main(String[] args) {

		FastReader sc = new FastReader();

		N = sc.nextInt();
		M = sc.nextLong();
		arr = new int[N];
		
		for(int i =0;i<N;i++) arr[i] = sc.nextInt();
		
		two_pointer();
	}
	
	static class FastReader // 빠른 입력을 위한 클래스
}

결과

  • 4,5,6번째 줄 틀렸습니다 : left = right일 때의 처리를 잘못하여 틀렸다.
  • 3번째 줄 출력 초과 : 디버깅할 때 쓴 출력 코드를 안 지우고 제출했다.
profile
개념부터 확실히!

0개의 댓글

관련 채용 정보