문제 설명
Finn은 요즘 수학공부에 빠져 있습니다. 수학 공부를 하던 Finn은 자연수 n을 연속한 자연수들로 표현 하는 방법이 여러개라는 사실을 알게 되었습니다. 예를들어 15는 다음과 같이 4가지로 표현 할 수 있습니다.
1 + 2 + 3 + 4 + 5 = 15
4 + 5 + 6 = 15
7 + 8 = 15
15 = 15
자연수 n이 매개변수로 주어질 때, 연속된 자연수들로 n을 표현하는 방법의 수를 return하는 solution를 완성해주세요.
제한사항
n은 10,000 이하의 자연수 입니다.
★ 이중 포문의 문제가 아니다.
★ 등차수열을 활용해 일반식을 도출해서 풀어야 하는 문제이다.
- 처음엔 이중포문으로 풀었다.
#include <string>
#include <vector>
using namespace std;
int solution(int n)
{
int answer = 0;
// n 횟수 만큼 반복
// 1부터 더해서 n과 동일해지면 되면 카운트 +1
// n보다 커지면 다음 2부터 시작
for (int i = 1; i <= n / 2; i++)
{
int val = 0;
for (int j = i; j <= n; j++)
{
val += j;
if (val == n)
answer++;
}
}
return ++answer;
}
하지만 O^2의 시간 복잡도로 시간초과가 남
★ 식을 고민하다 결국 다른 블로그를 찾아보며 힌트를 얻었다.
아래는 유도한 방법
- 더해서 나오는 목표값: n
- 연속된 덧셈의 시작값: a
- 더하는 개수: k
1. 식부터 유도하자
ㄴ 일단 1부터 10까지 더하면 55, 이는 (1 + 10) 값을 1부터 10까지의 개수(10)에서 2를 나눈 값을 곱한 결과이다.
ㄴ 1부터하니 뭔가 헷갈려서 3부터 10으로 친다면 개수는 (10 - 3 +1)이므로 계산하면 8/2*(10+3) = 52
2. 일반식으로
ㄴ n = a + (a+1) + (a+2) + ... + (a+k-2) + (a+k-1) // k를 k-1까지 해야 총 개수가 k 개이다.
ㄴ 이걸 일반식으로
ㄴ 개수는 k 개 이므로, k/2*(a+(a+k-1) = n 이라는 식이 나온다.
이때 조건을 따지면 n과, k, a 모두 자연수이다.
a를 좌항으로 보내면
=> 2a + k - 1 = 2n/k
=> 2a = 2n/k - (k + 1)
=> a = n/k - (k + 1)/2
가 된다.
3. 조건 따지기
ㄴ a는 자연수 이므로, 우항의 n/k와 (k+1)/2 가 모두 정수가 되려면, n은k로 나누어떨어지고, k는 홀수여야 한다.
ㄴ (n % k == 0 && k % 2 == 1)
#include <string>
#include <vector>
using namespace std;
int solution(int n)
{
int answer = 0;
for (int i = 1; i <= n; i++)
if (n % i == 0 && i % 2 == 1)
answer++;
return answer;
}
★ 덧 붙이기
ㄴ 가끔은 문제 접근 자체를 다시해야한다.
답을 구하는 것이 아니라, 해당 답이 나오기 위해 필요한 조건을 활용해서 답을 구하는 방식을 고민해보자
그러기 위해서는 일반식을 도출하는게 좋다.
ㄴ 이전 모회사 코테에서 2중포문으로 풀리지만 시간 초과때문에 실패했던 문제가 있었다.
그때도 이런 유형이지 않았을까 싶다.
그땐 도저히 이중 포문 말고는 답을 모르겠어서 못풀었었다.
'게임 클라이언트 개발 > 알고리즘 문제' 카테고리의 다른 글
[2] 피보나치 수 (0) | 2024.09.15 |
---|---|
[2] 다음 큰 숫자 (0) | 2024.09.15 |
[2] 이진 변환 반복하기 (0) | 2024.09.01 |
[2] JadenCase 문자열 만들기 (0) | 2024.09.01 |
[2] 최솟값 만들기 (0) | 2024.09.01 |