-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
277 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
--- | ||
title: [C++/백준 17928] 오큰수 | ||
date: "2022-08-29" | ||
description: "[C++/백준 17928] 오큰수 문제 풀이" | ||
tag: ["algorithm"] | ||
--- | ||
|
||
## 문제 | ||
|
||
크기가 N인 수열 A = A1, A2, ..., AN이 있다. 수열의 각 원소 Ai에 대해서 오큰수 NGE(i)를 구하려고 한다. Ai의 오큰수는 오른쪽에 있으면서 Ai보다 큰 수 중에서 가장 왼쪽에 있는 수를 의미한다. 그러한 수가 없는 경우에 오큰수는 -1이다. | ||
|
||
예를 들어, A = [3, 5, 2, 7]인 경우 NGE(1) = 5, NGE(2) = 7, NGE(3) = 7, NGE(4) = -1이다. A = [9, 5, 4, 8]인 경우에는 NGE(1) = -1, NGE(2) = 8, NGE(3) = 8, NGE(4) = -1이다. | ||
|
||
### 첫 번째 코드 (38% 시간초과) | ||
|
||
```jsx | ||
#include <iostream> | ||
#include <stack> | ||
|
||
using namespace std; | ||
|
||
int main() | ||
{ | ||
ios_base :: sync_with_stdio(false); | ||
cin.tie(NULL); | ||
cout.tie(NULL); | ||
|
||
int n; | ||
int input; | ||
|
||
stack<int> st; | ||
stack<int> less; | ||
|
||
cin >> n; | ||
int arr[n]; | ||
|
||
for(int i = 0 ; i < n ; i++){ | ||
cin >> arr[i]; | ||
} | ||
for(int i = n-1 ; i >=0 ; i--){ | ||
st.push(arr[i]); | ||
} | ||
|
||
for(int i = 0 ; i < n ; i++){ | ||
int cur = arr[i]; | ||
st.pop(); | ||
if(st.empty()){ | ||
cout << "-1 "; | ||
continue; | ||
} | ||
|
||
while(!st.empty()){ | ||
if(cur < st.top()){ | ||
cout << st.top() <<" "; | ||
while(!less.empty()){ | ||
st.push(less.top()); | ||
less.pop(); | ||
} | ||
break; | ||
}else{ | ||
less.push(st.top()); | ||
st.pop(); | ||
|
||
if(st.empty()){ | ||
cout << "-1 "; | ||
while(!less.empty()){ | ||
st.push(less.top()); | ||
less.pop(); | ||
} | ||
break; | ||
|
||
} | ||
} | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
``` | ||
|
||
골드 4, 시간제한 1초, N 100만 에서 시간복잡도를 신경써야하는 문제임을 알 수 있었다... | ||
|
||
처음에 짠 코드는 스택 두개와 입력받은 수열 배열을 만들어놓고, 수열의 맨 왼쪽부터 체크해서 | ||
|
||
수열이 3 5 2 7 이면 스택 하나에는 3 5 2 7 이렇게 넣어놓고 시작했다. | ||
|
||
현재 원소가 3이면, 먼저 스택의 맨 위(=자기 자신)를 pop 한 다음 (5 2 7) | ||
|
||
자신보다 작으면 less 스택에 넣고, 자신보다 크면 출력 후 less 배열 원소들을 다시 stack으로 넣어서 복구 시켜줬다. | ||
|
||
왼쪽부터 시작하는 게 왼쪽에 있는 가장 큰 수를 빨리 찾을 수 있을거라 생각하고 알고리즘을 짰지만 | ||
|
||
스택 두 개를 두고 매 경우마다 복구시켜주면서 for과 while문이 중첩되었고 역시나 38%에서 시간초과가 났다 ^^; | ||
|
||
스택 하나로 해결할 수 있는 방법이 필요했다. | ||
|
||
### 통과 코드 | ||
|
||
첫번째 시도때는 모든 원소를 스택에 넣어놓고 하나씩 제거해갔는데, | ||
|
||
수열의 오른쪽부터 체크하면서 스택에 원소를 추가하는 식으로 과정이 더 간단해졌다. | ||
|
||
수열의 오른쪽부터 체크하면서 스택의 맨 위 원소가 수열보다 크면 출력하고, 작으면 제거하고, 스택이 비었으면 오큰수가 없으므로 -1을 출력한다. | ||
|
||
오른쪽에 있는 애들 중, 자기자신보다 크면서 가장 왼쪽에 있는 애를 찾는 문제이기 때문에 | ||
|
||
오른쪽 -> 왼쪽으로 가면서 자기자신보다 작은 애들은 스택에서 제거하고 다음 차례로 넘기니 | ||
|
||
매차례 스택을 복구 시켜줬던 첫번째 시도보다 시간도 줄어들고 코드도 깔끔해졌다. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
--- | ||
title: [C++/백준 2110] 공유기 설치 | ||
date: "2022-09-14" | ||
description: "[C++/백준 2110] 공유기 설치 문제 풀이" | ||
tag: ["algorithm"] | ||
--- | ||
|
||
```jsx | ||
#include <iostream> | ||
#include <algorithm> | ||
using namespace std; | ||
|
||
int home[200001]; | ||
int ans = 0; | ||
|
||
void binary_search(int n, int c){ | ||
|
||
int l = 0; | ||
int r = home[n-1] - home[0]; | ||
|
||
while(1){ | ||
if(l > r){ | ||
return; | ||
} | ||
|
||
int mid = (l + r) / 2; | ||
// 거리를 mid 이상으로 해서 몇개의 공유기를 설치할 수 있는가? | ||
int count = 1; | ||
|
||
int compare = home[0]; | ||
for(int i = 1 ; i < n ; i ++){ | ||
if(home[i] - compare >= mid){ | ||
count++; | ||
compare = home[i]; | ||
} | ||
} | ||
|
||
if(count < c){ //설치할 수 없다. 거리를 줄이자. | ||
r = mid - 1; | ||
}else{ //설치할 수 있다. 거리를 늘린다. | ||
l = mid + 1; | ||
ans = max(ans, mid); | ||
} | ||
} | ||
} | ||
|
||
int main() | ||
{ | ||
ios_base :: sync_with_stdio(false); | ||
cin.tie(NULL); | ||
cout.tie(NULL); | ||
|
||
int n, c; | ||
cin >> n >> c; | ||
|
||
for(int i = 0 ; i < n ; i++){ | ||
cin >> home[i]; | ||
} | ||
sort(home, home + n); | ||
|
||
binary_search(n, c); | ||
|
||
cout << ans; | ||
|
||
return 0; | ||
} | ||
``` | ||
|
||
이분 탐색 중 parametric search 문제이다. | ||
|
||
집 좌표 범위 (0 ≤ xi ≤ 1,000,000,000) 를 보고 시간초과가 관건이겠군 하고 이분 탐색 힌트를 얻을 수 있을 것 같다. | ||
|
||
+) 나는 뭔가 거리를 가능한 크게 하여~ 가장 인접한 거리를 최대로~ 등등 최대로 하라는거냐 최소로 하라는거냐 어캐 풀라는거지 싶으면 parametric search를 떠올린다 | ||
|
||
parametric search를 떠올렸으면 문제를 **가능한 \_\_중에서 최대 값을 구하는 문제**로 바꾼다. | ||
|
||
여기서는 공유기를 설치할 수 있는 거리 중에서 최대 값을 구하는 문제로 바꿨다. | ||
|
||
범위 (l 과 r 사이)는 최대한 크게 잡는다. | ||
|
||
구하는 값을 이분 탐색의 mid로 둔다. 여기서는 공유기 사이의 거리를 mid로 두었다. | ||
|
||
parametric search에서 주의할 점은 공유기가 3개 있고, 각 거리마다 설치할 수 있는 공유기의 개수(count)를 셌을 때 | ||
|
||
3개보다 **더 많이 설치할 수 있어도 답이 될 수 있다**는 것이다. | ||
|
||
그래서 count == C(문제에서 주어진 공유기의 개수)인 경우와 count > C인 경우를 나누지 않고 같이 묶었다. | ||
|
||
공유기를 설치할 수 있는 거리를 찾았다고 그대로 끝내는 것이 아니라, 더 최적화된 답을 찾을 수 있는 가능성이 남아있으므로거리를 의미하는 mid가 커지는 방향으로, 즉, l을 늘려서 범위를 좁히는 방향으로 탐색을 더 진행한다. | ||
|
||
거리를 mid 이상으로 했을 때 공유기를 최대 몇 개 설치할 수 있는지 구하는 부분이 고민이었는데, | ||
|
||
1 2 4 8 9 가 있을 때 꼭 공유기를 1에 설치해야하는지에 대한 확신이 없어서 이중 for문으로 시작점을 옮겨가며 count 했더니 시간초과가 났다. | ||
|
||
생각해보니 어차피 1에 공유기를 설치하는 게 1을 건너뛰고 2에 공유기를 설치하는 경우를 포함하므로 1부터 시작하는게 맞았다. for문을 하나로 바꾸고 통과했다. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
--- | ||
title: [C++/백준 5052] 전화번호 목록 | ||
date: "2022-09-14" | ||
description: "[C++/백준 5052] 전화번호 목록 문제 풀이" | ||
tag: ["algorithm"] | ||
--- | ||
|
||
```jsx | ||
//5052 전화번호 목록 | ||
#include <iostream> | ||
#include <algorithm> | ||
|
||
using namespace std; | ||
|
||
|
||
int main() | ||
{ | ||
ios_base :: sync_with_stdio(false); | ||
cin.tie(NULL); | ||
cout.tie(NULL); | ||
|
||
int t; | ||
cin >> t; | ||
while(t--){ | ||
int n; | ||
cin >> n; | ||
string phone[n]; | ||
for(int i = 0 ; i < n ; i++){ | ||
cin >> phone[i]; | ||
} | ||
sort(phone, phone + n); | ||
|
||
string compare = phone[0]; | ||
|
||
bool consistent = true; | ||
for(int i = 1 ; i < n ; i++){ | ||
bool check; | ||
if(compare.length() > phone[i].length()){ | ||
check = (compare.substr(0, phone[i].length()) == phone[i]); | ||
}else{ | ||
check = (compare == phone[i].substr(0, compare.length())); | ||
} | ||
|
||
if(check){ | ||
cout << "NO\n"; | ||
consistent = false; | ||
break; | ||
} | ||
compare = phone[i]; | ||
|
||
} | ||
|
||
if(consistent){ | ||
cout << "YES\n"; | ||
} | ||
|
||
} | ||
|
||
return 0; | ||
} | ||
``` | ||
|
||
나는 이문제가 왜 골드 4인지 모르겠다 트라이 안쓰고 그냥 정렬해도 풀리는데.. | ||
|
||
같은 문자열 문제 중에 1141 접두사 실버2 문제가 있는데 이게 더 어려웠던 거 같다. | ||
|
||
그냥 한 번 정렬해준 다음, 앞에서부터 두개씩 비교해가며 | ||
|
||
한쪽이 남은 한쪽의 접두사가 되는지 체크하는 check라는 bool 변수를 썼고, | ||
|
||
check가 true일 때 일관성을 의미하는 변수 consistent를 false로 바꿔줬다. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
export const POST_PER_PAGE = 1 | ||
export const POST_PER_PAGE = 10 |