๋ฐ˜์‘ํ˜•

์ด์ง„ ํƒ์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ ํŠน์ • ๊ฐ’์„ ํšจ์œจ์ ์œผ๋กœ ์ฐพ๊ธฐ ์œ„ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค. ์ด์ง„ ํƒ์ƒ‰์€ ๊ฐ’์˜ ํฌ๊ธฐ์— ๋”ฐ๋ผ ํƒ์ƒ‰ ๋ฒ”์œ„๋ฅผ ์ ˆ๋ฐ˜์œผ๋กœ ์ค„์—ฌ๊ฐ€๋ฉฐ ์›ํ•˜๋Š” ๊ฐ’์„ ์ฐพ์•„๋‚ด๋Š” ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” $O(\log n)$์œผ๋กœ ํšจ์œจ์ ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด 1024๊ฐœ ์š”์†Œ๋ฅผ ๊ฐ€์ง„ ๋ฐฐ์—ด์—์„œ ์›ํ•˜๋Š” ๊ฐ’์„ ์ฐพ์„ ๋•Œ ์ตœ๋Œ€ 10๋ฒˆ์˜ ๋น„๊ต๋งŒ ํ•„์š”ํ•˜๋‹ค.

 

ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž์ฃผ ๋ณ€๊ฒฝ๋œ๋‹ค๋ฉด ๋งค๋ฒˆ ์ •๋ ฌ์„ ํ•ด์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํšจ์œจ์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค. ๋ฐ์ดํ„ฐ ์‚ฝ์ž…/์‚ญ์ œ๊ฐ€ ๋นˆ๋ฒˆํ•œ ๊ฒฝ์šฐ์—” ํ•ด์‹œ ํ…Œ์ด๋ธ” ๊ฐ™์€ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ๋” ๋‚˜์„ ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ’ก ์ด์ง„ ํƒ์ƒ‰์€ ์ด๋ถ„ ํƒ์ƒ‰์ด๋ผ๊ณ ๋„ ๋ถˆ๋ฆฐ๋‹ค.

 

 

์ด์ง„ ํƒ์ƒ‰ ๊ธฐ๋ณธ


์ด์ง„ ํƒ์ƒ‰ ๊ณผ์ •์„ ์‹œ๊ฐํ™”ํ•œ ์ด๋ฏธ์ง€

  1. ์ค‘์•™๊ฐ’ ๊ณ„์‚ฐ
    • ๋ฐฐ์—ด์˜ ์ค‘๊ฐ„ ์ธ๋ฑ์Šค๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค mid = Math.floor((left + right) / 2)
    • ์ค‘์•™๊ฐ’๊ณผ ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’(target)์„ ๋น„๊ตํ•œ๋‹ค
  2. ๊ฐ’ ๋น„๊ต ๋ฐ ๋ฒ”์œ„ ์กฐ์ •
    1. ๋ฐ˜๋ณต ์ข…๋ฃŒ
      • ์ค‘์•™๊ฐ’์ด ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’๊ณผ ๊ฐ™๋‹ค๋ฉด ํƒ์ƒ‰์„ ์ข…๋ฃŒํ•˜๊ณ  ํ•ด๋‹น ์ธ๋ฑ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค
      • ๋” ์ด์ƒ ํƒ์ƒ‰ ๋ฒ”์œ„๊ฐ€ ์—†์œผ๋ฉด(left > right) ๋ฐ˜๋ณต์„ ์ข…๋ฃŒํ•˜๊ณ  -1์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค
    2. ๊ณ„์† ๋ฐ˜๋ณต
      • ์ค‘์•™๊ฐ’์ด ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’๋ณด๋‹ค ์ž‘๋‹ค๋ฉด, ํƒ์ƒ‰ ๋ฒ”์œ„๋ฅผ ์˜ค๋ฅธ์ชฝ ์ ˆ๋ฐ˜์œผ๋กœ ์ค„์ธ๋‹ค left = mid + 1
      • ์ค‘์•™๊ฐ’์ด ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’๋ณด๋‹ค ํฌ๋‹ค๋ฉด, ํƒ์ƒ‰ ๋ฒ”์œ„๋ฅผ ์™ผ์ชฝ ์ ˆ๋ฐ˜์œผ๋กœ ์ค„์ธ๋‹ค right = mid - 1

 

๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ๊ตฌํ˜„ํ•œ ์ด์ง„ ํƒ์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜ โ–ผ

const binarySearch = (sortedArr, target) => {
  let left = 0;
  let right = sortedArr.length - 1;

  while (left <= right) {
    const mid = Math.floor((left + right) / 2); // ์ค‘์•™ ์ธ๋ฑ์Šค ๊ณ„์‚ฐ

    if (sortedArr[mid] === target) return mid; // ์›ํ•˜๋Š” ๊ฐ’์„ ์ฐพ์•˜์„ ๋•Œ

    if (sortedArr[mid] < target) left = mid + 1; // ํƒ์ƒ‰ ๋ฒ”์œ„ ์˜ค๋ฅธ์ชฝ ์ ˆ๋ฐ˜์œผ๋กœ ์ถ•์†Œ
    else right = mid - 1; // ํƒ์ƒ‰ ๋ฒ”์œ„ ์™ผ์ชฝ ์ ˆ๋ฐ˜์œผ๋กœ ์ถ•์†Œ
  }

  return -1; // ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’์ด ์—†์„ ๋•Œ
};

 

 

์ด์ง„ ํƒ์ƒ‰ ์‘์šฉ


๐Ÿ’ก bisect๋Š” “์ด๋“ฑ๋ถ„ํ•˜๋‹ค”๋ผ๋Š” ๋œป์œผ๋กœ ์–ด๋–ค ๊ฒƒ์„ ๋‘ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

ํŒŒ์ด์ฌ์—์„  ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด bisect๋ผ๋Š” ๋ชจ๋“ˆ์„ ์ œ๊ณตํ•œ๋‹ค. ์ด ๋ชจ๋“ˆ์—” ์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ ํŠน์ • ๊ฐ’์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์œ„์น˜๋ฅผ ์ฐพ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” bisect_left, bisect_right ํ•จ์ˆ˜๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋„ ์ด์ง„ ํƒ์ƒ‰ ๋กœ์ง์„ ์‚ด์ง๋งŒ ๋ณ€ํ˜•ํ•ด์„œ ๋™์ผํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

bisect_left, bisect_right ์ž‘๋™ ๊ณผ์ •์„ ์‹œ๊ฐํ™”ํ•œ ์ด๋ฏธ์ง€. ๋ฆฌ์ŠคํŠธ์—์„œ target๊ณผ ๊ฐ™์€ ์ˆซ์ž๋Š” *๋กœ ํ‘œ์‹œํ•ด๋’€๋‹ค

 

bisect_left (์ขŒ์ธก ์ด๋ถ„ ํƒ์ƒ‰)

์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ target์„ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ์™ผ์ชฝ ์œ„์น˜(์ธ๋ฑ์Šค)๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. target๊ณผ ๋™์ผํ•œ ๊ฐ’์ด 1๊ฐœ ํ˜น์€ ์—ฌ๋Ÿฌ ๊ฐœ ์กด์žฌํ•˜๋ฉด, ๊ฐ€์žฅ ์™ผ์ชฝ์— ์žˆ๋Š” target์˜ ์œ„์น˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. target๊ณผ ๋™์ผํ•œ ๊ฐ’์ด ์—†๋‹ค๋ฉด, target๋ณด๋‹ค ํฐ ๊ฐ’์ด ์ฒ˜์Œ ๋‚˜ํƒ€๋‚œ ์œ„์น˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

const bisectLeft = (sortedArr, target) => {
  let left = 0;
  let right = sortedArr.length;

  while (left < right) {
    const mid = Math.floor((left + right) / 2);
    if (sortedArr[mid] < target) left = mid + 1;
    else right = mid;
  }
  return left;
};

const arr = [1, 2, 4, 4, 6];

console.log(bisectLeft(arr, 4)); // 2
console.log(bisectLeft(arr, 3)); // 2

 

์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ๋œ ๋ฐฐ์—ด์ด๋ผ๋ฉด bisect_left ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์ธ๋ฑ์Šค ์ดํ›„์— ์žˆ๋Š” ์š”์†Œ๋“ค์€ ๋ชจ๋‘ target๊ณผ ๊ฐ™๊ฑฐ๋‚˜ ํฌ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์—์„œ target๊ณผ ๊ฐ™๊ฑฐ๋‚˜ ํฐ ์š”์†Œ์˜ ๋ชจ๋“  ๊ฐœ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค.

const countGreaterOrEqual = (sortedArr, target) => {
  const leftIndex = bisectLeft(sortedArr, target);
  return sortedArr.length - leftIndex; // target๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€ ์š”์†Œ์˜ ์ˆ˜
};

const arr = [1, 2, 4, 4, 6];
console.log(countGreaterOrEqual(arr, 4)); // 3

 

target์ด 4์ผ ๋•Œ bisect_left๋Š” 2๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , target๊ณผ ๊ฐ™๊ฑฐ๋‚˜ ํฐ ์š”์†Œ์˜ ๋ชจ๋“  ๊ฐœ์ˆ˜๋Š” 5-2=3์ด๋‹ค

 

bisect_right (์šฐ์ธก ์ด๋ถ„ ํƒ์ƒ‰)

์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ target์„ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ์˜ค๋ฅธ์ชฝ ์œ„์น˜(์ธ๋ฑ์Šค)๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. target๊ณผ ๋™์ผํ•œ ๊ฐ’์ด 1๊ฐœ ํ˜น์€ ์—ฌ๋Ÿฌ ๊ฐœ ์กด์žฌํ•˜๋ฉด, ๊ฐ€์žฅ ์˜ค๋ฅธ์ชฝ์— ์žˆ๋Š” target์˜ ๋‹ค์Œ ์œ„์น˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. target๊ณผ ๋™์ผํ•œ ๊ฐ’์ด ์—†๋‹ค๋ฉด, target๋ณด๋‹ค ํฐ ๊ฐ’์ด ์ฒ˜์Œ ๋‚˜ํƒ€๋‚œ ์œ„์น˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

const bisectRight = (sortedArr, target) => {
  let left = 0;
  let right = sortedArr.length;

  while (left < right) {
    const mid = Math.floor((left + right) / 2);
    if (sortedArr[mid] <= target) left = mid + 1;
    else right = mid;
  }
  return left;
};

const arr = [1, 2, 4, 4, 6];

console.log(bisectRight(arr, 4)); // 4
console.log(bisectRight(arr, 3)); // 2

 

์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ๋œ ๋ฐฐ์—ด์ด๋ผ๋ฉด bisect_right ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์ธ๋ฑ์Šค ์ด์ „์— ์žˆ๋Š” ์š”์†Œ๋“ค์€ ๋ชจ๋‘ target๊ณผ ๊ฐ™๊ฑฐ๋‚˜ ์ž‘๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด bisect_right๊ฐ€ 4๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค๋ฉด 0~3 ์ธ๋ฑ์Šค์— ์žˆ๋Š” ์š”์†Œ๋Š” target๊ณผ ๊ฐ™๊ฑฐ๋‚˜ ์ž‘์€ ๊ฐ’๋“ค์ด๋‹ค. ๋”ฐ๋ผ์„œ bisect_right๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ธ๋ฑ์Šค๋Š” ๊ณง target๊ณผ ๊ฐ™๊ฑฐ๋‚˜ ์ž‘์€ ์š”์†Œ์˜ ๊ฐœ์ˆ˜์™€ ๊ฐ™๋‹ค.

const countLessOrEqual = (sortedArr, target) => {
  return bisectRight(sortedArr, target);
};

const arr = [1, 2, 4, 4, 6];
console.log(countLessOrEqual(arr, 4)); // 4

 

target์ด 4์ผ ๋•Œ bisect_right๋Š” 4๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ด๋Š” ๊ณง target๊ณผ ๊ฐ™๊ฑฐ๋‚˜ ์ž‘์€ ๋ชจ๋“  ์š”์†Œ์˜ ๊ฐœ์ˆ˜์™€ ๊ฐ™๋‹ค

 


๊ธ€ ์ˆ˜์ •์‚ฌํ•ญ์€ ๋…ธ์…˜ ํŽ˜์ด์ง€์— ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”
๋ฐ˜์‘ํ˜•