diff --git a/arrays-strings/unique_chars.ipynb b/arrays-strings/unique_chars.ipynb index 50fd4ce..5204b0b 100644 --- a/arrays-strings/unique_chars.ipynb +++ b/arrays-strings/unique_chars.ipynb @@ -4,7 +4,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Problem: Implement an algorithm to determine if a string has all unique characters" + "## Problem: Implement an algorithm to determine if a string has all unique characters\n", + "\n", + "* [Clarifying Questions](#Clarifying-Questions)\n", + "* [Test Cases](#Test-Cases)\n", + "* [Algorithm 1: Sets and Length Comparison](#Algorithm-1:-Sets-and-Length-Comparison)\n", + "* [Code: Sets and Length Comparison](#Code:-Sets-and-Length-Comparison)\n", + "* [Algorithm 2: Hash Map Lookup](#Algorithm-2:-Hash-Map-Lookup)\n", + "* [Code: Hash Map Lookup](#Code:-Hash-Map-Lookup)\n", + "* [Algorithm 3: In-Place](#Algorithm-3:-In-Place)\n", + "* [Code: In-Place](#Code:-In-Place)" ] }, { @@ -13,7 +22,7 @@ "source": [ "## Clarifying Questions\n", "* Is the string in ASCII (extended?) or Unicode? \n", - " * ASCII extended, which is 256 characters.\n", + " * ASCII extended, which is 256 characters\n", "* Can you use additional data structures? \n", " * Yes" ] @@ -24,40 +33,34 @@ "source": [ "## Test Cases\n", "\n", - "* \"\" -> True\n", - "* \"foo\" -> False\n", - "* \"bar\" -> True" + "* '' -> True\n", + "* 'foo' -> False\n", + "* 'bar' -> True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Algorithm\n", + "## Algorithm 1: Sets and Length Comparison\n", "\n", - "We'll keep a hash map (set) to keep track of unique characters we encounter. \n", - "\n", - "Note:\n", - "* We could also use a dictionary, but it seems more logical to use a set as it does not contain duplicate elements.\n", - "* Since the characters are in ASCII, we could potentially use an array of size 128 (or 256 for extended ASCII)\n", - "\n", - "Steps:\n", - "* Scan each character.\n", - "* For each character:\n", - " * If the character does not exist in a hash map, add the character to a hash map.\n", - " * Else, return False.\n", - "* Return True\n", + "A set is an unordered collection of unique elements. \n", "\n", + "* If the length of the set(string) equals the length of the string\n", + " * Return True\n", + "* Else\n", + " * Return False\n", + " \n", "Complexity:\n", - "* Time: O(n).\n", - "* Space: Additional O(m), where m is the number of unique characters in the hash map." + "* Time: O(n)\n", + "* Space: Additional O(m), where m is the number of unique characters in the set" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Code" + "## Code: Sets and Length Comparison" ] }, { @@ -69,13 +72,7 @@ "outputs": [], "source": [ "def unique_chars(string):\n", - " chars_set = set()\n", - " for char in string:\n", - " if char in chars_set:\n", - " return False\n", - " else:\n", - " chars_set.add(char)\n", - " return True\n", + " return len(set(string)) == len(string)\n", "\n", "print(unique_chars(''))\n", "print(unique_chars('foo'))\n", @@ -86,10 +83,59 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Algorithm: No Additional Data Structures\n", + "## Algorithm 2: Hash Map Lookup\n", + "\n", + "We'll keep a hash map (set) to keep track of unique characters we encounter. \n", + "\n", + "Steps:\n", + "* Scan each character\n", + "* For each character:\n", + " * If the character does not exist in a hash map, add the character to a hash map\n", + " * Else, return False\n", + "* Return True\n", + "\n", + "Notes:\n", + "* We could also use a dictionary, but it seems more logical to use a set as it does not contain duplicate elements\n", + "* Since the characters are in ASCII, we could potentially use an array of size 128 (or 256 for extended ASCII)\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: Hash Map Lookup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def unique_chars_alt(string):\n", + " chars_set = set()\n", + " for char in string:\n", + " if char in chars_set:\n", + " return False\n", + " else:\n", + " chars_set.add(char)\n", + " return True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm 3: In-Place\n", "\n", "Since we cannot use additional data structures, this will eliminate the fast lookup O(1) time provided by our hash map.\n", - "* Scan each character.\n", + "* Scan each character\n", "* For each character:\n", " * Scan all [other] characters in the array\n", " * Exluding the current character from the scan is rather tricky in Python and results in a non-Pythonic solution\n", @@ -97,15 +143,15 @@ "* Return True\n", "\n", "Algorithm Complexity:\n", - "* Time: O(n^2).\n", - "* Space: In-place." + "* Time: O(n^2)\n", + "* Space: In-place" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Code" + "## Code: In-Place" ] }, { @@ -122,25 +168,6 @@ " return False\n", " return True" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Pythonic Solution(s)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def unique_chars_alt2(string):\n", - " return len(set(string)) == len(string)" - ] } ], "metadata": {