diff --git a/bit_manipulation/bit/__init__.py b/bit_manipulation/bit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bit_manipulation/bit/bit_challenge.ipynb b/bit_manipulation/bit/bit_challenge.ipynb new file mode 100644 index 0000000..85fc5ae --- /dev/null +++ b/bit_manipulation/bit/bit_challenge.ipynb @@ -0,0 +1,225 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Challenge Notebook" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem: Implement common bit manipulation operations: get_bit, set_bit, clear_bit, clear_bits_msb_to_index, clear_bits_msb_to_lsb, update_bit.\n", + "\n", + "* [Constraints](#Constraints)\n", + "* [Test Cases](#Test-Cases)\n", + "* [Algorithm](#Algorithm)\n", + "* [Code](#Code)\n", + "* [Unit Test](#Unit-Test)\n", + "* [Solution Notebook](#Solution-Notebook)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Constraints\n", + "\n", + "* Can we assume the inputs are valid?\n", + " * No\n", + "* Can we assume this fits memory?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* None as a number input -> Exception\n", + "* Negative index -> Exception\n", + "\n", + "### get_bit\n", + " number = 0b10001110, index = 3\n", + " expected = True\n", + "### set_bit\n", + " number = 0b10001110, index = 4\n", + " expected = 0b10011110\n", + "### clear_bit\n", + " number = 0b10001110, index = 3\n", + " expected = 0b10000110\n", + "### clear_bits_msb_to_index\n", + " number = 0b10001110, index = 3\n", + " expected = 0b00000110\n", + "### clear_bits_index_to_lsb\n", + " number = 0b10001110, index = 3\n", + " expected = 0b10000000\n", + "### update_bit\n", + " number = 0b10001110, index = 3, value = 1\n", + " expected = 0b10001110\n", + " number = 0b10001110, index = 3, value = 0\n", + " expected = 0b10000110\n", + " number = 0b10001110, index = 0, value = 1\n", + " expected = 0b10001111" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm\n", + "\n", + "Refer to the [Solution Notebook](). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class Bit(object):\n", + "\n", + " def __init__(self, number):\n", + " # TODO: Implement me\n", + " pass\n", + "\n", + " def get_bit(self, index):\n", + " # TODO: Implement me\n", + " pass\n", + "\n", + " def set_bit(self, index):\n", + " # TODO: Implement me\n", + " pass\n", + "\n", + " def clear_bit(self, index):\n", + " # TODO: Implement me\n", + " pass\n", + "\n", + " def clear_bits_msb_to_index(self, index):\n", + " # TODO: Implement me\n", + " pass\n", + "\n", + " def clear_bits_index_to_lsb(self, index):\n", + " # TODO: Implement me\n", + " pass\n", + "\n", + " def update_bit(self, index, value):\n", + " # TODO: Implement me\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Unit Test" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**The following unit test is expected to fail until you solve the challenge.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# %load test_bit.py\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestBit(object):\n", + "\n", + " def test_bit(self):\n", + " number = int('10001110', base=2)\n", + " bit = Bit(number)\n", + " assert_equal(bit.get_bit(index=3), True)\n", + " expected = int('10011110', base=2)\n", + " assert_equal(bit.set_bit(index=4), expected)\n", + " bit = Bit(number)\n", + " expected = int('10000110', base=2)\n", + " assert_equal(bit.clear_bit(index=3), expected)\n", + " bit = Bit(number)\n", + " expected = int('00000110', base=2)\n", + " assert_equal(bit.clear_bits_msb_to_index(index=3), expected)\n", + " bit = Bit(number)\n", + " expected = int('10000000', base=2)\n", + " assert_equal(bit.clear_bits_index_to_lsb(index=3), expected)\n", + " bit = Bit(number)\n", + " assert_equal(bit.update_bit(index=3, value=1), number)\n", + " bit = Bit(number)\n", + " expected = int('10000110', base=2)\n", + " assert_equal(bit.update_bit(index=3, value=0), expected)\n", + " bit = Bit(number)\n", + " expected = int('10001111', base=2)\n", + " assert_equal(bit.update_bit(index=0, value=1), expected)\n", + " print('Success: test_bit')\n", + "\n", + "\n", + "def main():\n", + " test = TestBit()\n", + " test.test_bit()\n", + "\n", + "\n", + "if __name__ == '__main__':\n", + " main()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution Notebook\n", + "\n", + "Review the [Solution Notebook]() for a discussion on algorithms and code solutions." + ] + } + ], + "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.5.0" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/bit_manipulation/bit/bit_solution.ipynb b/bit_manipulation/bit/bit_solution.ipynb new file mode 100644 index 0000000..be72758 --- /dev/null +++ b/bit_manipulation/bit/bit_solution.ipynb @@ -0,0 +1,358 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution Notebook" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem: Implement common bit manipulation operations: get_bit, set_bit, clear_bit, clear_bits_msb_to_index, clear_bits_msb_to_lsb, update_bit.\n", + "\n", + "* [Constraints](#Constraints)\n", + "* [Test Cases](#Test-Cases)\n", + "* [Algorithm](#Algorithm)\n", + "* [Code](#Code)\n", + "* [Unit Test](#Unit-Test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Constraints\n", + "\n", + "* Can we assume the inputs are valid?\n", + " * No\n", + "* Can we assume this fits memory?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* None as a number input -> Exception\n", + "* Negative index -> Exception\n", + "\n", + "### get_bit\n", + " number = 0b10001110, index = 3\n", + " expected = True\n", + "### set_bit\n", + " number = 0b10001110, index = 4\n", + " expected = 0b10011110\n", + "### clear_bit\n", + " number = 0b10001110, index = 3\n", + " expected = 0b10000110\n", + "### clear_bits_msb_to_index\n", + " number = 0b10001110, index = 3\n", + " expected = 0b00000110\n", + "### clear_bits_index_to_lsb\n", + " number = 0b10001110, index = 3\n", + " expected = 0b10000000\n", + "### update_bit\n", + " number = 0b10001110, index = 3, value = 1\n", + " expected = 0b10001110\n", + " number = 0b10001110, index = 3, value = 0\n", + " expected = 0b10000110\n", + " number = 0b10001110, index = 0, value = 1\n", + " expected = 0b10001111" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm\n", + "\n", + "### get_bit\n", + "\n", + "
\n", + "indices 7 6 5 4 3 2 1 0 index = 3\n", + "--------------------------------------------------\n", + "input 1 0 0 0 1 1 1 0 0b10001110\n", + "mask 0 0 0 0 1 0 0 0 1 << index\n", + "--------------------------------------------------\n", + "result 0 0 0 0 1 0 0 0 number & mask != 0\n", + "\n", + "\n", + "Complexity:\n", + "* Time: O(n)\n", + "* Space: O(n)\n", + "\n", + "### set_bit\n", + "\n", + "
\n", + "indices 7 6 5 4 3 2 1 0 index = 4\n", + "--------------------------------------------------\n", + "input 1 0 0 0 1 1 1 0 0b10001110\n", + "mask 0 0 0 1 0 0 0 0 1 << index\n", + "--------------------------------------------------\n", + "result 1 0 0 1 1 1 1 0 number | mask\n", + "\n", + "\n", + "Complexity:\n", + "* Time: O(n)\n", + "* Space: O(n)\n", + "\n", + "### clear_bit\n", + "\n", + "
\n", + "indices 7 6 5 4 3 2 1 0 index = 3\n", + "--------------------------------------------------\n", + "input 1 0 0 0 1 1 1 0 0b10001110\n", + "mask 0 0 0 0 1 0 0 0 1 << index\n", + "mask 1 1 1 1 0 1 1 1 ~(1 << index)\n", + "--------------------------------------------------\n", + "result 1 0 0 0 0 1 1 0 number & mask\n", + "\n", + "\n", + "Complexity:\n", + "* Time: O(n)\n", + "* Space: O(n)\n", + "\n", + "### clear_bits_msb_to_index\n", + "\n", + "
\n", + "indices 7 6 5 4 3 2 1 0 index = 3\n", + "--------------------------------------------------\n", + "input 1 0 0 0 1 1 1 0 0b10001110\n", + "mask 0 0 0 0 1 0 0 0 1 << index\n", + "mask 0 0 0 0 0 1 1 1 (1 << index) - 1\n", + "--------------------------------------------------\n", + "result 0 0 0 0 0 1 1 1 number & mask\n", + "\n", + "\n", + "Complexity:\n", + "* Time: O(n)\n", + "* Space: O(n)\n", + "\n", + "### clear_bits_index_to_lsb\n", + "\n", + "
\n", + "indices 7 6 5 4 3 2 1 0 index = 3\n", + "--------------------------------------------------\n", + "input 1 0 0 0 1 1 1 0 0b10001110\n", + "mask 0 0 0 1 0 0 0 0 1 << index + 1\n", + "mask 0 0 0 0 1 1 1 1 (1 << index + 1) - 1\n", + "mask 1 1 1 1 0 0 0 0 ~((1 << index + 1) - 1)\n", + "--------------------------------------------------\n", + "result 1 0 0 0 0 0 0 0 number & mask\n", + "\n", + "\n", + "Complexity:\n", + "* Time: O(n)\n", + "* Space: O(n)\n", + "\n", + "### update_bit\n", + "\n", + "* Use `get_bit` to see if the value is already set or cleared\n", + "* If not, use `set_bit` if setting the value or `clear_bit` if clearing the value\n", + "\n", + "Complexity:\n", + "* Time: O(n)\n", + "* Space: O(n)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def validate_index(func):\n", + " def validate_index_wrapper(self, *args, **kwargs):\n", + " for arg in args:\n", + " if arg < 0:\n", + " raise IndexError('Invalid index')\n", + " return func(self, *args, **kwargs)\n", + " return validate_index_wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class Bit(object):\n", + "\n", + " def __init__(self, number):\n", + " if number is None:\n", + " raise TypeError('number cannot be None')\n", + " self.number = number\n", + "\n", + " @validate_index\n", + " def get_bit(self, index):\n", + " mask = 1 << index\n", + " return self.number & mask != 0\n", + "\n", + " @validate_index\n", + " def set_bit(self, index):\n", + " mask = 1 << index\n", + " self.number |= mask\n", + " return self.number\n", + "\n", + " @validate_index\n", + " def clear_bit(self, index):\n", + " mask = ~(1 << index)\n", + " self.number &= mask\n", + " return self.number\n", + "\n", + " @validate_index\n", + " def clear_bits_msb_to_index(self, index):\n", + " mask = (1 << index) - 1\n", + " self.number &= mask\n", + " return self.number\n", + "\n", + " @validate_index\n", + " def clear_bits_index_to_lsb(self, index):\n", + " mask = ~((1 << index + 1) - 1)\n", + " self.number &= mask\n", + " return self.number\n", + "\n", + " @validate_index\n", + " def update_bit(self, index, value):\n", + " if value is None or value not in (0, 1):\n", + " raise Exception('Invalid value')\n", + " if self.get_bit(index) == value:\n", + " return self.number\n", + " if value:\n", + " self.set_bit(index)\n", + " else:\n", + " self.clear_bit(index)\n", + " return self.number" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Unit Test" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting test_bit.py\n" + ] + } + ], + "source": [ + "%%writefile test_bit.py\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestBit(object):\n", + "\n", + " def test_bit(self):\n", + " number = int('10001110', base=2)\n", + " bit = Bit(number)\n", + " assert_equal(bit.get_bit(index=3), True)\n", + " expected = int('10011110', base=2)\n", + " assert_equal(bit.set_bit(index=4), expected)\n", + " bit = Bit(number)\n", + " expected = int('10000110', base=2)\n", + " assert_equal(bit.clear_bit(index=3), expected)\n", + " bit = Bit(number)\n", + " expected = int('00000110', base=2)\n", + " assert_equal(bit.clear_bits_msb_to_index(index=3), expected)\n", + " bit = Bit(number)\n", + " expected = int('10000000', base=2)\n", + " assert_equal(bit.clear_bits_index_to_lsb(index=3), expected)\n", + " bit = Bit(number)\n", + " assert_equal(bit.update_bit(index=3, value=1), number)\n", + " bit = Bit(number)\n", + " expected = int('10000110', base=2)\n", + " assert_equal(bit.update_bit(index=3, value=0), expected)\n", + " bit = Bit(number)\n", + " expected = int('10001111', base=2)\n", + " assert_equal(bit.update_bit(index=0, value=1), expected)\n", + " print('Success: test_bit')\n", + "\n", + "\n", + "def main():\n", + " test = TestBit()\n", + " test.test_bit()\n", + "\n", + "\n", + "if __name__ == '__main__':\n", + " main()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Success: test_bit\n" + ] + } + ], + "source": [ + "%run -i test_bit.py" + ] + } + ], + "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.5.0" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/bit_manipulation/bit/test_bit.py b/bit_manipulation/bit/test_bit.py new file mode 100644 index 0000000..2bca822 --- /dev/null +++ b/bit_manipulation/bit/test_bit.py @@ -0,0 +1,38 @@ +from nose.tools import assert_equal + + +class TestBit(object): + + def test_bit(self): + number = int('10001110', base=2) + bit = Bit(number) + assert_equal(bit.get_bit(index=3), True) + expected = int('10011110', base=2) + assert_equal(bit.set_bit(index=4), expected) + bit = Bit(number) + expected = int('10000110', base=2) + assert_equal(bit.clear_bit(index=3), expected) + bit = Bit(number) + expected = int('00000110', base=2) + assert_equal(bit.clear_bits_msb_to_index(index=3), expected) + bit = Bit(number) + expected = int('10000000', base=2) + assert_equal(bit.clear_bits_index_to_lsb(index=3), expected) + bit = Bit(number) + assert_equal(bit.update_bit(index=3, value=1), number) + bit = Bit(number) + expected = int('10000110', base=2) + assert_equal(bit.update_bit(index=3, value=0), expected) + bit = Bit(number) + expected = int('10001111', base=2) + assert_equal(bit.update_bit(index=0, value=1), expected) + print('Success: test_bit') + + +def main(): + test = TestBit() + test.test_bit() + + +if __name__ == '__main__': + main() \ No newline at end of file