Given an array of integers nums which is sorted in ascending order, and an integer target, write a function to search target in nums. If target exists, then return its index. Otherwise, return -1.
You must write an algorithm with O(log n) runtime complexity.
Example 1:
Input: nums = [-1,0,3,5,9,12], target = 9
Output: 4
Explanation: 9 exists in nums and its index is 4
Plain Text
복사
Example 2:
Input: nums = [-1,0,3,5,9,12], target = 2
Output: -1
Explanation: 2 does not exist in nums so return -1
Plain Text
복사
Constraints:
•
1 <= nums.length <= 104
•
104 < nums[i], target < 104
•
All the integers in nums are unique.
•
nums is sorted in ascending order.
My solution
정수 배열 nums 가 주어진다. 오름차순으로 정렬되어 있다. target 이 주어지면 찾는 함수를 작성하라.
있으면 인덱스를 반환하고, 없으면 -1을 반환해라.
O(log n)의 시간복잡도를 가진 알고리즘으로 작성하라.
Input: nums = [-1,0,3,5,9,12], target = 9
Output: 4
Explanation: 9 exists in nums and its index is 4
JavaScript
복사
find 메서드를 구현하는 것으로 생각할 수 있다. 이진 탐색을 사용한다.
1.
시작포인터와 끝 포인터, 그리고 중앙을 가리키는 포인터가 있다.
2.
중앙 값은 매번 루프마다 업데이트된다. 시작과 끝 포인터가 같아질 때까지는 범위가 존재하므로 계속해서 target을 찾아나갈 것이다.
3.
mid 인덱스에 접근했을 때의 값이 내가 찾으려는 target인지 조건문으로 검사한다.
a.
맞으면 true를 반환하면 된다.
b.
이 때 만약 target 보다 크다면 그 값을 기준으로 끝 포인터를 업데이트해주어도 그보다 더 큰 값을 검사할 필요가 없기 때문에 탐색이 확 줄어든다.
c.
반대로 target보다 작다면 시작 포인터를 그 값보다 1 크도록 업데이트해서 탐색 범위를 확 좁혀줄 수 있다.
function BinarySearch(arr, len, key) {
let start = 0;
let end = len - 1;
let mid;
while (end - start >= 0) {
mid = (start + end) / 2; // 중앙 값
if (arr[mid] == key) {
// key값을 찾았을때
return true;
}
if (arr[mid] > key) {
// key값이 mid의 값보다 작을때 (왼쪽으로)
end = mid - 1;
} else {
// key값이 mid의 값보다 클때 (오른쪽으로)
start = mid + 1;
}
}
return false;
}
JavaScript
복사
여기서는 mid가 key가 되자마자 이 인덱스를 반환해주거나, 아예 찾지 못하면 false 대신 -1을 반환해주어야 하므로 함수의 return statement를 변경하면 된다.
function BinarySearch(arr, len, key) {
let start = 0;
let end = len - 1;
let mid;
while (end - start >= 0) {
mid = Math.floor((start + end) / 2);
if (arr[mid] === key) return mid;
if (arr[mid] > key) end = mid - 1;
else start = mid + 1;
}
return -1;
}
JavaScript
복사
이진탐색은 재귀로도 구현할 수 있다. 로직은 거의 같다.
함수를 실행하면서 start 포인터가 end 포인터보다 커지는 시점에 return false를 해주는 방식이고, start, end 포인터를 인수를 통해 전달하면서 줄여나가고 타겟을 찾는다.
function RecursiveBinarySearch(arr, start, end, key) {
if (start > end) return -1; // key 값이 없을 때
const mid = Math.floor((start + end) / 2);
if (arr[mid] === key) return mid;
if (arr[mid] > key) return RecursiveBinarySearch(arr, start, mid - 1, key);
return RecursiveBinarySearch(arr, mid + 1, end, key);
}
return RecursiveBinarySearch(nums, 0, nums.length - 1, target);
JavaScript
복사
코드라인이 줄어든 대신 파라미터가 1개 늘어났고 런타임은 거의 똑같았다.(68, 67ms)
Code
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
const search = function (nums, target) {
function BinarySearch(arr, len, key) {
let start = 0;
let end = len - 1;
let mid;
while (end - start >= 0) {
mid = Math.floor((start + end) / 2);
if (arr[mid] === key) return mid;
if (arr[mid] > key) end = mid - 1;
else start = mid + 1;
}
return -1;
}
return BinarySearch(nums, nums.length, target);
};
describe('BinarySearch', () => {
it('TC1', () => {
expect(search([-1, 0, 3, 5, 9, 12], 9)).toStrictEqual(4);
});
it('TC2', () => {
expect(search([-1, 0, 3, 5, 9, 12], 2)).toStrictEqual(-1);
});
});
JavaScript
복사