알고리즘/Samsung codeground

11/19 좋은 수

삼성 코드그라운드에서 제공하는 알고리즘에 관한 개인적인 풀이를 정리했습니다.

아래 사이트에서 직접 풀어보실 수 있습니다.

 

https://www.codeground.org/practice

 

모든 알고리즘 문제는 C++로 구현되어 있습니다.

 

 

처음 이 문제를 봤을 때는 배열을 순회하면서 현재 수 보다 앞에 있는 수들을 재귀 호출을 통해 더해보면서 좋은 수를 판별하는 방식을 생각했다.

#include <iostream>
#include <cstring> 
using namespace std;

int Answer, arr[5000], chk[200000]; //좋은 수(첫 코드, 시간 초과)

void getGoodNum(int objIdx, int prev, int idx, int sum) {
	if (chk[objIdx]) return;
	if (idx == 3) {
		if (sum == arr[objIdx]) {
			Answer++;
			chk[objIdx] = 1;
		}
		return;
	}
	for (int i = prev; i < objIdx; i++) {
		getGoodNum(objIdx, i, idx+1, sum + arr[i]);
	}
}

int main(int argc, char** argv)
{
	int T, test_case;

	cin >> T;
	for (test_case = 0; test_case < T; test_case++)
	{
		memset(chk, 0, sizeof(chk));
		Answer = 0;
		int i, n;
		cin >> n;
		for (i = 0; i < n; i++) {
			cin >> arr[i];
		}

		for (i = 1; i < n; i++) {
			getGoodNum(i, 0, 0, 0);
		}
		cout << "Case #" << test_case + 1 << endl;
		cout << Answer << endl;
	}

	return 0;
}

처음 생각한 코드. 시간 초과가 발생할 뿐만 아니라 음수 입력이 들어오면

chk 배열에 들어가지 못해 프로그램이 죽어버린다.

 

 

처음 생각한 대로 코드를 적당히 짜보고 실행해보니 테스트 케이스는 통과했지만, N이 더 크게 늘어났을 때는 시간제한에 걸리는 것을 확인할 수 있었다. 이는 시간 복잡도가 O(N^3)인 getGoodNum 메소드를 n-1번 실행하여 전체 코드의 총 시간복잡도가 O(N^4)가 되기 때문이었다. 나는 이 방법으로는 풀 수 없다는 것을 느끼고 다른 방법을 찾아야 했다.

 

 

 

 

특별한 방법이 생각나지 않아 구글링을 해보던 중, 세 가지 수가 아닌 두 수의 합만 배열에 저장해놓으면 O(N^2)의 시간복잡도로 문제를 풀 수 있다는 것을 알게 되었다. i번째 수를 좋은 수인지 판별하기 위해서 0번째 수부터 i-1번째 수에서 2개의 수를 뽑아 더한 값이 i번째 수 - (0번째 수 ~ i-1번째 수)인지를 확인하고 같은 값이 있다면 i번째 수를 좋은 수라고 판별하는 방식으로 i를 0부터 n까지 돌리면 문제를 O(N^2) 시간 안에 풀 수 있다.

 

 

전체 코드는 다음과 같다.

#include <iostream>
#include <cstring>
using namespace std;

int Answer, arr[5000], chk[400001]; //좋은 수

int main(int argc, char** argv)
{
	int T, test_case;

	cin >> T;
	for (test_case = 0; test_case < T; test_case++)
	{
		Answer = 0;
		int i, j, n;
		cin >> n;
		for (i = 0; i < n; i++) {
			cin >> arr[i];
		}
		memset(chk, 0, sizeof(chk));
		for (i = 0; i < n; i++) {
			for (j = 0; j < i; j++) { // 두 수의 합을 저장하는 배열을 채운다.
				if (!chk[arr[i-1] + arr[j]+200000]) chk[arr[i-1] + arr[j] + 200000] = 1;
			}

			for (j = 0; j < i; j++) {
				if (chk[arr[i] - arr[j] + 200000]) {
					Answer++;
					break;
				}
			}
		}
		cout << "Case #" << test_case + 1 << endl;
		cout << Answer << endl;
	}

	return 0;
}

 

'알고리즘 > Samsung codeground' 카테고리의 다른 글

11/22 블럭 없애기  (0) 2019.11.22
11/19 미궁 속의 방  (0) 2019.11.19
11/18 이항계수의 합  (0) 2019.11.18
11/18 다트 게임  (0) 2019.11.18