From 199157aeed357c61c5e288983841f315839e3734 Mon Sep 17 00:00:00 2001 From: Donne Martin Date: Sat, 2 May 2015 17:06:21 -0400 Subject: [PATCH] Added notebook solving the following: Check if a string is a permutation of another. --- README.md | 1 + arrays-strings/permutation.ipynb | 171 +++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 arrays-strings/permutation.ipynb diff --git a/README.md b/README.md index 7d6536d..6e5614e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Data structures and algorithms practice problems. * [Check if a string contains unique characters](http://nbviewer.ipython.org/github/donnemartin/practice/blob/master/arrays-strings/unique_chars.ipynb) * [Reverse characters in a string](http://nbviewer.ipython.org/github/donnemartin/practice/blob/master/arrays-strings/reverse_string.ipynb) +* [Check if a string is a permutation of another](http://nbviewer.ipython.org/github/donnemartin/practice/blob/master/arrays-strings/permutation.ipynb) ## License diff --git a/arrays-strings/permutation.ipynb b/arrays-strings/permutation.ipynb new file mode 100644 index 0000000..e0dea31 --- /dev/null +++ b/arrays-strings/permutation.ipynb @@ -0,0 +1,171 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem: Determine if a string is a permutation of another string\n", + "\n", + "* [Clarifying Questions](#Clarifying-Questions)\n", + "* [Test Cases](#Test-Cases)\n", + "* [Algorithm: Compare Sorted Strings](#Algorithm:-Compare-Sorted-Strings)\n", + "* [Code: Compare Sorted Strings](#Code:-Compare-Sorted-Strings)\n", + "* [Pythonic-Code](#Pythonic-Code)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Clarifying Questions\n", + "\n", + "* Is the string ASCII (extended)? Or Unicode?\n", + " * ASCII extended, which is 256 characters\n", + "* Is whitespace important?\n", + " * Yes\n", + "* Is this case sensitive? 'Nib', 'bin' is not a match?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* One or more empty strings -> False\n", + "* 'Nib', 'bin' -> False\n", + "* 'act', 'cat' -> True\n", + "* 'a ct', 'ca t' -> True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm: Compare Sorted Strings\n", + "\n", + "Anagrams contain the same strings but in different orders. This approach could be slow for large strings due to sorting.\n", + "\n", + "* Sort both strings\n", + "* If both sorted strings are equal\n", + " * return True\n", + "* Else\n", + " * return False\n", + "\n", + "Complexity:\n", + "* Time: O(n log n) from the sort, in general\n", + "* Space: Additional O(l + m) is created by the sorting algorithm, where l is the length of one string and m is the length of the other" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code: Compare Sorted Strings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def permutations(str1, str2):\n", + " return sorted(str1) == sorted(str2)\n", + "\n", + "print(permutations('', 'foo'))\n", + "print(permutations('Nib', 'bin'))\n", + "print(permutations('act', 'cat'))\n", + "print(permutations('a ct', 'ca t'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm: Hash Map Lookup\n", + "\n", + "We'll keep a hash map (dict) to keep track of characters we encounter. \n", + "\n", + "Steps:\n", + "* Scan each character\n", + "* For each character in each string:\n", + " * If the character does not exist in a hash map, add the character to a hash map\n", + " * Else, increment the character's count\n", + "* If the hash maps for each string are equal\n", + " * Return True\n", + "* Else\n", + " * Return False\n", + "\n", + "Notes:\n", + "* Since the characters are in ASCII, we could potentially use an array of size 128 (or 256 for extended ASCII)\n", + "* Instead of using two hash maps, you could use one hash map and increment character values based on the first string and decrement based on the second string\n", + "* You can short circuit if the lengths of each string are not equal, len() in Python is generally O(1)\n", + "\n", + "Complexity:\n", + "* Time: O(n)\n", + "* Space: Additional O(m), where m is the number of unique characters in the hash map" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from collections import defaultdict\n", + "\n", + "def unique_counts(string):\n", + " dict_chars = defaultdict(int)\n", + " for char in string:\n", + " dict_chars[char] += 1\n", + " return dict_chars\n", + "\n", + "def permutations(str1, str2):\n", + " if len(str1) != len(str2):\n", + " return False\n", + " unique_counts1 = unique_counts(str1)\n", + " unique_counts2 = unique_counts(str2)\n", + " return unique_counts1 == unique_counts2\n", + "\n", + "print(permutations('', 'foo'))\n", + "print(permutations('Nib', 'bin'))\n", + "print(permutations('act', 'cat'))\n", + "print(permutations('a ct', 'ca t'))" + ] + } + ], + "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.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}