Skip to content

Commit

Permalink
[cpp] softeer-HSAT_7_1
Browse files Browse the repository at this point in the history
  • Loading branch information
minjae9610 committed Aug 12, 2023
1 parent 1320ee9 commit eec0007
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
34 changes: 34 additions & 0 deletions seoul_21_minjaekim/Softeer/HSAT_7th/1/HSAT_7th_1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include<iostream>
#include<algorithm>
#include<unordered_map>

using namespace std;

int main(int argc, char** argv)
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

int n, q;
cin >> n >> q;

int cars[50000];
for (int i = 0; i < n; ++i)
cin >> cars[i];

sort(cars, cars + n);

unordered_map<int, int> map;
for (int i = 0; i < n; ++i)
map[cars[i]] = i + 1;

for (int i = 0; i < q; ++i) {
int m, m_idx;
cin >> m;
m_idx = map[m];
cout << (m_idx ? (m_idx - 1) * (n - m_idx) : m_idx) << '\n';
}

return 0;
}
89 changes: 89 additions & 0 deletions seoul_21_minjaekim/Softeer/HSAT_7th/1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# [7차 Softeer 정기 역량 진단] 1번 - 자동차 테스트

## 카테고리

자료구조, 해시 테이블

## 시간복잡도

`O(N * log N + Q)`

## 문제

자동차의 연비들을 제공해준다.

자동차 중 임의의 3개를 골랐을 때, 중앙값이 `m`이 될 수 있는 서로 다른 경우의 수를 구하라.

n대의 자동차에 대한 연비의 정보와 `q`개의 `m`값이 주어진다.

## 제약 조건

- 1 ≤ n ≤ 50,000
- 1 ≤ q ≤ 200,000
- 1 ≤ 연비 ≤ 1,000,000,000
- 1 ≤ m ≤ 1,000,000,000
- 각 차량의 연비는 모두 다르다.

## 시간 제약

- Java : 3초
- C++ : 2초
- Python : 2초

# 입력 형식

- 첫 번째 줄에 `n`, `q`가 주어진다.
- 두 번째 줄에 `n`개의 자동차의 연비에 해당하는 값이 공백을 사이에 두고 주어진다.
- 세 번째 줄부터 `q`개의 줄에 걸쳐 각 줄에 `m`값이 주어진다.

# 출력 형식

`q`개의 줄에 걸쳐 각 줄에 `m`값이 중앙값이 될 수 있는 서로 다른 경우의 수를 출력한다.

## 해설

데이터를 입력받는다. `O(N)`

```cpp
int n, q;
cin >> n >> q;

int cars[50000];
for (int i = 0; i < n; ++i)
cin >> cars[i];
```

입력받은 데이터를 정렬한다. `O(N * log N)`

```cpp
sort(cars, cars + n);
```
정렬된 데이터를 키로, 인덱스를 값으로 하는 해시 테이블을 만든다. 이때 해시 테이블에 없는 값을 조회했을때 나오는 리턴값인 `0`과 구분을 위해 인덱스에 `1`을 더해서 저장한다. `O(N)`
```cpp
unordered_map<int, int> map;
for (int i = 0; i < n; ++i)
map[cars[i]] = i + 1;
```

`q`개의 `m`값을 입력받아 해시 테이블에서 조회한다. 3개의 값을 뽑았을 때, `m`이 중간값이 되는 경우는 `m`의 왼쪽에서 한 개, `m`의 오른쪽에서 한 개를 뽑는 경우의 수와 같다. 이는 `m`의 왼쪽 개수 * `m`의 오른쪽 개수로 상수시간으로 계산이 가능하다. `O(q)`

```cpp
for (int i = 0; i < q; ++i) {
int m, m_idx;
cin >> m;
m_idx = map[m];
cout << (m_idx ? (m_idx - 1) * (n - m_idx) : m_idx) << '\n';
}
```

## 문제 분석

문제의 제약조건에서 알 수 있다싶이, `n`의 최대값이 `50,000`이고 `q`의 최대값이 `200,000`이다. `n``50,000`이고 `q``200,000`이라면, `n`개의 자동차 중 임의의 3개를 직접 골라서, 중앙값이 `m`이 될 수 있는 서로 다른 경우의 수를 구하는 것은 `O(N^3)`의 시간복잡도를 가진다. 이는 제한시간인 `2초`를 넘어가기 때문에, `O(N^3)`의 알고리즘으로는 풀 수 없다.

이는 최소한 `O(Q * log N)`의 알고리즘으로 풀어야 한다는 것을 의미한다.

`O(Q * log N)`의 알고리즘으로 풀기 위해서는, `n`개의 자동차의 연비를 정렬한 다음 각 `q`에 대해 `m`의 인덱스를 이진 탐색으로 찾아야 한다.

본 풀이와 같이 해시 테이블을 이용한 `O(N * log N + Q)` 알고리즘으로도 풀 수 있다.

0 comments on commit eec0007

Please sign in to comment.