📍 백준 000번 - 제목 문제 프로그래밍 언어
🧩문제 요약
<이진탐색>
제시된 크기 n만큼 수가 입력된다.
이후, 타겟값이 m개 주어질때 해당 타겟값이 배열에 몇개가 들어있는지를 순서대로 출력하라.
🧾내가 작성한 초기 코드
#include <iostream>
#include <algorithm>
using namespace std;
int input_card[500001], find_card[500001];
int countCard(const int num, int size){
cout << "finding a same card...\n";
// binary search로 타겟값 위치 찾기
int start = 0, end = size-1, mid = (start+end)/2;
int cnt=0 ;
while(start <= end){
cout << "start : " << start << ", end : " << end << ", mid : " << mid << ", mid_val : " << input_card[mid] <<"\n";
if(num==input_card[mid]){
cout << "We got same card. Now we are searching a another...\n";
// 같은 카드가 있는지 탐색
for(int i=start; i<=end; i++){
cout << "Is it the same ? " << num << ", " << input_card[i] << "\n";
if(num==input_card[i]){
cnt++;
}
cout << "count : " << cnt << " \n";
}
return cnt;
break;
}else if(num < input_card[mid]){
cout << "target num is smaller than mid--- " << num << " < " << input_card[mid] <<"\n";
end = mid-1;
mid = (start+end)/2;
}else if(num > input_card[mid]){
cout << "target num is bigger than mid--- " << num << " > " << input_card[mid] <<"\n";
start = mid+1;
mid = (start+end)/2;
}
}
return 0;
}
int main(){
int n,m,i;
cin >> n ;
for(i=0; i<n; i++){
cin >> input_card[i];
}
cin >> m ;
for(i=0; i<m; i++){
cin >> find_card[i];
}
sort(input_card, input_card+n);
////////
cout << "checking sort...\n";
for(i=0; i<n; i++){
cout<< input_card[i];
}
cout << "\n";
////////
for(i=0; i<m; i++){
cout << "target num : " << find_card[i] << "\n";
cout << countCard(find_card[i], n) << " ";
cout << "\n";
}
cout << "\n";
}
cf) 영어문장은 그냥 틀려도 그러려니 봐주세여.. ㅎㅎ
👍이 문제에서 배운점
😕 문제점 1.
초기 코드에서는 시간초과 문제가 발생한다.
아마도 이진 탐색 이후 같은 카드가 있는지 탐색하는 부분이 worst case가 O(n)이여서 그런것 같다.
이진탐색으로 잘 구현해놓고 여기서 다시 선형탐색이 들어간다. 이부분을 어떻게 처리해야 할까 고민을 했다.
✅ 이진 탐색을 이용한 std::upper_bound(), std::lower_bound()
upper_bound(), lower_bound() 는 c++에서 이진탐색으로 원소를 탐색하는 함수이다.
두 함수는 algorithm헤더에 들어있다.
- lower_bound() : 찾으려는 key값보다 같거나 큰 숫자가 배열 몇 번째에서 처음 등장하는지 찾음.
- upper_bound() : 찾으려는 key값을 초과하는 숫자가 배열 몇 번째에서 처음 등장하는지 찾음.
두 함수의 사용방법은 다음과 같다.
#include <algorithm>
int input_card[500001];
upper_bound(input_card, input_card+n, target_num);
lower_bound(input_card, input_card+n, target_num);
(배열의 시작, 배열의 끝 찾고자 하는 값)을 파라미터로 넣어주면 된다.
이 두 함수의 return 값은 Iterator이기 때문에 실제 인덱스 값을 얻고 싶다면, return 값에서 배열 첫 번째 주소를 빼주면 된다.
upper_bound(input_card, input_card+n, target_num) - input_card;
lower_bound(input_card, input_card+n, target_num) - input_card;
만약 찾고자 하는 값이 없다면 last(v.end())를 반환한다.
이진 탐색을 기본으로 하기 때문에 O(logN)으로 탐색이 가능하다.
lower_bound를 사용해 key값이 몇번째 인덱스에서 처음 나타나는지 찾고 upper_bound를 사용해 key값이 나타나는 마지막 인덱스를 찾아서 둘의 차를 구하면 key값이 해당 배열에 몇개 존재하는지 계산 할 수 있다.
이렇게 완성된 코드는 다음과 같다.
🧾완성된 코드
#include <iostream>
#include <algorithm>
using namespace std;
int input_card[500001], find_card[500001];
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
// 입력받기
int n,m,i;
cin >> n ;
for(i=0; i<n; i++){
cin >> input_card[i];
}
cin >> m ;
for(i=0; i<m; i++){
cin >> find_card[i];
}
sort(input_card, input_card+n); // 이진 탐색을 위한 정렬
// upper_bound와 lower_bound를 사용한 target 값 갯수 세기
for(i=0; i<m; i++){
cout << (upper_bound(input_card, input_card+n, find_card[i])-input_card ) - (lower_bound(input_card, input_card+n, find_card[i])- input_card) << " ";
}
cout << "\n";
}
'하루 알고리즘 1문제 풀기' 카테고리의 다른 글
백준 11399번 - ATM 문제 C++ [그리디 알고리즘] (0) | 2025.04.07 |
---|---|
백준 2164번 - 카드2 문제 C++ [Queue] (0) | 2025.04.04 |
백준 1018번[brute force] - 체스판 다시 칠하기문제 C++ 초기값 설정 (0) | 2025.04.03 |
백준 11650번 - 좌표 정렬하기문제 C++ (0) | 2025.04.02 |
백준 10814번 - 나이순 정렬 문제 C++ sort()/stable_sort() (0) | 2025.04.02 |