Binary Search
ย - Last update: 2023-08-07

Binary Search์˜ ๊ตฌํ˜„์— ๊ด€ํ•œ ์ •๋ฆฌ. ์ฃผ์ œ ์ž์ฒด๋Š” solved.ac ๊ธฐ์ค€ ์‹ค๋ฒ„ ํ‹ฐ์–ด ์ •๋„์ผ ์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ, ์ œ๋Œ€๋กœ ์“ฐ๊ธฐ๊นŒ์ง€ ์ƒ๋‹นํ•œ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ์ฃผ์ œ์ด๊ธฐ๋„ ํ•˜๋‹ค. ๋˜, ๊ฐ์ข… ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ ๋œฌ๊ธˆ์—†์ด ํŠ€์–ด๋‚˜์˜ค๋Š” 1์ˆœ์œ„. O(n)์„ O(log n)์œผ๋กœ ์ค„์—ฌ์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๋ฌด๊ธฐ.

TL;DR

Find

bool find(int v) {
int l = 0; int r = N - 1;
while (l <= r) {
int m = (l + r) / 2; // overflow prevent: l + (r - l) / 2;
if (arr[m] == v) return true;
if (arr[m] < v) {
l = m + 1;
} else {
r = m - 1;
}
}
return false;
}

Lower Bound

int lb(int v) {
int l = 0; int r = N - 1;
int ans = -1;
while (l <= r) {
int m = (l + r) / 2; // overflow prevent: l + (r - l) / 2;
if (arr[m] >= v) {
r = m - 1;
ans = m;
} else {
l = m + 1;
}
}
return ans;
}

Upper Bound

int lb(int v) {
int l = 0; int r = N - 1;
int ans = -1;
while (l <= r) {
int m = (l + r) / 2; // overflow prevent: l + (r - l) / 2;
if (arr[m] > v) {
r = m - 1;
ans = m;
} else {
l = m + 1;
}
}
return ans;
}

์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ •๋ฆฌ

์„œ๋ก 

Binary Search๋Š” ํ•ญ์ƒ ๊ตฌํ˜„์ด ํ—ท๊ฐˆ๋ฆฐ๋‹ค. ๋ฒ”์œ„๋ฅผ ์–ด๋””๊นŒ์ง€ ํ•ด์•ผํ•˜๋Š”์ง€, l, r ์„ค์ •์€ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜๋Š”์ง€ ๋“ฑ๋“ฑ...

์—ฌ๊ธฐ์„œ ๊ทธ๋Ÿฐ ๋ถ€๋ถ„๋“ค์„ ํ•œ๋ฒˆ ์ •๋ฆฌํ•˜๊ณ  ๋„˜์–ด๊ฐ€๊ณ ์ž ํ•œ๋‹ค.

Binary Search์˜ STL ์‚ฌ์šฉ ๊ตฌํ˜„

์šฐ์„  ํ‘œ์ค€์ด ๋˜๋Š” STL์„ ์‚ฌ์šฉํ•œ Binary Search ์‚ฌ์šฉ๋ฒ•์„ ํ™•์ธํ•ด๋ณด์ž. ์‚ฌ์šฉํ•  ๋•Œ vector๋Š” ์ •๋ ฌ์ด ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

binary_search๋Š” ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’์ด ์žˆ๋Š”์ง€ ์—†๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

bool isExist = binary_search(v.begin(), v.end(), tval);

lower_bound๋Š” ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€ ๊ฐ’์ด ์ฒ˜์Œ์œผ๋กœ ๋‚˜์˜ค๋Š” ์‹œ์ ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋ฐ˜ํ™˜๊ฐ’ ํ˜•ํƒœ๋Š” iterator์ด๋‹ค.

auto it = lower_bound(v.begin(), v.end(), tval);

upper_bound๋„ ๊ฑฐ์˜ ๋™์ผํ•˜์ง€๋งŒ ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€ ์ด ์•„๋‹Œ ํฐ ์ด๋‹ค. ์‚ฌ์šฉ๋ฒ•์€ ์™„์ „ํžˆ ๋™์ผํ•˜๋‹ค. (๊ฒฐ๊ณผ๋งŒ ๋‹ฌ๋ผ์ง„๋‹ค)

auto it = upper_bound(v.begin(), v.end(), tval);

Binary Search์˜ ์˜์˜๋Š” ์›์†Œ๋ฅผ ์ฐพ์„ ๋•Œ ์ „์ฒด ์›์†Œ(O(n))๋ฅผ ์ฐพ์ง€ ์•Š์•„๋„ ๋จ์— ๊ทธ ์˜์˜๊ฐ€ ์žˆ๋‹ค. ์ ˆ๋ฐ˜์”ฉ ์ฐพ์„ ์›์†Œ๊ฐ€ ์ค„์–ด๋“œ๋ฏ€๋กœ Master Theorem์— ์˜ํ•ด ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ O(log n)์œผ๋กœ ์ค„์–ด๋“ค๊ฒŒ ๋œ๋‹ค.

Binary Search์˜ ์ง์ ‘๊ตฌํ˜„

์ง์ ‘ ๊ตฌํ˜„์‹œ์— ์‹ ๊ฒฝ์จ์•ผ ํ•  ํฌ์ธํŠธ๋“ค์ด ๋งŽ์ด ์žˆ๋‹ค.

loop์‹œ l, r ์กฐ์ • ๋ฌธ์ œ

์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ๋œ arr[]์—์„œ, ์›์†Œ๋ฅผ ์ฐพ์œผ๋ฉด ์›์†Œ index, ๋ชป์ฐพ์œผ๋ฉด -1์„ ๋ฆฌํ„ดํ•˜๋Š” ์˜ˆ์‹œ๋ฅผ ๋ณด์ž.

// [s, e] ๊ตฌ๊ฐ„ ์‚ฌ์šฉ
int binarySearch(int arr[], int s, int e, int tval) {
int l = s, int r = e, mid;
while (l <= r) {
mid = (l + r) >> 1;
if (tval == arr[mid]) return mid;
else if (tval < arr[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
}
return -1;
}

ํ‘œ๋กœ ํ•˜๋‚˜ ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด์ž.

index01234567
value58101417202225

์ด ๊ฒฝ์šฐ, 10์„ ์ฐพ๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

  1. ์ฒซ๋ฒˆ์งธ loop์—์„œ์˜ ๊ฐ param ๊ฐ’์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
    • l: 0
    • r: 7
    • mid: 3
    • ๊ฒฐ๊ณผ: arr[3] = 14 > 10 ์ด๋ฏ€๋กœ, r ์ด 2๋กœ ์กฐ์ •๋œ๋‹ค.
  2. ๋‘๋ฒˆ์งธ loop๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋œ๋‹ค.
    • l: 0
    • r: 2
    • mid: 1
    • ๊ฒฐ๊ณผ: arr[1] = 8 > 10 ์ด๋ฏ€๋กœ, l์ด 2๋กœ ์กฐ์ •๋œ๋‹ค.
  3. ์„ธ๋ฒˆ์งธ loop๋Š” l == r == 2์ด๋ฏ€๋กœ, ๊ฐ’์„ ์ฐพ๊ณ  ์ข…๋ฃŒ๋œ๋‹ค.

์ฆ‰, ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ๋œ ๋ฐฐ์—ด ๊ธฐ์ค€์œผ๋กœ, ์ค‘์•™์„ ๋ดค์„ ๋•Œ ๊ทธ ๊ฐ’์ด ์ฐพ๋Š” ๊ฐ’๋ณด๋‹ค ๋” ํฌ๋ฉด ํƒ€๊ฒŸ๊ฐ’์€ ์ขŒ์ธก์— ์žˆ์„ ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ r์ด ์กฐ์ •๋˜๋Š” ๊ฒƒ์ด๋ฉฐ, ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ l์ด ์กฐ์ •๋œ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

lower_bound์™€ upper_bound์˜ ์‹ค ๊ตฌํ˜„

์ด ๊ฒฝ์šฐ ๋” ๋ถ„๊ธฐ๋ฅผ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ, ๊ตฌํ˜„์ด ์‰ฌ์šด ๋ฐฉ๋ฒ•์œผ๋กœ ์•„๋ž˜์ฒ˜๋Ÿผ binarySearch ํ•จ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

// [s, e) ๊ตฌ๊ฐ„ ์‚ฌ์šฉ
int lowerBound(int arr[], int s, int e, int tval) {
int l = s, int r = e, mid, ans = e; // ans์˜ ์ดˆ๊ธฐ๊ฐ’์— ์œ ์˜
while (l <= r) {
mid = (l + r) >> 1;
if (tval == arr[mid]) {
ans = mid;
r = mid - 1; // ๋งŒ์•ฝ ์›์†Œ๊ฐ€ 1 2 3 3 3 3 3 4 5 ์ฒ˜๋Ÿผ ๋˜์–ด ์žˆ๋‹ค๋ฉด, ์ฒ˜์Œ ์ฐพ์€ 3๋ณด๋‹ค ๋” ์™ผ์ชฝ์— 3์ด ๋˜ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ตฌ๊ฐ„์„ ์™ผ์ชฝ์œผ๋กœ ํ•ด์„œ ๊ณ„์† ํƒ์ƒ‰ํ•œ๋‹ค.
}
else if (tval < arr[mid]) {
ans = mid; // ์—ฌ๊ธฐ์—๋„ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
r = mid - 1;
} else {
l = mid + 1;
}
}
return ans;
}

lower_bound์˜ ๊ฒฝ์šฐ ์œ„์ฒ˜๋Ÿผ๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋œ๋‹ค. ๊ฐ™์„๋•Œ return ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋” ์ฐพ๋Š” ๊ฒƒ์ด ํฌ์ธํŠธ.

upper_bound๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

// [s, e) ๊ตฌ๊ฐ„ ์‚ฌ์šฉ
int upperBound(int arr[], int s, int e, int tval) {
int l = s, int r = e, mid, ans = e; // ans์˜ ์ดˆ๊ธฐ๊ฐ’์— ์œ ์˜
while (l <= r) {
mid = (l + r) >> 1;
if (tval == arr[mid]) { // lowerBound ๊ตฌํ˜„ ๋Œ€๋น„ ๋‹ฌ๋ผ์ง€๋Š” ๋ถ€๋ถ„
l = mid + 1; // ๋” ํฐ๊ฑธ ์ฐพ๋Š” ๊ฑฐ๋‹ˆ๊นŒ ์ขŒ์ธก์ด ์•„๋‹Œ ์šฐ์ธก์œผ๋กœ ๊ณ„์†ํ•ด์„œ ๋ณด๋ฉด ๋œ๋‹ค. (lowerBound๋Š” ๊ฒฝ๊ณ„๊ฐ’์—์„œ ์ขŒ์ธก, upper๋Š” ์šฐ์ธก)
}
else if (tval < arr[mid]) {
ans = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
return ans;
}

ans ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๋ถ€๋ถ„๋งŒ ๋ณ€๊ฒฝ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‰ฝ๊ฒŒ ํ™•์ธํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. tval == arr[mid] ๋ถ€๋ถ„์˜ ๊ตฌํ˜„๋งŒ ๋‹ฌ๋ผ์ง€๊ณ , ์ง๊ด€์ ์œผ๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค. lower_bound๋Š” ๊ฒฝ๊ณ„๊ฐ’์„ ์—…๋ฐ์ดํŠธ ํ•˜์ง€๋งŒ, upper_bound๋Š” ์•„๋‹ˆ๋‹ค.

Time Complexity

  • Find: O(logโกN)O(\log N)
  • LowerBound: O(logโกN)O(\log N)
  • UpperBound: O(logโกN)O(\log N)
๐Ÿท๏ธ ์ฃผ์ œ ๋ชฉ๋ก: