Add ransom note challenge

This commit is contained in:
Donne Martin 2017-03-28 05:13:14 -04:00
parent 923e98e4cf
commit c3b6ef0376
4 changed files with 394 additions and 0 deletions

View File

View File

@ -0,0 +1,171 @@
{
"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: Given a magazine, see if a ransom note could have been written using the letters in the magazine.\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",
"* Is this case sensitive?\n",
" * Yes\n",
"* Can we assume we're working with ASCII characters?\n",
" * Yes\n",
"* Can we scan the entire magazine, or should we scan only when necessary?\n",
" * You can scan the entire magazine\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 -> Exception\n",
"* '', '' -> Exception\n",
"* 'a', 'b' -> False\n",
"* 'aa', 'ab' -> False\n",
"* 'aa', 'aab' -> True"
]
},
{
"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 Solution(object):\n",
"\n",
" def match_note_to_magazine(self, ransom_note, magazine):\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_ransom_note.py\n",
"from nose.tools import assert_equal, assert_raises\n",
"\n",
"\n",
"class TestRansomNote(object):\n",
"\n",
" def test_ransom_note(self):\n",
" solution = Solution()\n",
" assert_raises(TypeError, solution.match_note_to_magazine, None, None)\n",
" assert_equal(solution.match_note_to_magazine('', ''), True)\n",
" assert_equal(solution.match_note_to_magazine('a', 'b'), False)\n",
" assert_equal(solution.match_note_to_magazine('aa', 'ab'), False)\n",
" assert_equal(solution.match_note_to_magazine('aa', 'aab'), True)\n",
" print('Success: test_ransom_note')\n",
"\n",
"\n",
"def main():\n",
" test = TestRansomNote()\n",
" test.test_ransom_note()\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
}

View File

@ -0,0 +1,201 @@
{
"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: Given a magazine, see if a ransom note could have been written using the letters in the magazine.\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",
"* Is this case sensitive?\n",
" * Yes\n",
"* Can we assume we're working with ASCII characters?\n",
" * Yes\n",
"* Can we scan the entire magazine, or should we scan only when necessary?\n",
" * You can scan the entire magazine\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 -> Exception\n",
"* '', '' -> Exception\n",
"* 'a', 'b' -> False\n",
"* 'aa', 'ab' -> False\n",
"* 'aa', 'aab' -> True"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Algorithm\n",
"\n",
"* Build a dictionary of the magazine characters and counts.\n",
"* Loop through each letter in the ransom note and see if there are enough letters in the magazine's dictionary.\n",
"* Note: You could make this more efficient by not scanning the entire magazine all at once, but instead scan just in time as you run out of letters in the dictionary.\n",
"\n",
"Complexity:\n",
"* Time: O(n+m), where n is the length of the ransom note and m is the length of the magazine\n",
"* Space: O(n+m)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Code"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"class Solution(object):\n",
"\n",
" def match_note_to_magazine(self, ransom_note, magazine):\n",
" if ransom_note is None or magazine is None:\n",
" raise TypeError('ransom_note or magazine cannot be None')\n",
" seen_chars = {}\n",
" for char in magazine:\n",
" if char in seen_chars:\n",
" seen_chars[char] += 1\n",
" else:\n",
" seen_chars[char] = 1\n",
" for char in ransom_note:\n",
" try:\n",
" seen_chars[char] -= 1\n",
" except KeyError:\n",
" return False\n",
" if seen_chars[char] < 0:\n",
" return False\n",
" return True"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Unit Test"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting test_ransom_note.py\n"
]
}
],
"source": [
"%%writefile test_ransom_note.py\n",
"from nose.tools import assert_equal, assert_raises\n",
"\n",
"\n",
"class TestRansomNote(object):\n",
"\n",
" def test_ransom_note(self):\n",
" solution = Solution()\n",
" assert_raises(TypeError, solution.match_note_to_magazine, None, None)\n",
" assert_equal(solution.match_note_to_magazine('', ''), True)\n",
" assert_equal(solution.match_note_to_magazine('a', 'b'), False)\n",
" assert_equal(solution.match_note_to_magazine('aa', 'ab'), False)\n",
" assert_equal(solution.match_note_to_magazine('aa', 'aab'), True)\n",
" print('Success: test_ransom_note')\n",
"\n",
"\n",
"def main():\n",
" test = TestRansomNote()\n",
" test.test_ransom_note()\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" main()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Success: test_ransom_note\n"
]
}
],
"source": [
"%run -i test_ransom_note.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
}

View File

@ -0,0 +1,22 @@
from nose.tools import assert_equal, assert_raises
class TestRansomNote(object):
def test_ransom_note(self):
solution = Solution()
assert_raises(TypeError, solution.match_note_to_magazine, None, None)
assert_equal(solution.match_note_to_magazine('', ''), True)
assert_equal(solution.match_note_to_magazine('a', 'b'), False)
assert_equal(solution.match_note_to_magazine('aa', 'ab'), False)
assert_equal(solution.match_note_to_magazine('aa', 'aab'), True)
print('Success: test_ransom_note')
def main():
test = TestRansomNote()
test.test_ransom_note()
if __name__ == '__main__':
main()