mirror of
https://github.com/donnemartin/interactive-coding-challenges.git
synced 2024-03-22 13:11:13 +08:00
Added reverse string challenge.
This commit is contained in:
parent
ac42b882bb
commit
73ec41e427
164
arrays_strings/reverse_string/reverse_string_challenge.ipynb
Normal file
164
arrays_strings/reverse_string/reverse_string_challenge.ipynb
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<small><i>This notebook was prepared by [Donne Martin](http://donnemartin.com). Source and license info is on [GitHub](https://github.com/donnemartin/coding-challenges).</i></small>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Challenge Notebook"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Problem: Implement a function to reverse a string (a list of characters), in-place.\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",
|
||||||
|
"*Problem statements are sometimes ambiguous. Identifying constraints and stating assumptions can help to ensure you code the intended solution.*\n",
|
||||||
|
"\n",
|
||||||
|
"* Can I assume the string is ASCII?\n",
|
||||||
|
" * Yes\n",
|
||||||
|
" * Note: Unicode strings could require special handling depending on your language\n",
|
||||||
|
"* Since we need to do this in-place, it seems we cannot use the slice operator or the reversed function?\n",
|
||||||
|
" * Correct\n",
|
||||||
|
"* Since Python string are immutable, can I use a list of characters instead?\n",
|
||||||
|
" * Yes"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Test Cases\n",
|
||||||
|
"\n",
|
||||||
|
"* None -> None\n",
|
||||||
|
"* [''] -> ['']\n",
|
||||||
|
"* ['f', 'o', 'o', ' ', 'b', 'a', 'r'] -> ['r', 'a', 'b', ' ', 'o', 'o', 'f']"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Algorithm\n",
|
||||||
|
"\n",
|
||||||
|
"Refer to the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/coding-challenges/blob/master/arrays_strings/reverse_string/reverse_string_solution.ipynb). 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": [
|
||||||
|
"def list_of_chars(list_chars):\n",
|
||||||
|
" # TODO: Implement me\n",
|
||||||
|
" pass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Unit Test"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"**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_reverse_string.py\n",
|
||||||
|
"from nose.tools import assert_equal\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"class TestReverse(object):\n",
|
||||||
|
" \n",
|
||||||
|
" def test_reverse(self):\n",
|
||||||
|
" assert_equal(list_of_chars(None), None)\n",
|
||||||
|
" assert_equal(list_of_chars(['']), [''])\n",
|
||||||
|
" assert_equal(list_of_chars(['f', 'o', 'o', ' ', 'b', 'a', 'r']), \n",
|
||||||
|
" ['r', 'a', 'b', ' ', 'o', 'o', 'f'])\n",
|
||||||
|
" print('Success: test_reverse')\n",
|
||||||
|
"\n",
|
||||||
|
"def main():\n",
|
||||||
|
" test = TestReverse()\n",
|
||||||
|
" test.test_reverse()\n",
|
||||||
|
" \n",
|
||||||
|
"if __name__ == '__main__':\n",
|
||||||
|
" main()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Solution Notebook\n",
|
||||||
|
"\n",
|
||||||
|
"Review the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/coding-challenges/blob/master/arrays_strings/reverse_string/reverse_string_solution.ipynb) for a discussion on algorithms and code solutions."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 2",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python2"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython2",
|
||||||
|
"version": "2.7.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 0
|
||||||
|
}
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"<small><i>This notebook was prepared by [Donne Martin](http://donnemartin.com). Source and license info is on [GitHub](https://bit.ly/code-notes).</i></small>"
|
"<small><i>This notebook was prepared by [Donne Martin](http://donnemartin.com). Source and license info is on [GitHub](https://github.com/donnemartin/coding-challenges).</i></small>"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Problem: Implement a function to reverse a string.\n",
|
"# Solution Notebook"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Problem: Implement a function to reverse a string (a list of characters), in-place.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"* [Constraints](#Constraints)\n",
|
"* [Constraints](#Constraints)\n",
|
||||||
"* [Test Cases](#Test-Cases)\n",
|
"* [Test Cases](#Test-Cases)\n",
|
||||||
|
@ -19,8 +26,8 @@
|
||||||
"* [Code](#Code)\n",
|
"* [Code](#Code)\n",
|
||||||
"* [Pythonic-Code](#Pythonic-Code)\n",
|
"* [Pythonic-Code](#Pythonic-Code)\n",
|
||||||
"* [Unit Test](#Unit-Test)\n",
|
"* [Unit Test](#Unit-Test)\n",
|
||||||
"* [C Algorithm](C-Algorithm)\n",
|
"* [Bonus C Algorithm](#Bonus-C-Algorithm)\n",
|
||||||
"* [C Code]()"
|
"* [Bonus C Code](#Bonus-C-Code)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -29,14 +36,14 @@
|
||||||
"source": [
|
"source": [
|
||||||
"## Constraints\n",
|
"## Constraints\n",
|
||||||
"\n",
|
"\n",
|
||||||
"*Problem statements are often intentionally ambiguous. Identifying constraints and stating assumptions can help to ensure you code the intended solution.*\n",
|
"*Problem statements are sometimes ambiguous. Identifying constraints and stating assumptions can help to ensure you code the intended solution.*\n",
|
||||||
"\n",
|
"\n",
|
||||||
"* Can I assume the string is ASCII?\n",
|
"* Can I assume the string is ASCII?\n",
|
||||||
" * Yes\n",
|
" * Yes\n",
|
||||||
" * Note: Unicode strings could require special handling depending on your language\n",
|
" * Note: Unicode strings could require special handling depending on your language\n",
|
||||||
"* Can I use the slice operator or the reversed function?\n",
|
"* Since we need to do this in-place, it seems we cannot use the slice operator or the reversed function?\n",
|
||||||
" * No\n",
|
" * Correct\n",
|
||||||
"* Since Python string are immutable, can I use a list instead?\n",
|
"* Since Python string are immutable, can I use a list of characters instead?\n",
|
||||||
" * Yes"
|
" * Yes"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -46,9 +53,9 @@
|
||||||
"source": [
|
"source": [
|
||||||
"## Test Cases\n",
|
"## Test Cases\n",
|
||||||
"\n",
|
"\n",
|
||||||
"* NULL input\n",
|
"* None -> None\n",
|
||||||
"* '' -> ''\n",
|
"* [''] -> ['']\n",
|
||||||
"* 'foo bar' -> 'rab oof'"
|
"* ['f', 'o', 'o', ' ', 'b', 'a', 'r'] -> ['r', 'a', 'b', ' ', 'o', 'o', 'f']"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -57,15 +64,18 @@
|
||||||
"source": [
|
"source": [
|
||||||
"## Algorithm\n",
|
"## Algorithm\n",
|
||||||
"\n",
|
"\n",
|
||||||
"* Convert the string to a list\n",
|
"Since Python strings are immutable, we'll use a list of chars instead to exercise in-place string manipulation as you would get with a C string.\n",
|
||||||
|
"\n",
|
||||||
"* Iterate len(string)/2 times, starting with i = 0:\n",
|
"* Iterate len(string)/2 times, starting with i = 0:\n",
|
||||||
" * Swap i and len(string) - 1 - i\n",
|
" * Swap i and len(string) - 1 - i\n",
|
||||||
" * Sncrement i\n",
|
" * Increment i\n",
|
||||||
"* Convert the list to a string and return it\n",
|
|
||||||
"\n",
|
"\n",
|
||||||
"Complexity:\n",
|
"Complexity:\n",
|
||||||
"* Time: O(n)\n",
|
"* Time: O(n)\n",
|
||||||
"* Space: O(n), additional space converting to/from a list"
|
"* Space: O(1)\n",
|
||||||
|
"\n",
|
||||||
|
"Note:\n",
|
||||||
|
"* You could use a byte array instead of a list to do in-place string operations"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -83,15 +93,14 @@
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"def reverse_string(string):\n",
|
"def list_of_chars(list_chars):\n",
|
||||||
" if string is None:\n",
|
" if list_chars is None:\n",
|
||||||
" return None\n",
|
" return None\n",
|
||||||
" string_list = list(string)\n",
|
" string_length = len(list_chars)\n",
|
||||||
" string_length = len(string_list)\n",
|
|
||||||
" for i in xrange(string_length/2):\n",
|
" for i in xrange(string_length/2):\n",
|
||||||
" string_list[i], string_list[string_length-1-i] = \\\n",
|
" list_chars[i], list_chars[string_length-1-i] = \\\n",
|
||||||
" string_list[string_length-1-i], string_list[i]\n",
|
" list_chars[string_length-1-i], list_chars[i]\n",
|
||||||
" return ''.join(string_list)"
|
" return list_chars"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -100,7 +109,7 @@
|
||||||
"source": [
|
"source": [
|
||||||
"## Pythonic-Code\n",
|
"## Pythonic-Code\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This question has an artificial constraint that prevented the use of the slice operator and the reversed method. For completeness, the solutions for these are provided below."
|
"This question has an artificial constraint that prevented the use of the slice operator and the reversed method. For completeness, the solutions for these are provided below. Note these solutions are not in-place."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -129,13 +138,6 @@
|
||||||
"## Unit Test"
|
"## Unit Test"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"*It is important to identify and run through general and edge cases from the [Test Cases](#Test-Cases) section by hand. You generally will not be asked to write a unit test like what is shown below.*"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 3,
|
"execution_count": 3,
|
||||||
|
@ -147,27 +149,49 @@
|
||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"Success: test_reversed\n",
|
"Overwriting test_reverse_string.py\n"
|
||||||
"Success: test_reversed\n",
|
|
||||||
"Success: test_reversed\n"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
|
"%%writefile test_reverse_string.py\n",
|
||||||
"from nose.tools import assert_equal\n",
|
"from nose.tools import assert_equal\n",
|
||||||
"\n",
|
"\n",
|
||||||
"class Test(object):\n",
|
|
||||||
" def test_reversed(self, func):\n",
|
|
||||||
" assert_equal(func(None), None)\n",
|
|
||||||
" assert_equal(func(''), '')\n",
|
|
||||||
" assert_equal(func('foo bar'), 'rab oof')\n",
|
|
||||||
" print('Success: test_reversed')\n",
|
|
||||||
"\n",
|
"\n",
|
||||||
|
"class TestReverse(object):\n",
|
||||||
|
" \n",
|
||||||
|
" def test_reverse(self):\n",
|
||||||
|
" assert_equal(list_of_chars(None), None)\n",
|
||||||
|
" assert_equal(list_of_chars(['']), [''])\n",
|
||||||
|
" assert_equal(list_of_chars(['f', 'o', 'o', ' ', 'b', 'a', 'r']), \n",
|
||||||
|
" ['r', 'a', 'b', ' ', 'o', 'o', 'f'])\n",
|
||||||
|
" print('Success: test_reverse')\n",
|
||||||
|
"\n",
|
||||||
|
"def main():\n",
|
||||||
|
" test = TestReverse()\n",
|
||||||
|
" test.test_reverse()\n",
|
||||||
|
" \n",
|
||||||
"if __name__ == '__main__':\n",
|
"if __name__ == '__main__':\n",
|
||||||
" test = Test()\n",
|
" main()"
|
||||||
" test.test_reversed(reverse_string)\n",
|
]
|
||||||
" test.test_reversed(reverse_string_alt)\n",
|
},
|
||||||
" test.test_reversed(reverse_string_alt2)"
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 4,
|
||||||
|
"metadata": {
|
||||||
|
"collapsed": false
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"Success: test_reverse\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"%run -i test_reverse_string.py"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
18
arrays_strings/reverse_string/test_reverse_string.py
Normal file
18
arrays_strings/reverse_string/test_reverse_string.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
from nose.tools import assert_equal
|
||||||
|
|
||||||
|
|
||||||
|
class TestReverse(object):
|
||||||
|
|
||||||
|
def test_reverse(self):
|
||||||
|
assert_equal(list_of_chars(None), None)
|
||||||
|
assert_equal(list_of_chars(['']), [''])
|
||||||
|
assert_equal(list_of_chars(['f', 'o', 'o', ' ', 'b', 'a', 'r']),
|
||||||
|
['r', 'a', 'b', ' ', 'o', 'o', 'f'])
|
||||||
|
print('Success: test_reverse')
|
||||||
|
|
||||||
|
def main():
|
||||||
|
test = TestReverse()
|
||||||
|
test.test_reverse()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user