1부터 n까지의 수 집합이 존재한다.
이 중에서 하나의 수만 제외하고 n-1개의 수 집합 중에서 서로 다른 숫자 n-1개를 입력받는다.
여기서 존재하지 않는 숫자는 무엇인가?
ex) n=5 이고 {1,2,4,5} 입력받았다면 답은 "3"이다.
입력 : 5
1 2 4 5
출력 : 3
크게 두 가지 방법이 존재한다.
배열 사용
첫 번째는 넉넉한 크기의 배열을 만든 다음에 모두 0을 저장한다.
그리고 수를 입력받으면 그 값을 인덱스로 사용하여 배열 해당 인덱스의 값을 1로 저장한다.
다 입력받고 나면 0이 들어있는 인덱스를 찾으면 끝이다.
위의 예시에서는 수를 전부 입력받으면 아래와 같은 모습이 된다.
index | 0 | 1 | 2 | 3 | 4 | 5 |
value | 0 | 1 | 1 | 0 | 1 | 1 |
- 0번 인덱스의 값은 사용하지 않고 1번 인덱스부터 조사하면 된다. 평균적으로 n/2번의 조사해야한다.
#include <iostream>
using namespace std;
int main(){
int arr[1000] = {0,}; //배열을 0으로 초기화
int n,temp;
cin>>n;
for(int i = 1;i<n;i++){
cin>>temp;
arr[temp] = 1; //해당 인덱스의 배열 값을 1로 저장
}
for(int i = 1;i<=n;i++){
if(!arr[i]){ //arr[i]가 0이라는 것은 i가 입력되지 않았다는 뜻
cout<<i;
return 0;
}
}
}
이보다 시간을 단축시키는 방법이 존재한다.
덧셈 공식 사용
1부터 n까지 더하는 공식이 $$\frac{n(n+1)}{2}$$ 라는 것은 다들 알고 있을 것이다.
그렇다면 먼저 위 공식을 사용하여 1부터 n까지 더한 값을 구한다.
그리고 값을 입력받을 때마다 변수에 계속 더해서 입력받은 수의 합을 구한다.
그리고 1부터 n까지의 합에서 위의 합을 빼버리면 입력받지 않은 수를 알 수 있다.
#include <iostream>
using namespace std;
int main(){
int arr[1000] = {0,};
int n,temp;
int res= 0;
cin>>n;
for(int i = 1;i<n;i++){
cin>>temp;
res+=temp;
}
cout<<n*(n+1)/2-res;
}
1번의 계산으로 없는 수를 구할 수 있다.
만약 n개 중 n-2개만 입력받고 입력받지 않은 두 수를 구한다면 어떻게 할까?
이것도 숫자 하나만 입력받지 않을 때와 비슷하다. 첫 번째 방식인 배열을 사용하면 역시 1이 아닌 인덱스 두 개를 찾기만 하면 된다.
두 번째 방식에서는 조금 달라진다.
없는 수가 a, b라고 하자. 합 공식을 사용한다면 a+b의 값까지는 구해낼 수 있지만 a와 b의 정확한 값을 구해낼 수 없다.
그래서 추가로 1부터 n까지 전부 제곱을해서 합을 구하는 것이다.
그리고 입력받은 수를 전부 제곱해서 더한 값을 빼면 $$ a^{2}+b^{2} $$의 값을 알 수 있다.
그러면 아래처럼 ab의 값을 구할 수가 있고 $$ (a+b)^{2}-a^{2}+b^{2}=2ab $$
아래와 같이 이차 방정식의 근을 구하면 된다. $$ x^{2}-(a+b)x+ab $$
'공부 > Algorithm' 카테고리의 다른 글
[Algorithm] RMQ (Range Minimum Query) (0) | 2023.04.19 |
---|---|
[Algorithm] 다익스트라 (Dijkstra algorithm), 벨만 포드(Bellman ford algorithm) (0) | 2022.12.19 |
[Algorithm] KMP 알고리즘 (문자열 매칭 알고리즘) (0) | 2022.12.18 |
[Algorithm] 프림 알고리즘(Prim algorithm)과 크루스칼 알고리즘 (Kruskal algorithm) (0) | 2022.12.17 |
[Algorithm] 점화식 점근적 접근 방식(반복 대치, 추정 후 증명) (0) | 2022.12.05 |
댓글