{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1>704. Binary Search</h1>\n",
    "<hr>\n",
    "\n",
    "<!--Copy Paste Leetcode statement between-->\n",
    "<p>Given a <strong>sorted</strong> (in ascending order) integer array <code>nums</code> of <code>n</code> elements and a <code>target</code> value, write a function to search <code>target</code> in <code>nums</code>. If <code>target</code> exists, then return its index, otherwise return <code>-1</code>.</p>\n",
    "\n",
    "<p><br>\n",
    "<strong>Example 1:</strong></p>\n",
    "\n",
    "<pre><strong>Input:</strong> <code>nums</code> = [-1,0,3,5,9,12], <code>target</code> = 9\n",
    "<strong>Output:</strong> 4\n",
    "<strong>Explanation:</strong> 9 exists in <code>nums</code> and its index is 4\n",
    "\n",
    "</pre>\n",
    "\n",
    "<p><strong>Example 2:</strong></p>\n",
    "\n",
    "<pre><strong>Input:</strong> <code>nums</code> = [-1,0,3,5,9,12], <code>target</code> = 2\n",
    "<strong>Output:</strong> -1\n",
    "<strong>Explanation:</strong> 2 does not exist in <code>nums</code> so return -1\n",
    "</pre>\n",
    "\n",
    "<p>&nbsp;</p>\n",
    "\n",
    "<p><strong>Note:</strong></p>\n",
    "\n",
    "<ol>\n",
    "\t<li>You may assume that all elements in <code>nums</code> are unique.</li>\n",
    "\t<li><code>n</code> will be in the range <code>[1, 10000]</code>.</li>\n",
    "\t<li>The value of each element in <code>nums</code> will be in the range <code>[-9999, 9999]</code>.</li>\n",
    "</ol>\n",
    "<!--Copy Paste Leetcode statement between-->\n",
    "\n",
    "<p>&nbsp;</p>\n",
    "<a href=\"https://leetcode.com/problems/binary-search/\">Source</a> \n",
    "<hr>\n",
    "\n",
    "<h4>Code</h4>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def binary_search(nums, target):\n",
    "    \"\"\"Iterative implementation of binary search\"\"\"\n",
    "    left = 0\n",
    "    right = len(nums)-1\n",
    "    while left <= right:\n",
    "        mid = (left + right) // 2\n",
    "        if nums[mid] == target:\n",
    "            return mid\n",
    "        if nums[mid] < target:\n",
    "            left = mid+1\n",
    "        if target < nums[mid]:\n",
    "            right = mid-1\n",
    "    return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def binary_search(nums, target):\n",
    "    \"\"\"Alternative version of above solution\"\"\"\n",
    "    left = 0\n",
    "    right = len(nums)              # vs. len(nums)-1\n",
    "    while left < right:            # vs. <=\n",
    "        mid = (left + right) // 2\n",
    "        if nums[mid] == target:\n",
    "            return mid\n",
    "        if nums[mid] < target:\n",
    "            left = mid+1\n",
    "        if target < nums[mid]:\n",
    "            right = mid            # vs. mid-1\n",
    "    return -1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h4>Check</h4>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nums = [-1,0,3,5,9,12]\n",
    "target = 9\n",
    "binary_search(nums, target)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-1"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nums = [-1,0,3,5,9,12]\n",
    "target = 2\n",
    "binary_search(nums, target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<hr>\n",
    "<h4>Follow up:</h4>\n",
    "<p>Solve it both iteratively and recursively. Solve it using built-in methods too.</p>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def binary_search(nums, target):\n",
    "    \"\"\"Recursive implementation of binary search\"\"\"\n",
    "    def helper(left, right):\n",
    "        if right < left:  # base case: target not present\n",
    "            return -1\n",
    "\n",
    "        nonlocal nums, target\n",
    "        mid = left + (right-left)//2\n",
    "\n",
    "        if nums[mid] == target:  # base case: target at middle index\n",
    "            return mid\n",
    "        if target > nums[mid]:\n",
    "            return helper(mid+1, right)\n",
    "        else:\n",
    "            return helper(left, mid-1)\n",
    "\n",
    "\n",
    "\n",
    "    return helper(0, len(nums)-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def binary_search(nums, target):\n",
    "    \"\"\"Using Built-in method index()\"\"\"\n",
    "    try:\n",
    "        return nums.index(target)\n",
    "    except ValueError:  # index() returns an error if target is not in nums\n",
    "        return -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bisect import bisect_left\n",
    "\n",
    "def binary_search(nums, target):\n",
    "    \"\"\"Using Built-in method bisect_left()\"\"\"\n",
    "    i = bisect_left(nums, target) \n",
    "    return i if i != len(nums) and nums[i] == target else -1  "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}