From 1b1f4d2ba4c0ee7c1c723a49892398d111e5ae50 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 17 Mar 2020 01:25:12 -0700 Subject: [PATCH] First commit --- .../Big O Notation-checkpoint.ipynb | 34 + .ipynb_checkpoints/Practice-checkpoint.ipynb | 187 +++ .../Reflect Notes-checkpoint.ipynb | 47 + .project | 17 + .pydevproject | 5 + ...m Analysis and Big O Quiz-checkpoint.ipynb | 32 + .../Big O Examples -checkpoint.ipynb | 580 +++++++ .../Big O Notation-checkpoint.ipynb | 206 +++ ...or Python Data Structures-checkpoint.ipynb | 288 ++++ ...rithm Analysis and Big O -checkpoint.ipynb | 194 +++ .../Algorithm Analysis and Big O Quiz.ipynb | 32 + .../Big O Examples .ipynb | 558 +++++++ .../Big O Notation.ipynb | 206 +++ .../Big O for Python Data Structures.ipynb | 284 ++++ ...ion to Algorithm Analysis and Big O .ipynb | 194 +++ .../Amortization-checkpoint.ipynb | 44 + .../Array Mini-Project-checkpoint.ipynb | 45 + .../Dynamic Array Exercise-checkpoint.ipynb | 329 ++++ .../Dynamic Arrays-checkpoint.ipynb | 44 + ... to Array Based Sequences-checkpoint.ipynb | 112 ++ .../Low Level Arrays-checkpoint.ipynb | 43 + Array Sequences/Amortization.ipynb | 44 + Array Sequences/Array Mini-Project.ipynb | 45 + .../Anagram Check -checkpoint.ipynb | 197 +++ .../Array Pair Sum -checkpoint.ipynb | 136 ++ ...Find the Missing Element -checkpoint.ipynb | 169 ++ .../Largest Continuous Sum -checkpoint.ipynb | 130 ++ .../Sentence Reversal-checkpoint.ipynb | 220 +++ .../String Compression -checkpoint.ipynb | 128 ++ ...ique Characters in String-checkpoint.ipynb | 126 ++ .../Anagram Check .ipynb | 213 +++ .../Array Pair Sum .ipynb | 136 ++ .../Find the Missing Element .ipynb | 181 +++ .../Largest Continuous Sum .ipynb | 128 ++ .../Sentence Reversal.ipynb | 220 +++ .../String Compression .ipynb | 143 ++ .../Unique Characters in String.ipynb | 126 ++ .../Anagram Check - SOLUTION-checkpoint.ipynb | 330 ++++ ...Array Pair Sum - SOLUTION-checkpoint.ipynb | 162 ++ ...issing Element - SOLUTION-checkpoint.ipynb | 272 ++++ ...Continuous Sum - SOLUTION-checkpoint.ipynb | 146 ++ ...tence Reversal - SOLUTION-checkpoint.ipynb | 267 ++++ ...ing Compression -SOLUTION-checkpoint.ipynb | 168 ++ ...ters in String - SOLUTION-checkpoint.ipynb | 124 ++ .../Anagram Check - SOLUTION.ipynb | 310 ++++ .../Array Pair Sum - SOLUTION.ipynb | 162 ++ .../Find the Missing Element - SOLUTION.ipynb | 272 ++++ .../Largest Continuous Sum - SOLUTION.ipynb | 140 ++ .../Sentence Reversal - SOLUTION.ipynb | 257 +++ .../String Compression -SOLUTION.ipynb | 162 ++ ...ique Characters in String - SOLUTION.ipynb | 122 ++ .../Anagram Check -checkpoint.ipynb | 197 +++ .../Array Pair Sum -checkpoint.ipynb | 135 ++ ...Find the Missing Element -checkpoint.ipynb | 169 ++ .../Largest Continuous Sum -checkpoint.ipynb | 125 ++ .../Sentence Reversal-checkpoint.ipynb | 169 ++ .../String Compression -checkpoint.ipynb | 128 ++ ...ique Characters in String-checkpoint.ipynb | 104 ++ .../Anagram Check .ipynb | 197 +++ .../Array Pair Sum .ipynb | 135 ++ .../Find the Missing Element .ipynb | 169 ++ .../Largest Continuous Sum .ipynb | 125 ++ .../Sentence Reversal.ipynb | 169 ++ .../String Compression .ipynb | 128 ++ .../Unique Characters in String.ipynb | 104 ++ Array Sequences/Dynamic Array Exercise.ipynb | 309 ++++ Array Sequences/Dynamic Arrays.ipynb | 44 + ...ntroduction to Array Based Sequences.ipynb | 112 ++ Array Sequences/Low Level Arrays.ipynb | 43 + ...ntation of Adjacency List-checkpoint.ipynb | 235 +++ ...n of Breadth First Search-checkpoint.ipynb | 182 +++ ...ion of Depth First Search-checkpoint.ipynb | 184 +++ ...ntation of Graph Overview-checkpoint.ipynb | 160 ++ ...ht's Tour Example Problem-checkpoint.ipynb | 113 ++ ...rd Ladder Example Problem-checkpoint.ipynb | 154 ++ ...th First Search Algorithm-checkpoint.ipynb | 62 + ...th First Search Algorithm-checkpoint.ipynb | 62 + .../Implement a Graph-checkpoint.ipynb | 45 + ...ement Breadth First Search Algorithm.ipynb | 62 + ...plement Depth First Search Algorithm.ipynb | 62 + .../Implement a Graph.ipynb | 223 +++ ...th First Search Algorithm-checkpoint.ipynb | 62 + ...th First Search Algorithm-checkpoint.ipynb | 62 + .../Implement a Graph-checkpoint.ipynb | 45 + ...ement Breadth First Search Algorithm.ipynb | 62 + ...plement Depth First Search Algorithm.ipynb | 62 + .../Implement a Graph.ipynb | 45 + Graphs/Implementation of Adjacency List.ipynb | 229 +++ ...plementation of Breadth First Search.ipynb | 176 +++ ...Implementation of Depth First Search.ipynb | 178 +++ Graphs/Implementation of Graph Overview.ipynb | 156 ++ Graphs/Knight's Tour Example Problem.ipynb | 113 ++ Graphs/Word Ladder Example Problem.ipynb | 154 ++ Graphs/words.txt | 6 + ...inked List Implementation-checkpoint.ipynb | 111 ++ .../Doubly Linked Lists-checkpoint.ipynb | 34 + .../Linked List Overview-checkpoint.ipynb | 42 + ...inked List Implementation-checkpoint.ipynb | 120 ++ .../Singly Linked Lists-checkpoint.ipynb | 36 + .../Doubly Linked List Implementation.ipynb | 111 ++ Linked Lists/Doubly Linked Lists.ipynb | 34 + Linked Lists/Linked List Overview.ipynb | 42 + ...ment a Doubly Linked List-checkpoint.ipynb | 69 + ...ment a Singly Linked List-checkpoint.ipynb | 69 + ...ed List Nth to Last Node -checkpoint.ipynb | 192 +++ .../Linked List Reversal -checkpoint.ipynb | 244 +++ ...y Linked List Cycle Check-checkpoint.ipynb | 149 ++ .../Implement a Doubly Linked List.ipynb | 69 + .../Implement a Singly Linked List.ipynb | 69 + .../Linked List Nth to Last Node .ipynb | 192 +++ .../Linked List Reversal .ipynb | 246 +++ .../Singly Linked List Cycle Check.ipynb | 149 ++ ...t a Linked List -SOLUTION-checkpoint.ipynb | 158 ++ ...h to Last Node - SOLUTION-checkpoint.ipynb | 210 +++ ... List Reversal - SOLUTION-checkpoint.ipynb | 267 ++++ ...st Cycle Check - SOLUTION-checkpoint.ipynb | 169 ++ .../Implement a Linked List -SOLUTION.ipynb | 158 ++ ...ked List Nth to Last Node - SOLUTION.ipynb | 210 +++ .../Linked List Reversal - SOLUTION.ipynb | 267 ++++ ...y Linked List Cycle Check - SOLUTION.ipynb | 169 ++ ...ment a Doubly Linked List-checkpoint.ipynb | 67 + ...ment a Singly Linked List-checkpoint.ipynb | 68 + ...ed List Nth to Last Node -checkpoint.ipynb | 186 +++ .../Linked List Reversal -checkpoint.ipynb | 244 +++ ...y Linked List Cycle Check-checkpoint.ipynb | 147 ++ .../Implement a Doubly Linked List.ipynb | 67 + .../Implement a Singly Linked List.ipynb | 68 + .../Linked List Nth to Last Node .ipynb | 186 +++ .../Linked List Reversal .ipynb | 244 +++ .../Singly Linked List Cycle Check.ipynb | 147 ++ .../Singly Linked List Implementation.ipynb | 120 ++ Linked Lists/Singly Linked Lists.ipynb | 36 + ...ite Question 1 - SOLUTION-checkpoint.ipynb | 232 +++ ...ite Question 2 - SOLUTION-checkpoint.ipynb | 164 ++ ...ite Question 3 - SOLUTION-checkpoint.ipynb | 196 +++ .../Phone Screen - SOLUTION-checkpoint.ipynb | 85 + .../On-Site Question 1 - SOLUTION.ipynb | 226 +++ .../On-Site Question 2 - SOLUTION.ipynb | 160 ++ .../On-Site Question 3 - SOLUTION.ipynb | 196 +++ .../Phone Screen - SOLUTION.ipynb | 85 + .../On-Site Question 1-checkpoint.ipynb | 56 + .../On-Site Question 2 -checkpoint.ipynb | 51 + .../On-Site Question 3-checkpoint.ipynb | 78 + .../Phone Screen -checkpoint.ipynb | 49 + .../On-Site Question 1.ipynb | 56 + .../On-Site Question 2 .ipynb | 51 + .../On-Site Question 3.ipynb | 78 + .../Phone Screen .ipynb | 49 + ...ite Question 1 - SOLUTION-checkpoint.ipynb | 127 ++ ...ite Question 2 - SOLUTION-checkpoint.ipynb | 149 ++ ...Site Question 3 -SOLUTION-checkpoint.ipynb | 91 ++ ...ite Question 4 - SOLUTION-checkpoint.ipynb | 263 +++ .../Phone Screen-checkpoint.ipynb | 274 ++++ .../On-Site Question 1 - SOLUTION.ipynb | 127 ++ .../On-Site Question 2 - SOLUTION.ipynb | 149 ++ .../On-Site Question 3 -SOLUTION.ipynb | 91 ++ .../On-Site Question 4 - SOLUTION.ipynb | 263 +++ .../Phone Screen.ipynb | 274 ++++ .../On-Site Question 1 -checkpoint.ipynb | 54 + .../On-Site Question 2 -checkpoint.ipynb | 54 + .../On-Site Question 3 -checkpoint.ipynb | 54 + .../On-Site Question 4 -checkpoint.ipynb | 46 + .../Phone Screen-checkpoint.ipynb | 80 + .../On-Site Question 1 .ipynb | 54 + .../On-Site Question 2 .ipynb | 54 + .../On-Site Question 3 .ipynb | 54 + .../On-Site Question 4 .ipynb | 46 + .../Phone Screen.ipynb | 80 + ...ite Question 1 - SOLUTION-checkpoint.ipynb | 149 ++ ...ite Question 2 - SOLUTION-checkpoint.ipynb | 115 ++ ...ite Question 3 - SOLUTION-checkpoint.ipynb | 121 ++ .../Phone Screen - SOLUTION-checkpoint.ipynb | 53 + .../On-Site Question 1 - SOLUTION.ipynb | 149 ++ .../On-Site Question 2 - SOLUTION.ipynb | 115 ++ .../On-Site Question 3 - SOLUTION.ipynb | 121 ++ .../Phone Screen - SOLUTION.ipynb | 53 + .../On-Site Question 1 -checkpoint.ipynb | 49 + .../On-Site Question 2 -checkpoint.ipynb | 47 + .../On-Site Question 3 -checkpoint.ipynb | 54 + .../Phone Screen -checkpoint.ipynb | 47 + .../On-Site Question 1 .ipynb | 49 + .../On-Site Question 2 .ipynb | 47 + .../On-Site Question 3 .ipynb | 54 + .../Phone Screen .ipynb | 47 + ...ite Question 1 - SOLUTION-checkpoint.ipynb | 138 ++ ...ite Question 2 - SOLUTION-checkpoint.ipynb | 86 + ...ite Question 3 - SOLUTION-checkpoint.ipynb | 116 ++ .../Phone Screen - SOLUTION-checkpoint.ipynb | 87 + .../On-Site Question 1 - SOLUTION.ipynb | 138 ++ .../On-Site Question 2 - SOLUTION.ipynb | 86 + .../On-Site Question 3 - SOLUTION.ipynb | 116 ++ .../Phone Screen - SOLUTION.ipynb | 87 + .../On-Site Question 1-checkpoint.ipynb | 49 + .../On-Site Question 2-checkpoint.ipynb | 47 + .../On-Site Question 3-checkpoint.ipynb | 47 + .../Phone Screen -checkpoint.ipynb | 47 + .../On-Site Question 1.ipynb | 49 + .../On-Site Question 2.ipynb | 47 + .../On-Site Question 3.ipynb | 47 + .../Phone Screen .ipynb | 47 + Practice.ipynb | 1407 +++++++++++++++++ README.md | 9 + ...Introduction to Recursion-checkpoint.ipynb | 180 +++ .../Memoization-checkpoint.ipynb | 147 ++ ...ample Problems - PRACTICE-checkpoint.ipynb | 293 ++++ ...mple Problems - SOLUTIONS-checkpoint.ipynb | 327 ++++ ...Homework Example Problems-checkpoint.ipynb | 291 ++++ Recursion/Introduction to Recursion.ipynb | 180 +++ Recursion/Memoization.ipynb | 145 ++ ...Homework Example Problems - PRACTICE.ipynb | 293 ++++ ...omework Example Problems - SOLUTIONS.ipynb | 327 ++++ .../Recursion Homework Example Problems.ipynb | 291 ++++ ...Reverse String - SOLUTION-checkpoint.ipynb | 146 ++ ...ing Permutation- SOLUTION-checkpoint.ipynb | 175 ++ ...nacci Sequence - SOLUTION-checkpoint.ipynb | 265 ++++ ... - Coin Change - SOLUTION-checkpoint.ipynb | 308 ++++ ...roblem 1 - Reverse String - SOLUTION.ipynb | 140 ++ ...lem 2 - String Permutation- SOLUTION.ipynb | 171 ++ ...em 3 - Fibonacci Sequence - SOLUTION.ipynb | 255 +++ ...n Problem 4 - Coin Change - SOLUTION.ipynb | 299 ++++ ...oblem 1 - Reverse String -checkpoint.ipynb | 131 ++ ...em 2 - String Permutation-checkpoint.ipynb | 135 ++ ...m 2 - String Permutations-checkpoint.ipynb | 34 + ...em 3 - Fibonacci Sequence-checkpoint.ipynb | 256 +++ ...n Problem 4 - Coin Change-checkpoint.ipynb | 147 ++ ...ecursion Problem 1 - Reverse String .ipynb | 131 ++ ...rsion Problem 2 - String Permutation.ipynb | 136 ++ ...rsion Problem 3 - Fibonacci Sequence.ipynb | 258 +++ .../Recursion Problem 4 - Coin Change.ipynb | 169 ++ ...oblem 1 - Reverse String -checkpoint.ipynb | 133 ++ ...em 2 - String Permutation-checkpoint.ipynb | 135 ++ ...m 2 - String Permutations-checkpoint.ipynb | 34 + ...em 3 - Fibonacci Sequence-checkpoint.ipynb | 248 +++ ...n Problem 4 - Coin Change-checkpoint.ipynb | 147 ++ ...ecursion Problem 1 - Reverse String .ipynb | 133 ++ ...rsion Problem 2 - String Permutation.ipynb | 135 ++ ...rsion Problem 3 - Fibonacci Sequence.ipynb | 248 +++ .../Recursion Problem 4 - Coin Change.ipynb | 147 ++ Reflect Notes.ipynb | 47 + .../How to Approach Riddles-checkpoint.ipynb | 34 + Riddles/How to Approach Riddles.ipynb | 34 + ...ridge Crossing - SOLUTION-checkpoint.ipynb | 66 + ...ns and a Scale - SOLUTION-checkpoint.ipynb | 39 + .../Egg Drop - SOLUTION-checkpoint.ipynb | 73 + ...Hallway Lockers -SOLUTION-checkpoint.ipynb | 63 + .../Jugs of Water - SOLUTION-checkpoint.ipynb | 113 ++ ...Light Switches - SOLUTION-checkpoint.ipynb | 47 + .../Ropes Burning - SOLUTION-checkpoint.ipynb | 49 + .../Bridge Crossing - SOLUTION.ipynb | 66 + .../Coins and a Scale - SOLUTION.ipynb | 39 + .../Egg Drop - SOLUTION.ipynb | 73 + .../Hallway Lockers -SOLUTION.ipynb | 63 + .../Jugs of Water - SOLUTION.ipynb | 113 ++ .../Light Switches - SOLUTION.ipynb | 47 + .../Ropes Burning - SOLUTION.ipynb | 49 + .../Bridge Crossing-checkpoint.ipynb | 46 + .../Coins and a Scale -checkpoint.ipynb | 35 + .../Egg Drop -checkpoint.ipynb | 38 + .../Hallway Lockers-checkpoint.ipynb | 35 + .../Jugs of Water -checkpoint.ipynb | 35 + .../Light Switches -checkpoint.ipynb | 37 + .../Ropes Burning-checkpoint.ipynb | 39 + .../Bridge Crossing.ipynb | 46 + .../Coins and a Scale .ipynb | 35 + .../Egg Drop .ipynb | 38 + .../Hallway Lockers.ipynb | 35 + .../Jugs of Water .ipynb | 35 + .../Light Switches .ipynb | 37 + .../Ropes Burning.ipynb | 39 + ...entation of Binary Search-checkpoint.ipynb | 226 +++ ...ementation of Bubble Sort-checkpoint.ipynb | 109 ++ ...ntation of Insertion Sort-checkpoint.ipynb | 105 ++ ...lementation of Merge Sort-checkpoint.ipynb | 119 ++ ...lementation of Quick Sort-checkpoint.ipynb | 132 ++ ...ntation of Selection Sort-checkpoint.ipynb | 104 ++ ...lementation of Shell Sort-checkpoint.ipynb | 114 ++ ...mentation of a Hash Table-checkpoint.ipynb | 277 ++++ .../Sequential Search-checkpoint.ipynb | 235 +++ .../Implementation of Binary Search.ipynb | 226 +++ .../Implementation of Bubble Sort.ipynb | 105 ++ .../Implementation of Insertion Sort.ipynb | 103 ++ .../Implementation of Merge Sort.ipynb | 117 ++ .../Implementation of Quick Sort.ipynb | 130 ++ .../Implementation of Selection Sort.ipynb | 104 ++ .../Implementation of Shell Sort.ipynb | 114 ++ .../Implementation of a Hash Table.ipynb | 269 ++++ Sorting and Searching/Sequential Search.ipynb | 235 +++ .../Deques Overview-checkpoint.ipynb | 69 + .../Implementation of Deque-checkpoint.ipynb | 180 +++ .../Implementation of Queue-checkpoint.ipynb | 181 +++ .../Implementation of Stack-checkpoint.ipynb | 334 ++++ .../Queues Overview-checkpoint.ipynb | 115 ++ .../Stacks Overview-checkpoint.ipynb | 94 ++ ...eues, and Deques Overview-checkpoint.ipynb | 53 + .../Deques Overview.ipynb | 69 + .../Implementation of Deque.ipynb | 180 +++ .../Implementation of Queue.ipynb | 181 +++ .../Implementation of Stack.ipynb | 334 ++++ .../Queues Overview.ipynb | 115 ++ .../Stacks Overview.ipynb | 94 ++ ...lanced Parentheses Check -checkpoint.ipynb | 169 ++ .../Implement a Deque -checkpoint.ipynb | 51 + ... Queue -Using Two Stacks -checkpoint.ipynb | 131 ++ .../Implement a Queue-checkpoint.ipynb | 104 ++ .../Implement a Stack -checkpoint.ipynb | 228 +++ .../Balanced Parentheses Check .ipynb | 169 ++ .../Implement a Deque .ipynb | 206 +++ ...Implement a Queue -Using Two Stacks .ipynb | 131 ++ .../Implement a Queue.ipynb | 104 ++ .../Implement a Stack .ipynb | 228 +++ ...entheses Check - SOLUTION-checkpoint.ipynb | 212 +++ ...lement a Deque - SOLUTION-checkpoint.ipynb | 65 + ...lement a Queue - SOLUTION-checkpoint.ipynb | 59 + ...ing Two Stacks - SOLUTION-checkpoint.ipynb | 134 ++ ...lement a Stack - SOLUTION-checkpoint.ipynb | 63 + ...alanced Parentheses Check - SOLUTION.ipynb | 204 +++ .../Implement a Deque - SOLUTION.ipynb | 65 + .../Implement a Queue - SOLUTION.ipynb | 59 + ...a Queue -Using Two Stacks - SOLUTION.ipynb | 132 ++ .../Implement a Stack - SOLUTION.ipynb | 63 + ...lanced Parentheses Check -checkpoint.ipynb | 171 ++ .../Implement a Deque -checkpoint.ipynb | 51 + ... Queue -Using Two Stacks -checkpoint.ipynb | 131 ++ .../Implement a Queue-checkpoint.ipynb | 51 + .../Implement a Stack -checkpoint.ipynb | 57 + .../Balanced Parentheses Check .ipynb | 171 ++ .../Implement a Deque .ipynb | 51 + ...Implement a Queue -Using Two Stacks .ipynb | 131 ++ .../Implement a Queue.ipynb | 51 + .../Implement a Stack .ipynb | 57 + .../Stacks, Queues, and Deques Overview.ipynb | 53 + ...inary Heap Implementation-checkpoint.ipynb | 132 ++ .../Binary Search Trees-checkpoint.ipynb | 305 ++++ ...on Implementation (Lists)-checkpoint.ipynb | 74 + ...on (Nodes and References)-checkpoint.ipynb | 122 ++ Trees/Binary Heap Implementation.ipynb | 132 ++ Trees/Binary Search Trees.ipynb | 305 ++++ ...epresentation Implementation (Lists).ipynb | 74 + ...mplementation (Nodes and References).ipynb | 122 ++ .../Binary Search Tree Check-checkpoint.ipynb | 82 + .../Tree Level Order Print-checkpoint.ipynb | 119 ++ ...rim a Binary Search Tree -checkpoint.ipynb | 83 + .../Binary Search Tree Check.ipynb | 82 + .../Node.py | 5 + .../Tree Level Order Print.ipynb | 119 ++ .../Trim a Binary Search Tree .ipynb | 83 + .../bst1.png | Bin 0 -> 61595 bytes .../bst_trim.png | Bin 0 -> 33369 bytes .../tree_print.png | Bin 0 -> 30513 bytes ...rch Tree Check - SOLUTION-checkpoint.ipynb | 155 ++ ...el Order Print - SOLUTION-checkpoint.ipynb | 113 ++ ...ry Search Tree - SOLUTION-checkpoint.ipynb | 100 ++ .../Binary Search Tree Check - SOLUTION.ipynb | 155 ++ .../Tree Level Order Print - SOLUTION.ipynb | 113 ++ ...Trim a Binary Search Tree - SOLUTION.ipynb | 100 ++ .../bst1.png | Bin 0 -> 61595 bytes .../bst_trim.png | Bin 0 -> 33369 bytes .../tree_print.png | Bin 0 -> 30513 bytes .../Binary Search Tree Check-checkpoint.ipynb | 60 + .../Tree Level Order Print-checkpoint.ipynb | 79 + ...rim a Binary Search Tree -checkpoint.ipynb | 76 + .../Binary Search Tree Check.ipynb | 60 + .../Tree Level Order Print.ipynb | 79 + .../Trim a Binary Search Tree .ipynb | 76 + Trees/Trees Interview Problems/bst1.png | Bin 0 -> 61595 bytes Trees/Trees Interview Problems/bst_trim.png | Bin 0 -> 33369 bytes Trees/Trees Interview Problems/tree_print.png | Bin 0 -> 30513 bytes 367 files changed, 47370 insertions(+) create mode 100644 .ipynb_checkpoints/Big O Notation-checkpoint.ipynb create mode 100644 .ipynb_checkpoints/Practice-checkpoint.ipynb create mode 100644 .ipynb_checkpoints/Reflect Notes-checkpoint.ipynb create mode 100644 .project create mode 100644 .pydevproject create mode 100644 Algorithm Analysis and Big O/.ipynb_checkpoints/Algorithm Analysis and Big O Quiz-checkpoint.ipynb create mode 100644 Algorithm Analysis and Big O/.ipynb_checkpoints/Big O Examples -checkpoint.ipynb create mode 100644 Algorithm Analysis and Big O/.ipynb_checkpoints/Big O Notation-checkpoint.ipynb create mode 100644 Algorithm Analysis and Big O/.ipynb_checkpoints/Big O for Python Data Structures-checkpoint.ipynb create mode 100644 Algorithm Analysis and Big O/.ipynb_checkpoints/Introduction to Algorithm Analysis and Big O -checkpoint.ipynb create mode 100644 Algorithm Analysis and Big O/Algorithm Analysis and Big O Quiz.ipynb create mode 100644 Algorithm Analysis and Big O/Big O Examples .ipynb create mode 100644 Algorithm Analysis and Big O/Big O Notation.ipynb create mode 100644 Algorithm Analysis and Big O/Big O for Python Data Structures.ipynb create mode 100644 Algorithm Analysis and Big O/Introduction to Algorithm Analysis and Big O .ipynb create mode 100644 Array Sequences/.ipynb_checkpoints/Amortization-checkpoint.ipynb create mode 100644 Array Sequences/.ipynb_checkpoints/Array Mini-Project-checkpoint.ipynb create mode 100644 Array Sequences/.ipynb_checkpoints/Dynamic Array Exercise-checkpoint.ipynb create mode 100644 Array Sequences/.ipynb_checkpoints/Dynamic Arrays-checkpoint.ipynb create mode 100644 Array Sequences/.ipynb_checkpoints/Introduction to Array Based Sequences-checkpoint.ipynb create mode 100644 Array Sequences/.ipynb_checkpoints/Low Level Arrays-checkpoint.ipynb create mode 100644 Array Sequences/Amortization.ipynb create mode 100644 Array Sequences/Array Mini-Project.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Anagram Check -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Array Pair Sum -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Find the Missing Element -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Largest Continuous Sum -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Sentence Reversal-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/String Compression -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Unique Characters in String-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Anagram Check .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Array Pair Sum .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Find the Missing Element .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Largest Continuous Sum .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Sentence Reversal.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/String Compression .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Unique Characters in String.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Anagram Check - SOLUTION-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Array Pair Sum - SOLUTION-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Find the Missing Element - SOLUTION-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Largest Continuous Sum - SOLUTION-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Sentence Reversal - SOLUTION-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/String Compression -SOLUTION-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Unique Characters in String - SOLUTION-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Anagram Check - SOLUTION.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Array Pair Sum - SOLUTION.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Find the Missing Element - SOLUTION.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Largest Continuous Sum - SOLUTION.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Sentence Reversal - SOLUTION.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/String Compression -SOLUTION.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Unique Characters in String - SOLUTION.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Anagram Check -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Array Pair Sum -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Find the Missing Element -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Largest Continuous Sum -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Sentence Reversal-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/String Compression -checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Unique Characters in String-checkpoint.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Anagram Check .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Array Pair Sum .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Find the Missing Element .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Largest Continuous Sum .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Sentence Reversal.ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/String Compression .ipynb create mode 100644 Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Unique Characters in String.ipynb create mode 100644 Array Sequences/Dynamic Array Exercise.ipynb create mode 100644 Array Sequences/Dynamic Arrays.ipynb create mode 100644 Array Sequences/Introduction to Array Based Sequences.ipynb create mode 100644 Array Sequences/Low Level Arrays.ipynb create mode 100644 Graphs/.ipynb_checkpoints/Implementation of Adjacency List-checkpoint.ipynb create mode 100644 Graphs/.ipynb_checkpoints/Implementation of Breadth First Search-checkpoint.ipynb create mode 100644 Graphs/.ipynb_checkpoints/Implementation of Depth First Search-checkpoint.ipynb create mode 100644 Graphs/.ipynb_checkpoints/Implementation of Graph Overview-checkpoint.ipynb create mode 100644 Graphs/.ipynb_checkpoints/Knight's Tour Example Problem-checkpoint.ipynb create mode 100644 Graphs/.ipynb_checkpoints/Word Ladder Example Problem-checkpoint.ipynb create mode 100644 Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement Breadth First Search Algorithm-checkpoint.ipynb create mode 100644 Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement Depth First Search Algorithm-checkpoint.ipynb create mode 100644 Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Graph-checkpoint.ipynb create mode 100644 Graphs/Graph Interview Questions - PRACTICE/Implement Breadth First Search Algorithm.ipynb create mode 100644 Graphs/Graph Interview Questions - PRACTICE/Implement Depth First Search Algorithm.ipynb create mode 100644 Graphs/Graph Interview Questions - PRACTICE/Implement a Graph.ipynb create mode 100644 Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement Breadth First Search Algorithm-checkpoint.ipynb create mode 100644 Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement Depth First Search Algorithm-checkpoint.ipynb create mode 100644 Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement a Graph-checkpoint.ipynb create mode 100644 Graphs/Graph Interview Questions/Implement Breadth First Search Algorithm.ipynb create mode 100644 Graphs/Graph Interview Questions/Implement Depth First Search Algorithm.ipynb create mode 100644 Graphs/Graph Interview Questions/Implement a Graph.ipynb create mode 100644 Graphs/Implementation of Adjacency List.ipynb create mode 100644 Graphs/Implementation of Breadth First Search.ipynb create mode 100644 Graphs/Implementation of Depth First Search.ipynb create mode 100644 Graphs/Implementation of Graph Overview.ipynb create mode 100644 Graphs/Knight's Tour Example Problem.ipynb create mode 100644 Graphs/Word Ladder Example Problem.ipynb create mode 100644 Graphs/words.txt create mode 100644 Linked Lists/.ipynb_checkpoints/Doubly Linked List Implementation-checkpoint.ipynb create mode 100644 Linked Lists/.ipynb_checkpoints/Doubly Linked Lists-checkpoint.ipynb create mode 100644 Linked Lists/.ipynb_checkpoints/Linked List Overview-checkpoint.ipynb create mode 100644 Linked Lists/.ipynb_checkpoints/Singly Linked List Implementation-checkpoint.ipynb create mode 100644 Linked Lists/.ipynb_checkpoints/Singly Linked Lists-checkpoint.ipynb create mode 100644 Linked Lists/Doubly Linked List Implementation.ipynb create mode 100644 Linked Lists/Doubly Linked Lists.ipynb create mode 100644 Linked Lists/Linked List Overview.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Implement a Doubly Linked List-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Implement a Singly Linked List-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Linked List Nth to Last Node -checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Linked List Reversal -checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Singly Linked List Cycle Check-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Implement a Doubly Linked List.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Implement a Singly Linked List.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Linked List Nth to Last Node .ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Linked List Reversal .ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Singly Linked List Cycle Check.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Implement a Linked List -SOLUTION-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Linked List Nth to Last Node - SOLUTION-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Linked List Reversal - SOLUTION-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Singly Linked List Cycle Check - SOLUTION-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Implement a Linked List -SOLUTION.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Linked List Nth to Last Node - SOLUTION.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Linked List Reversal - SOLUTION.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Singly Linked List Cycle Check - SOLUTION.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Implement a Doubly Linked List-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Implement a Singly Linked List-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Linked List Nth to Last Node -checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Linked List Reversal -checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Singly Linked List Cycle Check-checkpoint.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Implement a Doubly Linked List.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Implement a Singly Linked List.ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Linked List Nth to Last Node .ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Linked List Reversal .ipynb create mode 100644 Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Singly Linked List Cycle Check.ipynb create mode 100644 Linked Lists/Singly Linked List Implementation.ipynb create mode 100644 Linked Lists/Singly Linked Lists.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/Phone Screen - SOLUTION.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 1-checkpoint.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 3-checkpoint.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 1.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 2 .ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 3.ipynb create mode 100644 Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/Phone Screen .ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 -SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 4 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/Phone Screen-checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 3 -SOLUTION.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 4 - SOLUTION.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/Phone Screen.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 1 -checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 3 -checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 4 -checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/Phone Screen-checkpoint.ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 1 .ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 2 .ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 3 .ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 4 .ipynb create mode 100644 Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/Phone Screen.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/Phone Screen - SOLUTION.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 1 -checkpoint.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 3 -checkpoint.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 1 .ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 2 .ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 3 .ipynb create mode 100644 Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/Phone Screen .ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/Phone Screen - SOLUTION.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 1-checkpoint.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 2-checkpoint.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 3-checkpoint.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 1.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 2.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 3.ipynb create mode 100644 Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/Phone Screen .ipynb create mode 100644 Practice.ipynb create mode 100644 README.md create mode 100644 Recursion/.ipynb_checkpoints/Introduction to Recursion-checkpoint.ipynb create mode 100644 Recursion/.ipynb_checkpoints/Memoization-checkpoint.ipynb create mode 100644 Recursion/.ipynb_checkpoints/Recursion Homework Example Problems - PRACTICE-checkpoint.ipynb create mode 100644 Recursion/.ipynb_checkpoints/Recursion Homework Example Problems - SOLUTIONS-checkpoint.ipynb create mode 100644 Recursion/.ipynb_checkpoints/Recursion Homework Example Problems-checkpoint.ipynb create mode 100644 Recursion/Introduction to Recursion.ipynb create mode 100644 Recursion/Memoization.ipynb create mode 100644 Recursion/Recursion Homework Example Problems - PRACTICE.ipynb create mode 100644 Recursion/Recursion Homework Example Problems - SOLUTIONS.ipynb create mode 100644 Recursion/Recursion Homework Example Problems.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 1 - Reverse String - SOLUTION-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 2 - String Permutation- SOLUTION-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence - SOLUTION-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 4 - Coin Change - SOLUTION-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 1 - Reverse String - SOLUTION.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 2 - String Permutation- SOLUTION.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 3 - Fibonacci Sequence - SOLUTION.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 4 - Coin Change - SOLUTION.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 1 - Reverse String -checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 2 - String Permutation-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 2 - String Permutations-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 4 - Coin Change-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 1 - Reverse String .ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 2 - String Permutation.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 3 - Fibonacci Sequence.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 4 - Coin Change.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 1 - Reverse String -checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 2 - String Permutation-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 2 - String Permutations-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 4 - Coin Change-checkpoint.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 1 - Reverse String .ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 2 - String Permutation.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 3 - Fibonacci Sequence.ipynb create mode 100644 Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 4 - Coin Change.ipynb create mode 100644 Reflect Notes.ipynb create mode 100644 Riddles/.ipynb_checkpoints/How to Approach Riddles-checkpoint.ipynb create mode 100644 Riddles/How to Approach Riddles.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Bridge Crossing - SOLUTION-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Coins and a Scale - SOLUTION-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Egg Drop - SOLUTION-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Hallway Lockers -SOLUTION-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Jugs of Water - SOLUTION-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Light Switches - SOLUTION-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Ropes Burning - SOLUTION-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Bridge Crossing - SOLUTION.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Coins and a Scale - SOLUTION.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Egg Drop - SOLUTION.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Hallway Lockers -SOLUTION.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Jugs of Water - SOLUTION.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Light Switches - SOLUTION.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Ropes Burning - SOLUTION.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Bridge Crossing-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Coins and a Scale -checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Egg Drop -checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Hallway Lockers-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Jugs of Water -checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Light Switches -checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Ropes Burning-checkpoint.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/Bridge Crossing.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/Coins and a Scale .ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/Egg Drop .ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/Hallway Lockers.ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/Jugs of Water .ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/Light Switches .ipynb create mode 100644 Riddles/Riddle Interview Problems/Riddle Interview Problems_/Ropes Burning.ipynb create mode 100644 Sorting and Searching/.ipynb_checkpoints/Implementation of Binary Search-checkpoint.ipynb create mode 100644 Sorting and Searching/.ipynb_checkpoints/Implementation of Bubble Sort-checkpoint.ipynb create mode 100644 Sorting and Searching/.ipynb_checkpoints/Implementation of Insertion Sort-checkpoint.ipynb create mode 100644 Sorting and Searching/.ipynb_checkpoints/Implementation of Merge Sort-checkpoint.ipynb create mode 100644 Sorting and Searching/.ipynb_checkpoints/Implementation of Quick Sort-checkpoint.ipynb create mode 100644 Sorting and Searching/.ipynb_checkpoints/Implementation of Selection Sort-checkpoint.ipynb create mode 100644 Sorting and Searching/.ipynb_checkpoints/Implementation of Shell Sort-checkpoint.ipynb create mode 100644 Sorting and Searching/.ipynb_checkpoints/Implementation of a Hash Table-checkpoint.ipynb create mode 100644 Sorting and Searching/.ipynb_checkpoints/Sequential Search-checkpoint.ipynb create mode 100644 Sorting and Searching/Implementation of Binary Search.ipynb create mode 100644 Sorting and Searching/Implementation of Bubble Sort.ipynb create mode 100644 Sorting and Searching/Implementation of Insertion Sort.ipynb create mode 100644 Sorting and Searching/Implementation of Merge Sort.ipynb create mode 100644 Sorting and Searching/Implementation of Quick Sort.ipynb create mode 100644 Sorting and Searching/Implementation of Selection Sort.ipynb create mode 100644 Sorting and Searching/Implementation of Shell Sort.ipynb create mode 100644 Sorting and Searching/Implementation of a Hash Table.ipynb create mode 100644 Sorting and Searching/Sequential Search.ipynb create mode 100644 Stacks, Queues and Deques/.ipynb_checkpoints/Deques Overview-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Deque-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Queue-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Stack-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/.ipynb_checkpoints/Queues Overview-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/.ipynb_checkpoints/Stacks Overview-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/.ipynb_checkpoints/Stacks, Queues, and Deques Overview-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Deques Overview.ipynb create mode 100644 Stacks, Queues and Deques/Implementation of Deque.ipynb create mode 100644 Stacks, Queues and Deques/Implementation of Queue.ipynb create mode 100644 Stacks, Queues and Deques/Implementation of Stack.ipynb create mode 100644 Stacks, Queues and Deques/Queues Overview.ipynb create mode 100644 Stacks, Queues and Deques/Stacks Overview.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Balanced Parentheses Check -checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Deque -checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Queue -Using Two Stacks -checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Queue-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Stack -checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Balanced Parentheses Check .ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Deque .ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Queue -Using Two Stacks .ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Queue.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Stack .ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Balanced Parentheses Check - SOLUTION-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Deque - SOLUTION-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Queue - SOLUTION-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Queue -Using Two Stacks - SOLUTION-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Stack - SOLUTION-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Balanced Parentheses Check - SOLUTION.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Deque - SOLUTION.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Queue - SOLUTION.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Queue -Using Two Stacks - SOLUTION.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Stack - SOLUTION.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Balanced Parentheses Check -checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Deque -checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Queue -Using Two Stacks -checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Queue-checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Stack -checkpoint.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Balanced Parentheses Check .ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Deque .ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Queue -Using Two Stacks .ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Queue.ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Stack .ipynb create mode 100644 Stacks, Queues and Deques/Stacks, Queues, and Deques Overview.ipynb create mode 100644 Trees/.ipynb_checkpoints/Binary Heap Implementation-checkpoint.ipynb create mode 100644 Trees/.ipynb_checkpoints/Binary Search Trees-checkpoint.ipynb create mode 100644 Trees/.ipynb_checkpoints/Tree Representation Implementation (Lists)-checkpoint.ipynb create mode 100644 Trees/.ipynb_checkpoints/Tree Representation Implementation (Nodes and References)-checkpoint.ipynb create mode 100644 Trees/Binary Heap Implementation.ipynb create mode 100644 Trees/Binary Search Trees.ipynb create mode 100644 Trees/Tree Representation Implementation (Lists).ipynb create mode 100644 Trees/Tree Representation Implementation (Nodes and References).ipynb create mode 100644 Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Binary Search Tree Check-checkpoint.ipynb create mode 100644 Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Tree Level Order Print-checkpoint.ipynb create mode 100644 Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Trim a Binary Search Tree -checkpoint.ipynb create mode 100644 Trees/Trees Interview Problems - PRACTICE/Binary Search Tree Check.ipynb create mode 100644 Trees/Trees Interview Problems - PRACTICE/Node.py create mode 100644 Trees/Trees Interview Problems - PRACTICE/Tree Level Order Print.ipynb create mode 100644 Trees/Trees Interview Problems - PRACTICE/Trim a Binary Search Tree .ipynb create mode 100644 Trees/Trees Interview Problems - PRACTICE/bst1.png create mode 100644 Trees/Trees Interview Problems - PRACTICE/bst_trim.png create mode 100644 Trees/Trees Interview Problems - PRACTICE/tree_print.png create mode 100644 Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Binary Search Tree Check - SOLUTION-checkpoint.ipynb create mode 100644 Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Tree Level Order Print - SOLUTION-checkpoint.ipynb create mode 100644 Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Trim a Binary Search Tree - SOLUTION-checkpoint.ipynb create mode 100644 Trees/Trees Interview Problems - SOLUTIONS/Binary Search Tree Check - SOLUTION.ipynb create mode 100644 Trees/Trees Interview Problems - SOLUTIONS/Tree Level Order Print - SOLUTION.ipynb create mode 100644 Trees/Trees Interview Problems - SOLUTIONS/Trim a Binary Search Tree - SOLUTION.ipynb create mode 100644 Trees/Trees Interview Problems - SOLUTIONS/bst1.png create mode 100644 Trees/Trees Interview Problems - SOLUTIONS/bst_trim.png create mode 100644 Trees/Trees Interview Problems - SOLUTIONS/tree_print.png create mode 100644 Trees/Trees Interview Problems/.ipynb_checkpoints/Binary Search Tree Check-checkpoint.ipynb create mode 100644 Trees/Trees Interview Problems/.ipynb_checkpoints/Tree Level Order Print-checkpoint.ipynb create mode 100644 Trees/Trees Interview Problems/.ipynb_checkpoints/Trim a Binary Search Tree -checkpoint.ipynb create mode 100644 Trees/Trees Interview Problems/Binary Search Tree Check.ipynb create mode 100644 Trees/Trees Interview Problems/Tree Level Order Print.ipynb create mode 100644 Trees/Trees Interview Problems/Trim a Binary Search Tree .ipynb create mode 100644 Trees/Trees Interview Problems/bst1.png create mode 100644 Trees/Trees Interview Problems/bst_trim.png create mode 100644 Trees/Trees Interview Problems/tree_print.png diff --git a/.ipynb_checkpoints/Big O Notation-checkpoint.ipynb b/.ipynb_checkpoints/Big O Notation-checkpoint.ipynb new file mode 100644 index 00000000..d4218415 --- /dev/null +++ b/.ipynb_checkpoints/Big O Notation-checkpoint.ipynb @@ -0,0 +1,34 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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 +} diff --git a/.ipynb_checkpoints/Practice-checkpoint.ipynb b/.ipynb_checkpoints/Practice-checkpoint.ipynb new file mode 100644 index 00000000..dec76da5 --- /dev/null +++ b/.ipynb_checkpoints/Practice-checkpoint.ipynb @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'HELLO'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s = 'hello'\n", + "s.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hi\n" + ] + } + ], + "source": [ + "set1 = set()\n", + "print('hi')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('hello',)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import timeit\n", + "timeit\n", + "singleton = 'hello',\n", + "singleton" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "{'banana', 'apple', 'orange', 'pear'}\n" + ] + } + ], + "source": [ + "basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}\n", + "print(type(basket))\n", + "print(basket)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{' ', 't', 's', 'i', 'h', 'o', 'e', 'n', 'm', 'g'}\n" + ] + } + ], + "source": [ + "chars = {c for c in 'this is something'}\n", + "print(chars)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s = 'A man, a plan, a canal: Panama'\n" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "'return' outside function (, line 7)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m7\u001b[0m\n\u001b[0;31m return False\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m 'return' outside function\n" + ] + } + ], + "source": [ + "s='ab'\n", + "s=s.casefold()\n", + "chars = list(filter(lambda c:c.isalpha(), s))\n", + "low, high=0, len(chars)-1\n", + "while(low + + Python-for-Algorithm-and-Interviews + + + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 00000000..d001f0ae --- /dev/null +++ b/.pydevproject @@ -0,0 +1,5 @@ + + +Default +python interpreter + diff --git a/Algorithm Analysis and Big O/.ipynb_checkpoints/Algorithm Analysis and Big O Quiz-checkpoint.ipynb b/Algorithm Analysis and Big O/.ipynb_checkpoints/Algorithm Analysis and Big O Quiz-checkpoint.ipynb new file mode 100644 index 00000000..5f2b2c4f --- /dev/null +++ b/Algorithm Analysis and Big O/.ipynb_checkpoints/Algorithm Analysis and Big O Quiz-checkpoint.ipynb @@ -0,0 +1,32 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quiz is offered only in the course!" + ] + } + ], + "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 +} diff --git a/Algorithm Analysis and Big O/.ipynb_checkpoints/Big O Examples -checkpoint.ipynb b/Algorithm Analysis and Big O/.ipynb_checkpoints/Big O Examples -checkpoint.ipynb new file mode 100644 index 00000000..7f3a7a2d --- /dev/null +++ b/Algorithm Analysis and Big O/.ipynb_checkpoints/Big O Examples -checkpoint.ipynb @@ -0,0 +1,580 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Big O Examples\n", + "\n", + "In the first part of the Big-O example section we will go through various iterations of the various Big-O functions. Make sure to complete the reading assignment!\n", + "\n", + "Let's begin with some simple examples and explore what their Big-O is.\n", + "\n", + "## O(1) Constant" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n" + ] + } + ], + "source": [ + "def func_constant(values):\n", + " '''\n", + " Prints first item in a list of values.\n", + " '''\n", + " print values[0]\n", + " \n", + "func_constant([1,2,3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how this function is constant because regardless of the list size, the function will only ever take a constant step size, in this case 1, printing the first value from a list. so we can see here that an input list of 100 values will print just 1 item, a list of 10,000 values will print just 1 item, and a list of **n** values will print just 1 item!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## O(n) Linear" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "def func_lin(lst):\n", + " '''\n", + " Takes in list and prints out all values\n", + " '''\n", + " for val in lst:\n", + " print val\n", + " \n", + "func_lin([1,2,3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This function runs in O(n) (linear time). This means that the number of operations taking place scales linearly with n, so we can see here that an input list of 100 values will print 100 times, a list of 10,000 values will print 10,000 times, and a list of **n** values will print **n** times." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## O(n^2) Quadratic" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 0\n", + "0 1\n", + "0 2\n", + "0 3\n", + "1 0\n", + "1 1\n", + "1 2\n", + "1 3\n", + "2 0\n", + "2 1\n", + "2 2\n", + "2 3\n", + "3 0\n", + "3 1\n", + "3 2\n", + "3 3\n" + ] + } + ], + "source": [ + "def func_quad(lst):\n", + " '''\n", + " Prints pairs for every item in list.\n", + " '''\n", + " for item_1 in lst:\n", + " for item_2 in lst:\n", + " print item_1,item_2\n", + " \n", + "lst = [0, 1, 2, 3]\n", + "\n", + "func_quad(lst)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we now have two loops, one nested inside another. This means that for a list of n items, we will have to perform n operations for *every item in the list!* This means in total, we will perform n times n assignments, or n^2. So a list of 10 items will have 10^2, or 100 operations. You can see how dangerous this can get for very large inputs! This is why Big-O is so important to be aware of!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "______\n", + "## Calculating Scale of Big-O\n", + "\n", + "In this section we will discuss how insignificant terms drop out of Big-O notation.\n", + "\n", + "When it comes to Big O notation we only care about the most significant terms, remember as the input grows larger only the fastest growing terms will matter. If you've taken a calculus class before, this will reminf you of taking limits towards infinity. Let's see an example of how to drop constants:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def print_once(lst):\n", + " '''\n", + " Prints all items once\n", + " '''\n", + " for val in lst:\n", + " print val" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "print_once(lst)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The print_once() function is O(n) since it will scale linearly with the input. What about the next example?" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def print_3(lst):\n", + " '''\n", + " Prints all items three times\n", + " '''\n", + " for val in lst:\n", + " print val\n", + " \n", + " for val in lst:\n", + " print val\n", + " \n", + " for val in lst:\n", + " print val" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "0\n", + "1\n", + "2\n", + "3\n", + "0\n", + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "print_3(lst)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the first function will print O(n) items and the second will print O(3n) items. However for n going to inifinity the constant can be dropped, since it will not have a large effect, so both functions are O(n).\n", + "\n", + "Let's see a more complex example of this:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def comp(lst):\n", + " '''\n", + " This function prints the first item O(1)\n", + " Then is prints the first 1/2 of the list O(n/2)\n", + " Then prints a string 10 times O(10)\n", + " '''\n", + " print lst[0]\n", + " \n", + " midpoint = len(lst)/2\n", + " \n", + " for val in lst[:midpoint]:\n", + " print val\n", + " \n", + " for x in range(10):\n", + " print 'number'" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n" + ] + } + ], + "source": [ + "lst = [1,2,3,4,5,6,7,8,9,10]\n", + "\n", + "comp(lst)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So let's break down the operations here. We can combine each operation to get the total Big-O of the function:\n", + "\n", + "$$O(1 + n/2 + 10)$$\n", + "\n", + "We can see that as n grows larger the 1 and 10 terms become insignificant and the 1/2 term multiplied against n will also not have much of an effect as n goes towards infinity. This means the function is simply O(n)!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Worst Case vs Best Case\n", + "\n", + "Many times we are only concerned with the worst possible case of an algorithm, but in an interview setting its important to keep in mind that worst case and best case scenarios may be completely different Big-O times. For example, consider the following function:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def matcher(lst,match):\n", + " '''\n", + " Given a list lst, return a boolean indicating if match item is in the list\n", + " '''\n", + " for item in lst:\n", + " if item == match:\n", + " return True\n", + " return False" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lst" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "matcher(lst,1)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "matcher(lst,11)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that in the first scenario, the best case was actually O(1), since the match was found at the first element. In the case where there is no match, every element must be checked, this results in a worst case time of O(n). Later on we will also discuss average case time.\n", + "\n", + "Finally let's introduce the concept of space complexity.\n", + "\n", + "## Space Complexity\n", + "\n", + "Many times we are also concerned with how much memory/space an algorithm uses. The notation of space complexity is the same, but instead of checking the time of operations, we check the size of the allocation of memory.\n", + "\n", + "Let's see a few examples:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def printer(n=10):\n", + " '''\n", + " Prints \"hello world!\" n times\n", + " '''\n", + " for x in range(10):\n", + " print 'Hello World!'" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n" + ] + } + ], + "source": [ + "printer()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we only assign the 'hello world!' variable once, not every time we print. So the algorithm has O(1) **space** complexity and an O(n) **time** complexity. \n", + "\n", + "Let's see an example of O(n) **space** complexity:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def create_list(n):\n", + " new_list = []\n", + " \n", + " for num in range(n):\n", + " new_list.append('new')\n", + " \n", + " return new_list" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['new', 'new', 'new', 'new', 'new']\n" + ] + } + ], + "source": [ + "print create_list(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how the size of the new_list object scales with the input **n**, this shows that it is an O(n) algorithm with regards to **space** complexity.\n", + "_____\n", + "\n", + "Thats it for this lecture, before continuing on, make sure to complete the homework assignment below:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Homework Assignment\n", + "\n", + "Your homework assignment after this lecture is to read the fantastic explanations of Big-O at these two sources:\n", + "\n", + "* [Big-O Notation Explained](http://stackoverflow.com/questions/487258/plain-english-explanation-of-big-o/487278#487278)\n", + "\n", + "* [Big-O Examples Explained](http://stackoverflow.com/questions/2307283/what-does-olog-n-mean-exactly)" + ] + } + ], + "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 +} diff --git a/Algorithm Analysis and Big O/.ipynb_checkpoints/Big O Notation-checkpoint.ipynb b/Algorithm Analysis and Big O/.ipynb_checkpoints/Big O Notation-checkpoint.ipynb new file mode 100644 index 00000000..28cb4211 --- /dev/null +++ b/Algorithm Analysis and Big O/.ipynb_checkpoints/Big O Notation-checkpoint.ipynb @@ -0,0 +1,206 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Big O Notation\n", + "In this lecture we will go over how the syntax of Big-O Notation works and how we can describe algorithms using Big-O Notation!\n", + "\n", + "We previously discussed the functions below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# First function (Note the use of xrange since this is in Python 2)\n", + "def sum1(n):\n", + " '''\n", + " Take an input of n and return the sum of the numbers from 0 to n\n", + " '''\n", + " final_sum = 0\n", + " for x in xrange(n+1): \n", + " final_sum += x\n", + " \n", + " return final_sum" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def sum2(n):\n", + " \"\"\"\n", + " Take an input of n and return the sum of the numbers from 0 to n\n", + " \"\"\"\n", + " return (n*(n+1))/2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we want to develop a notation to objectively compare the efficiency of these two algorithms. A good place to start would be to compare the number of assignments each algorithm makes.\n", + "\n", + "The original **sum1** function will create an assignment **n+1** times, we can see this from the range based function. This means it will assign the final_sum variable n+1 times. We can then say that for a problem of n size (in this case just a number n) this function will take 1+n steps.\n", + "\n", + "This **n** notation allows us to compare solutions and algorithms relative to the size of the problem, since sum1(10) and sum1(100000) would take very different times to run but be using the same algorithm. We can also note that as n grows very large, the **+1** won't have much effect. So let's begin discussing how to build a syntax for this notation.\n", + "________\n", + "\n", + "Now we will discuss how we can formalize this notation and idea.\n", + "\n", + "Big-O notation describes *how quickly runtime will grow relative to the input as the input get arbitrarily large*.\n", + "\n", + "Let's examine some of these points more closely:\n", + "\n", + "* Remember, we want to compare how quickly runtime will grows, not compare exact runtimes, since those can vary depending on hardware.\n", + "\n", + "* Since we want to compare for a variety of input sizes, we are only concerned with runtime grow *relative* to the input. This is why we use **n** for notation.\n", + "\n", + "* As n gets arbitrarily large we only worry about terms that will grow the fastest as n gets large, to this point, Big-O analysis is also known as **asymptotic analysis**\n", + "\n", + "\n", + "As for syntax sum1() can be said to be **O(n)** since its runtime grows linearly with the input size. In the next lecture we will go over more specific examples of various O() types and examples. To conclude this lecture we will show the potential for vast difference in runtimes of Big-O functions.\n", + "\n", + "## Runtimes of Common Big-O Functions\n", + "\n", + "Here is a table of common Big-O functions:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + "
Big-OName
1Constant
log(n)Logarithmic
nLinear
nlog(n)Log Linear
n^2Quadratic
n^3Cubic
2^nExponential
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's plot the runtime versus the Big-O to compare the runtimes. We'll use a simple [matplotlib](http://matplotlib.org/) for the plot below. (Don't be concerned with how to use matplotlib, that is irrelevant for this part)." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from math import log\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "plt.style.use('bmh')\n", + "\n", + "# Set up runtime comparisons\n", + "n = np.linspace(1,10,1000)\n", + "labels = ['Constant','Logarithmic','Linear','Log Linear','Quadratic','Cubic','Exponential']\n", + "big_o = [np.ones(n.shape),np.log(n),n,n*np.log(n),n**2,n**3,2**n]\n", + "\n", + "# Plot setup\n", + "plt.figure(figsize=(12,10))\n", + "plt.ylim(0,50)\n", + "\n", + "for i in range(len(big_o)):\n", + " plt.plot(n,big_o[i],label = labels[i])\n", + "\n", + "\n", + "plt.legend(loc=0)\n", + "plt.ylabel('Relative Runtime')\n", + "plt.xlabel('n')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how much of a difference a Big-O efficiency can make for the same n value against the projected runtime! Clearly we want to choose algorithms that stay away from any exponential, quadratic, or cubic behavior!\n", + "\n", + "In the next lecture we will learn how to properly denote Big-O and look at examples of various problems and calculate the Big-O of them!" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python [conda env:python3]", + "language": "python", + "name": "conda-env-python3-py" + }, + "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.1" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Algorithm Analysis and Big O/.ipynb_checkpoints/Big O for Python Data Structures-checkpoint.ipynb b/Algorithm Analysis and Big O/.ipynb_checkpoints/Big O for Python Data Structures-checkpoint.ipynb new file mode 100644 index 00000000..ee5c35e6 --- /dev/null +++ b/Algorithm Analysis and Big O/.ipynb_checkpoints/Big O for Python Data Structures-checkpoint.ipynb @@ -0,0 +1,288 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Big O for Python Data Structures\n", + "In this lecture we will go over the Big O of built-in data structures in Python: Lists and Dictionaries." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Lists\n", + "\n", + "In Python lists act as dynamic arrays and support a number of common operations through methods called on them. The two most common operations performed on a list are indexing and assigning to an index position. These operations are both designed to be run in constant time, O(1).\n", + "\n", + "Let's imagine you wanted to test different methods to construct a list that is [0,1,2...10000]. Let go ahead and compare various methods, such as appending to the end of a list, concatenating a list, or using tools such as casting and list comprehension.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def method1():\n", + " l = []\n", + " for n in xrange(10000):\n", + " l = l + [n]\n", + "\n", + "def method2():\n", + " l = []\n", + " for n in xrange(10000):\n", + " l.append(n)\n", + "\n", + "def method3():\n", + " l = [n for n in xrange(10000)]\n", + "\n", + "def method4():\n", + " l = range(10000) # Python 3: list(range(10000))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's now test these methods using the timeit magic function:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10 loops, best of 3: 162 ms per loop\n", + "1000 loops, best of 3: 820 µs per loop\n", + "1000 loops, best of 3: 307 µs per loop\n", + "10000 loops, best of 3: 77.7 µs per loop\n" + ] + } + ], + "source": [ + "%timeit method1()\n", + "%timeit method2()\n", + "%timeit method3()\n", + "%timeit method4()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can clearly see that the most effective method is the built-in range() function in Python!\n", + "\n", + "It is important to keep these factors in mind when writing efficient code. More importantly begin thinking about how we are able to index with O(1). We will discuss this in more detail when we cover arrays general. For now, take a look at the table below for an overview of Big-O efficiencies." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Table of Big-O for common list operations\n", + "\n", + "** Please note, in order to see this table, you may need to download this .ipynb file and view it locally, sometimes GitHub or nbveiwer have trouble showing the HTML for it... **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "
Operation Big-O Efficiency
index []O(1)
index assignmentO(1)
appendO(1)
pop()O(1)
pop(i)O(n)
insert(i,item)O(n)
del operatorO(n)
iterationO(n)
contains (in)O(n)
get slice [x:y]O(k)
del sliceO(n)
set sliceO(n+k)
reverseO(n)
concatenateO(k)
sortO(n log n)
multiplyO(nk)
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Dictionaries\n", + "\n", + "Dictionaries in Python are an implementation of a hash table. They operate with keys and values, for example:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "d = {'k1':1,'k2':2}" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d['k1']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Something that is pretty amazing is that getting and setting items in a dictionary are O(1)! Hash tables are designed with efficiency in mind, and we will explore them in much more detail later on in the course as one of the most important data structures to undestand. In the meantime, refer to the table below for Big-O efficiencies of common dictionary operations:\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
OperationBig-O Efficiency
copyO(n)
get itemO(1)
set itemO(1)
delete itemO(1)
contains (in)O(1)
iterationO(n)
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "By the end of this section you should have an understanding of how Big-O is used in Algorithm analysis and be able to work out the Big-O of an algorithm you've developed. Get ready, there's a quiz up next!" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python [conda env:python3]", + "language": "python", + "name": "conda-env-python3-py" + }, + "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.1" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Algorithm Analysis and Big O/.ipynb_checkpoints/Introduction to Algorithm Analysis and Big O -checkpoint.ipynb b/Algorithm Analysis and Big O/.ipynb_checkpoints/Introduction to Algorithm Analysis and Big O -checkpoint.ipynb new file mode 100644 index 00000000..0238db22 --- /dev/null +++ b/Algorithm Analysis and Big O/.ipynb_checkpoints/Introduction to Algorithm Analysis and Big O -checkpoint.ipynb @@ -0,0 +1,194 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Introduction to Algorithm Analysis and Big O\n", + "\n", + "In this lecture we will discuss how to analyze Algorithms and why it is important to do so!\n", + "\n", + "## Why analyze algorithms?\n", + "\n", + "Before we begin, let's clarify what an algorthim is. In this course, an **algorithm** is simply a procedure or formula for solving a problem. Some problems are famous enough that the algorithms have names, as well as some procdures being common enough that the algorithm associated with it also has a name. So now we have a good question we need to answer:\n", + "\n", + "** *How do analyze algorithms and how can we compare algorithms against each other?* **\n", + "\n", + "Imagine if you and a friend both came up with functions to sum the numbers from 0 to N. How would you compare the functions and algorithms within the functions? Let's say you both cam up with these two seperate functions:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# First function (Note the use of xrange since this is in Python 2)\n", + "def sum1(n):\n", + " '''\n", + " Take an input of n and return the sum of the numbers from 0 to n\n", + " '''\n", + " final_sum = 0\n", + " for x in xrange(n+1): \n", + " final_sum += x\n", + " \n", + " return final_sum" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum1(10)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def sum2(n):\n", + " \"\"\"\n", + " Take an input of n and return the sum of the numbers from 0 to n\n", + " \"\"\"\n", + " return (n*(n+1))/2" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum2(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You'll notice both functions have the same result, but completely different algorithms. You'll note that the first function iteratively adds the numbers, while the second function makes use of:\n", + "$$ \\sum_{i=0}^{n} {i} = \\frac{n(n+1)}{2} $$\n", + "\n", + "So how can we objectively compare the algorithms? We could compare the amount of space they take in memory or we could also compare how much time it takes each function to run. We can use the built in **%timeit** magic function in jupyter to compare the time of the functions. The [**%timeit**](https://ipython.org/ipython-doc/3/interactive/magics.html#magic-timeit) magic in Jupyter Notebooks will repeat the loop iteration a certain number of times and take the best result. Check out the link for the documentation. \n", + "\n", + "Let's go ahead and compare the time it took to run the functions:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The slowest run took 5.15 times longer than the fastest. This could mean that an intermediate result is being cached \n", + "100000 loops, best of 3: 4.86 µs per loop\n" + ] + } + ], + "source": [ + "%timeit sum1(100)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The slowest run took 16.54 times longer than the fastest. This could mean that an intermediate result is being cached \n", + "10000000 loops, best of 3: 173 ns per loop\n" + ] + } + ], + "source": [ + "%timeit sum2(100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the second function is much more efficient! Running at a much faster rate than the first. However, we can not use \"time to run\" as an objective measurement, because that will depend on the speed of the computer itself and hardware capabilities. So we will need to use another method, **Big-O**!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "In the next lecture we will discuss Big-O notation and why its so important!" + ] + } + ], + "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 +} diff --git a/Algorithm Analysis and Big O/Algorithm Analysis and Big O Quiz.ipynb b/Algorithm Analysis and Big O/Algorithm Analysis and Big O Quiz.ipynb new file mode 100644 index 00000000..5f2b2c4f --- /dev/null +++ b/Algorithm Analysis and Big O/Algorithm Analysis and Big O Quiz.ipynb @@ -0,0 +1,32 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quiz is offered only in the course!" + ] + } + ], + "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 +} diff --git a/Algorithm Analysis and Big O/Big O Examples .ipynb b/Algorithm Analysis and Big O/Big O Examples .ipynb new file mode 100644 index 00000000..9352c727 --- /dev/null +++ b/Algorithm Analysis and Big O/Big O Examples .ipynb @@ -0,0 +1,558 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Big O Examples\n", + "\n", + "In the first part of the Big-O example section we will go through various iterations of the various Big-O functions. Make sure to complete the reading assignment!\n", + "\n", + "Let's begin with some simple examples and explore what their Big-O is.\n", + "\n", + "## O(1) Constant" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n" + ] + } + ], + "source": [ + "def func_constant(values):\n", + " '''\n", + " Prints first item in a list of values.\n", + " '''\n", + " print values[0]\n", + " \n", + "func_constant([1,2,3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how this function is constant because regardless of the list size, the function will only ever take a constant step size, in this case 1, printing the first value from a list. so we can see here that an input list of 100 values will print just 1 item, a list of 10,000 values will print just 1 item, and a list of **n** values will print just 1 item!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## O(n) Linear" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "def func_lin(lst):\n", + " '''\n", + " Takes in list and prints out all values\n", + " '''\n", + " for val in lst:\n", + " print val\n", + " \n", + "func_lin([1,2,3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This function runs in O(n) (linear time). This means that the number of operations taking place scales linearly with n, so we can see here that an input list of 100 values will print 100 times, a list of 10,000 values will print 10,000 times, and a list of **n** values will print **n** times." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## O(n^2) Quadratic" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 0\n", + "0 1\n", + "0 2\n", + "0 3\n", + "1 0\n", + "1 1\n", + "1 2\n", + "1 3\n", + "2 0\n", + "2 1\n", + "2 2\n", + "2 3\n", + "3 0\n", + "3 1\n", + "3 2\n", + "3 3\n" + ] + } + ], + "source": [ + "def func_quad(lst):\n", + " '''\n", + " Prints pairs for every item in list.\n", + " '''\n", + " for item_1 in lst:\n", + " for item_2 in lst:\n", + " print item_1,item_2\n", + " \n", + "lst = [0, 1, 2, 3]\n", + "\n", + "func_quad(lst)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we now have two loops, one nested inside another. This means that for a list of n items, we will have to perform n operations for *every item in the list!* This means in total, we will perform n times n assignments, or n^2. So a list of 10 items will have 10^2, or 100 operations. You can see how dangerous this can get for very large inputs! This is why Big-O is so important to be aware of!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "______\n", + "## Calculating Scale of Big-O\n", + "\n", + "In this section we will discuss how insignificant terms drop out of Big-O notation.\n", + "\n", + "When it comes to Big O notation we only care about the most significant terms, remember as the input grows larger only the fastest growing terms will matter. If you've taken a calculus class before, this will reminf you of taking limits towards infinity. Let's see an example of how to drop constants:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def print_once(lst):\n", + " '''\n", + " Prints all items once\n", + " '''\n", + " for val in lst:\n", + " print val" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "print_once(lst)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The print_once() function is O(n) since it will scale linearly with the input. What about the next example?" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def print_3(lst):\n", + " '''\n", + " Prints all items three times\n", + " '''\n", + " for val in lst:\n", + " print val\n", + " \n", + " for val in lst:\n", + " print val\n", + " \n", + " for val in lst:\n", + " print val" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "0\n", + "1\n", + "2\n", + "3\n", + "0\n", + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "print_3(lst)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the first function will print O(n) items and the second will print O(3n) items. However for n going to inifinity the constant can be dropped, since it will not have a large effect, so both functions are O(n).\n", + "\n", + "Let's see a more complex example of this:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def comp(lst):\n", + " '''\n", + " This function prints the first item O(1)\n", + " Then is prints the first 1/2 of the list O(n/2)\n", + " Then prints a string 10 times O(10)\n", + " '''\n", + " print lst[0]\n", + " \n", + " midpoint = len(lst)/2\n", + " \n", + " for val in lst[:midpoint]:\n", + " print val\n", + " \n", + " for x in range(10):\n", + " print 'number'" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n", + "number\n" + ] + } + ], + "source": [ + "lst = [1,2,3,4,5,6,7,8,9,10]\n", + "\n", + "comp(lst)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So let's break down the operations here. We can combine each operation to get the total Big-O of the function:\n", + "\n", + "$$O(1 + n/2 + 10)$$\n", + "\n", + "We can see that as n grows larger the 1 and 10 terms become insignificant and the 1/2 term multiplied against n will also not have much of an effect as n goes towards infinity. This means the function is simply O(n)!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Worst Case vs Best Case\n", + "\n", + "Many times we are only concerned with the worst possible case of an algorithm, but in an interview setting its important to keep in mind that worst case and best case scenarios may be completely different Big-O times. For example, consider the following function:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def matcher(lst,match):\n", + " '''\n", + " Given a list lst, return a boolean indicating if match item is in the list\n", + " '''\n", + " for item in lst:\n", + " if item == match:\n", + " return True\n", + " return False" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lst" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "matcher(lst,1)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "matcher(lst,11)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that in the first scenario, the best case was actually O(1), since the match was found at the first element. In the case where there is no match, every element must be checked, this results in a worst case time of O(n). Later on we will also discuss average case time.\n", + "\n", + "Finally let's introduce the concept of space complexity.\n", + "\n", + "## Space Complexity\n", + "\n", + "Many times we are also concerned with how much memory/space an algorithm uses. The notation of space complexity is the same, but instead of checking the time of operations, we check the size of the allocation of memory.\n", + "\n", + "Let's see a few examples:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def printer(n=10):\n", + " '''\n", + " Prints \"hello world!\" n times\n", + " '''\n", + " for x in range(n):\n", + " print 'Hello World!'" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n", + "Hello World!\n" + ] + } + ], + "source": [ + "printer()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we only assign the 'hello world!' variable once, not every time we print. So the algorithm has O(1) **space** complexity and an O(n) **time** complexity. \n", + "\n", + "Let's see an example of O(n) **space** complexity:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def create_list(n):\n", + " new_list = []\n", + " \n", + " for num in range(n):\n", + " new_list.append('new')\n", + " \n", + " return new_list" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['new', 'new', 'new', 'new', 'new']\n" + ] + } + ], + "source": [ + "print create_list(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how the size of the new_list object scales with the input **n**, this shows that it is an O(n) algorithm with regards to **space** complexity.\n", + "_____\n", + "\n", + "Thats it for this lecture, before continuing on, make sure to complete the homework assignment below:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Homework Assignment\n", + "\n", + "Your homework assignment after this lecture is to read the fantastic explanations of Big-O at these two sources:\n", + "\n", + "* [Big-O Notation Explained](http://stackoverflow.com/questions/487258/plain-english-explanation-of-big-o/487278#487278)\n", + "\n", + "* [Big-O Examples Explained](http://stackoverflow.com/questions/2307283/what-does-olog-n-mean-exactly)" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Algorithm Analysis and Big O/Big O Notation.ipynb b/Algorithm Analysis and Big O/Big O Notation.ipynb new file mode 100644 index 00000000..28cb4211 --- /dev/null +++ b/Algorithm Analysis and Big O/Big O Notation.ipynb @@ -0,0 +1,206 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Big O Notation\n", + "In this lecture we will go over how the syntax of Big-O Notation works and how we can describe algorithms using Big-O Notation!\n", + "\n", + "We previously discussed the functions below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# First function (Note the use of xrange since this is in Python 2)\n", + "def sum1(n):\n", + " '''\n", + " Take an input of n and return the sum of the numbers from 0 to n\n", + " '''\n", + " final_sum = 0\n", + " for x in xrange(n+1): \n", + " final_sum += x\n", + " \n", + " return final_sum" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def sum2(n):\n", + " \"\"\"\n", + " Take an input of n and return the sum of the numbers from 0 to n\n", + " \"\"\"\n", + " return (n*(n+1))/2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we want to develop a notation to objectively compare the efficiency of these two algorithms. A good place to start would be to compare the number of assignments each algorithm makes.\n", + "\n", + "The original **sum1** function will create an assignment **n+1** times, we can see this from the range based function. This means it will assign the final_sum variable n+1 times. We can then say that for a problem of n size (in this case just a number n) this function will take 1+n steps.\n", + "\n", + "This **n** notation allows us to compare solutions and algorithms relative to the size of the problem, since sum1(10) and sum1(100000) would take very different times to run but be using the same algorithm. We can also note that as n grows very large, the **+1** won't have much effect. So let's begin discussing how to build a syntax for this notation.\n", + "________\n", + "\n", + "Now we will discuss how we can formalize this notation and idea.\n", + "\n", + "Big-O notation describes *how quickly runtime will grow relative to the input as the input get arbitrarily large*.\n", + "\n", + "Let's examine some of these points more closely:\n", + "\n", + "* Remember, we want to compare how quickly runtime will grows, not compare exact runtimes, since those can vary depending on hardware.\n", + "\n", + "* Since we want to compare for a variety of input sizes, we are only concerned with runtime grow *relative* to the input. This is why we use **n** for notation.\n", + "\n", + "* As n gets arbitrarily large we only worry about terms that will grow the fastest as n gets large, to this point, Big-O analysis is also known as **asymptotic analysis**\n", + "\n", + "\n", + "As for syntax sum1() can be said to be **O(n)** since its runtime grows linearly with the input size. In the next lecture we will go over more specific examples of various O() types and examples. To conclude this lecture we will show the potential for vast difference in runtimes of Big-O functions.\n", + "\n", + "## Runtimes of Common Big-O Functions\n", + "\n", + "Here is a table of common Big-O functions:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + "\n", + "
Big-OName
1Constant
log(n)Logarithmic
nLinear
nlog(n)Log Linear
n^2Quadratic
n^3Cubic
2^nExponential
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's plot the runtime versus the Big-O to compare the runtimes. We'll use a simple [matplotlib](http://matplotlib.org/) for the plot below. (Don't be concerned with how to use matplotlib, that is irrelevant for this part)." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from math import log\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "plt.style.use('bmh')\n", + "\n", + "# Set up runtime comparisons\n", + "n = np.linspace(1,10,1000)\n", + "labels = ['Constant','Logarithmic','Linear','Log Linear','Quadratic','Cubic','Exponential']\n", + "big_o = [np.ones(n.shape),np.log(n),n,n*np.log(n),n**2,n**3,2**n]\n", + "\n", + "# Plot setup\n", + "plt.figure(figsize=(12,10))\n", + "plt.ylim(0,50)\n", + "\n", + "for i in range(len(big_o)):\n", + " plt.plot(n,big_o[i],label = labels[i])\n", + "\n", + "\n", + "plt.legend(loc=0)\n", + "plt.ylabel('Relative Runtime')\n", + "plt.xlabel('n')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how much of a difference a Big-O efficiency can make for the same n value against the projected runtime! Clearly we want to choose algorithms that stay away from any exponential, quadratic, or cubic behavior!\n", + "\n", + "In the next lecture we will learn how to properly denote Big-O and look at examples of various problems and calculate the Big-O of them!" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python [conda env:python3]", + "language": "python", + "name": "conda-env-python3-py" + }, + "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.1" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Algorithm Analysis and Big O/Big O for Python Data Structures.ipynb b/Algorithm Analysis and Big O/Big O for Python Data Structures.ipynb new file mode 100644 index 00000000..dd014176 --- /dev/null +++ b/Algorithm Analysis and Big O/Big O for Python Data Structures.ipynb @@ -0,0 +1,284 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Big O for Python Data Structures\n", + "In this lecture we will go over the Big O of built-in data structures in Python: Lists and Dictionaries." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Lists\n", + "\n", + "In Python lists act as dynamic arrays and support a number of common operations through methods called on them. The two most common operations performed on a list are indexing and assigning to an index position. These operations are both designed to be run in constant time, O(1).\n", + "\n", + "Let's imagine you wanted to test different methods to construct a list that is [0,1,2...10000]. Let go ahead and compare various methods, such as appending to the end of a list, concatenating a list, or using tools such as casting and list comprehension.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def method1():\n", + " l = []\n", + " for n in xrange(10000):\n", + " l = l + [n]\n", + "\n", + "def method2():\n", + " l = []\n", + " for n in xrange(10000):\n", + " l.append(n)\n", + "\n", + "def method3():\n", + " l = [n for n in xrange(10000)]\n", + "\n", + "def method4():\n", + " l = range(10000) # Python 3: list(range(10000))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's now test these methods using the timeit magic function:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10 loops, best of 3: 162 ms per loop\n", + "1000 loops, best of 3: 820 µs per loop\n", + "1000 loops, best of 3: 307 µs per loop\n", + "10000 loops, best of 3: 77.7 µs per loop\n" + ] + } + ], + "source": [ + "%timeit method1()\n", + "%timeit method2()\n", + "%timeit method3()\n", + "%timeit method4()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can clearly see that the most effective method is the built-in range() function in Python!\n", + "\n", + "It is important to keep these factors in mind when writing efficient code. More importantly begin thinking about how we are able to index with O(1). We will discuss this in more detail when we cover arrays general. For now, take a look at the table below for an overview of Big-O efficiencies." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Table of Big-O for common list operations\n", + "\n", + "** Please note, in order to see this table, you may need to download this .ipynb file and view it locally, sometimes GitHub or nbveiwer have trouble showing the HTML for it... **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "
Operation Big-O Efficiency
index []O(1)
index assignmentO(1)
appendO(1)
pop()O(1)
pop(i)O(n)
insert(i,item)O(n)
del operatorO(n)
iterationO(n)
contains (in)O(n)
get slice [x:y]O(k)
del sliceO(n)
set sliceO(n+k)
reverseO(n)
concatenateO(k)
sortO(n log n)
multiplyO(nk)
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Dictionaries\n", + "\n", + "Dictionaries in Python are an implementation of a hash table. They operate with keys and values, for example:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "d = {'k1':1,'k2':2}" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d['k1']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Something that is pretty amazing is that getting and setting items in a dictionary are O(1)! Hash tables are designed with efficiency in mind, and we will explore them in much more detail later on in the course as one of the most important data structures to undestand. In the meantime, refer to the table below for Big-O efficiencies of common dictionary operations:\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
OperationBig-O Efficiency
copyO(n)
get itemO(1)
set itemO(1)
delete itemO(1)
contains (in)O(1)
iterationO(n)
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "By the end of this section you should have an understanding of how Big-O is used in Algorithm analysis and be able to work out the Big-O of an algorithm you've developed. Get ready, there's a quiz up next!" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Algorithm Analysis and Big O/Introduction to Algorithm Analysis and Big O .ipynb b/Algorithm Analysis and Big O/Introduction to Algorithm Analysis and Big O .ipynb new file mode 100644 index 00000000..0238db22 --- /dev/null +++ b/Algorithm Analysis and Big O/Introduction to Algorithm Analysis and Big O .ipynb @@ -0,0 +1,194 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Introduction to Algorithm Analysis and Big O\n", + "\n", + "In this lecture we will discuss how to analyze Algorithms and why it is important to do so!\n", + "\n", + "## Why analyze algorithms?\n", + "\n", + "Before we begin, let's clarify what an algorthim is. In this course, an **algorithm** is simply a procedure or formula for solving a problem. Some problems are famous enough that the algorithms have names, as well as some procdures being common enough that the algorithm associated with it also has a name. So now we have a good question we need to answer:\n", + "\n", + "** *How do analyze algorithms and how can we compare algorithms against each other?* **\n", + "\n", + "Imagine if you and a friend both came up with functions to sum the numbers from 0 to N. How would you compare the functions and algorithms within the functions? Let's say you both cam up with these two seperate functions:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# First function (Note the use of xrange since this is in Python 2)\n", + "def sum1(n):\n", + " '''\n", + " Take an input of n and return the sum of the numbers from 0 to n\n", + " '''\n", + " final_sum = 0\n", + " for x in xrange(n+1): \n", + " final_sum += x\n", + " \n", + " return final_sum" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum1(10)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def sum2(n):\n", + " \"\"\"\n", + " Take an input of n and return the sum of the numbers from 0 to n\n", + " \"\"\"\n", + " return (n*(n+1))/2" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum2(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You'll notice both functions have the same result, but completely different algorithms. You'll note that the first function iteratively adds the numbers, while the second function makes use of:\n", + "$$ \\sum_{i=0}^{n} {i} = \\frac{n(n+1)}{2} $$\n", + "\n", + "So how can we objectively compare the algorithms? We could compare the amount of space they take in memory or we could also compare how much time it takes each function to run. We can use the built in **%timeit** magic function in jupyter to compare the time of the functions. The [**%timeit**](https://ipython.org/ipython-doc/3/interactive/magics.html#magic-timeit) magic in Jupyter Notebooks will repeat the loop iteration a certain number of times and take the best result. Check out the link for the documentation. \n", + "\n", + "Let's go ahead and compare the time it took to run the functions:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The slowest run took 5.15 times longer than the fastest. This could mean that an intermediate result is being cached \n", + "100000 loops, best of 3: 4.86 µs per loop\n" + ] + } + ], + "source": [ + "%timeit sum1(100)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The slowest run took 16.54 times longer than the fastest. This could mean that an intermediate result is being cached \n", + "10000000 loops, best of 3: 173 ns per loop\n" + ] + } + ], + "source": [ + "%timeit sum2(100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the second function is much more efficient! Running at a much faster rate than the first. However, we can not use \"time to run\" as an objective measurement, because that will depend on the speed of the computer itself and hardware capabilities. So we will need to use another method, **Big-O**!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "In the next lecture we will discuss Big-O notation and why its so important!" + ] + } + ], + "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 +} diff --git a/Array Sequences/.ipynb_checkpoints/Amortization-checkpoint.ipynb b/Array Sequences/.ipynb_checkpoints/Amortization-checkpoint.ipynb new file mode 100644 index 00000000..d58ff51c --- /dev/null +++ b/Array Sequences/.ipynb_checkpoints/Amortization-checkpoint.ipynb @@ -0,0 +1,44 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Amortization" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "___\n", + "## Please refer to the video lecture for the remaining information.\n", + "## The section consists mostly of video explanations not well-suited for Jupyter Notebooks.\n", + "# Thanks!" + ] + } + ], + "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 +} diff --git a/Array Sequences/.ipynb_checkpoints/Array Mini-Project-checkpoint.ipynb b/Array Sequences/.ipynb_checkpoints/Array Mini-Project-checkpoint.ipynb new file mode 100644 index 00000000..1a4dc652 --- /dev/null +++ b/Array Sequences/.ipynb_checkpoints/Array Mini-Project-checkpoint.ipynb @@ -0,0 +1,45 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Array Mini-Project\n", + "\n", + "In this mini project we will create our own scoreboard project to understand arrays better!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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 +} diff --git a/Array Sequences/.ipynb_checkpoints/Dynamic Array Exercise-checkpoint.ipynb b/Array Sequences/.ipynb_checkpoints/Dynamic Array Exercise-checkpoint.ipynb new file mode 100644 index 00000000..732a6e15 --- /dev/null +++ b/Array Sequences/.ipynb_checkpoints/Dynamic Array Exercise-checkpoint.ipynb @@ -0,0 +1,329 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Dynamic Array Exercise\n", + "____\n", + "\n", + "In this exercise we will create our own Dynamic Array class!\n", + "\n", + "We'll be using a built in library called [ctypes](https://docs.python.org/2/library/ctypes.html). Check out the documentation for more info, but its basically going to be used here as a raw array from the ctypes module.\n", + "If you find yourself very interested in it, check out: [Ctypes Tutorial](http://starship.python.net/crew/theller/ctypes/tutorial.html)\n", + "\n", + "Also..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**A quick note on public vs private methods, we can use an underscore _ before the method name to keep it non-public. For example:**" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class M(object):\n", + " \n", + " def public(self):\n", + " print 'Use Tab to see me!'\n", + " \n", + " def _private(self):\n", + " print \"You won't be able to Tab to see me!\"" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m = M()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Use Tab to see me!\n" + ] + } + ], + "source": [ + "m.public()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You won't be able to see me!\n" + ] + } + ], + "source": [ + "m._private()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check out PEP 8 and the Python docs for more info on this!\n", + "_____\n", + "\n", + "### Dynamic Array Implementation" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import ctypes\n", + "\n", + "class DynamicArray(object):\n", + " '''\n", + " DYNAMIC ARRAY CLASS (Similar to Python List)\n", + " '''\n", + " \n", + " def __init__(self):\n", + " self.n = 0 # Count actual elements (Default is 0)\n", + " self.capacity = 1 # Default Capacity\n", + " self.A = self.make_array(self.capacity)\n", + " \n", + " def __len__(self):\n", + " \"\"\"\n", + " Return number of elements sorted in array\n", + " \"\"\"\n", + " return self.n\n", + " \n", + " def __getitem__(self,k):\n", + " \"\"\"\n", + " Return element at index k\n", + " \"\"\"\n", + " if not 0 <= k \u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mlarge_cont_sum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mlarge_cont_sum\u001b[0;34m(arr)\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0marr\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0msum\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmax\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 9\u001b[0m \u001b[0mmax\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmax\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmax\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mmax\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: 'int' object is not callable" + ] + } + ], + "source": [ + "large_cont_sum([1,2,-1,3,4,10,10,-10,-1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "Many times in an interview setting the question also requires you to report back the start and end points of the sum. Keep this in mind and see if you can solve that problem, we'll see it in the mock interview section of the course!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "from nose.tools import assert_equal\n", + "\n", + "class LargeContTest(object):\n", + " def test(self,sol):\n", + " assert_equal(sol([1,2,-1,3,4,-1]),9)\n", + " assert_equal(sol([1,2,-1,3,4,10,10,-10,-1]),29)\n", + " assert_equal(sol([-1,1]),1)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "#Run Test\n", + "t = LargeContTest()\n", + "t.test(large_cont_sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Sentence Reversal-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Sentence Reversal-checkpoint.ipynb new file mode 100644 index 00000000..f1ce5f7a --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Sentence Reversal-checkpoint.ipynb @@ -0,0 +1,220 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sentence Reversal\n", + "\n", + "## Problem\n", + "\n", + "Given a string of words, reverse all the words. For example:\n", + "\n", + "Given:\n", + " \n", + " 'This is the best'\n", + "\n", + "Return:\n", + "\n", + " 'best the is This'\n", + "\n", + "As part of this exercise you should remove all leading and trailing whitespace. So that inputs such as:\n", + "\n", + " ' space here' and 'space here '\n", + "\n", + "both become:\n", + "\n", + " 'here space'\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "def rev_word(s):\n", + " return \" \".join(reversed(s.split()))\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'go? to ready you are John, Hi'" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word('Hi John, are you ready to go?')" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'before space'" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word(' space before')" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'after space'" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word('space after ')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Learn\n", + "- \" \".join()\n", + "- reversed()\n", + "- s.split()" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'\\nInit signature: reversed(self, /, *args, **kwargs)\\nDocstring: \\nreversed(sequence) -> reverse iterator over values of the sequence\\n\\nReturn a reverse iterator\\nType: type\\n'" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# reversed()\n", + "'''\n", + "Init signature: reversed(self, /, *args, **kwargs)\n", + "Docstring: \n", + "reversed(sequence) -> reverse iterator over values of the sequence\n", + "\n", + "Return a reverse iterator\n", + "Type: type\n", + "'''" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class ReversalTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(' space before'),'before space')\n", + " assert_equal(sol('space after '),'after space')\n", + " assert_equal(sol(' Hello John how are you '),'you are how John Hello')\n", + " assert_equal(sol('1'),'1')\n", + " print (\"ALL TEST CASES PASSED\")\n", + " \n", + "# Run and test\n", + "t = ReversalTest()\n", + "t.test(rev_word)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/String Compression -checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/String Compression -checkpoint.ipynb new file mode 100644 index 00000000..e8c7d5f4 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/String Compression -checkpoint.ipynb @@ -0,0 +1,128 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# String Compression\n", + "\n", + "## Problem\n", + "\n", + "Given a string in the form 'AAAABBBBCCCCCDDEEEE' compress it to become 'A4B4C5D2E4'. For this problem, you can falsely \"compress\" strings of single or double letters. For instance, it is okay for 'AAB' to return 'A2B1' even though this technically takes more space. \n", + "\n", + "The function should also be case sensitive, so that a string 'AAAaaa' returns 'A3a3'." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def compress(s):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'A5B4C4'" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "compress('AAAAABBBBCCCC')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCompress(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), '')\n", + " assert_equal(sol('AABBCC'), 'A2B2C2')\n", + " assert_equal(sol('AAABCCDDDDD'), 'A3B1C2D5')\n", + " print 'ALL TEST CASES PASSED'\n", + "\n", + "# Run Tests\n", + "t = TestCompress()\n", + "t.test(compress)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Unique Characters in String-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Unique Characters in String-checkpoint.ipynb new file mode 100644 index 00000000..e844d767 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/.ipynb_checkpoints/Unique Characters in String-checkpoint.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Unique Characters in String\n", + "\n", + "## Problem\n", + "Given a string,determine if it is compreised of all unique characters. For example, the string 'abcde' has all unique characters and should return True. The string 'aabcde' contains duplicate characters and should return false." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "def uni_char(s):\n", + " u = set()\n", + " for c in s:\n", + " if c in u:\n", + " return False\n", + " else:\n", + " u.add(c)\n", + " return True\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Learn This One Line Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "# another 1-line solution\n", + "def uni_char2(s):\n", + " return len(set(s)) == len(s)\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR CODE>\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestUnique(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), True)\n", + " assert_equal(sol('goo'), False)\n", + " assert_equal(sol('abcdefg'), True)\n", + " print ('ALL TEST CASES PASSED')\n", + " \n", + "# Run Tests\n", + "t = TestUnique()\n", + "t.test(uni_char)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Anagram Check .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Anagram Check .ipynb new file mode 100644 index 00000000..eac9c379 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Anagram Check .ipynb @@ -0,0 +1,213 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Anagram Check\n", + "\n", + "## Problem\n", + "\n", + "Given two strings, check to see if they are anagrams. An anagram is when the two strings can be written using the exact same letters (so you can just rearrange the letters to get a different phrase or word). \n", + "\n", + "For example:\n", + "\n", + " \"public relations\" is an anagram of \"crap built on lies.\"\n", + " \n", + " \"clint eastwood\" is an anagram of \"old west action\"\n", + " \n", + "**Note: Ignore spaces and capitalization. So \"d go\" is an anagram of \"God\" and \"dog\" and \"o d g\".**\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "# 242. Valid Anagram(https://leetcode.com/problems/valid-anagram/description/)\n", + "def anagram(s, t):\n", + " \"\"\"\n", + " :type s: str\n", + " :type t: str\n", + " :rtype: bool\n", + " \"\"\"\n", + " s=s.replace(' ','').lower()\n", + " t=t.replace(' ','').lower()\n", + " \n", + " if(len(s)!=len(t)):\n", + " return False\n", + " counter = {}\n", + " for letter in s:\n", + " if letter in counter:\n", + " counter[letter] += 1\n", + " else:\n", + " counter[letter] = 1\n", + "\n", + " for letter in t:\n", + " if letter in counter:\n", + " counter[letter] -= 1\n", + " else:\n", + " return False\n", + "\n", + " for k in counter:\n", + " if counter[k]!=0:\n", + " return False\n", + " \n", + " return True\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('dog','god')" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('clint eastwood','old west action')" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('aa','bb')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "Run the cell below to test your solution" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class AnagramTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('go go go','gggooo'),True)\n", + " assert_equal(sol('abc','cba'),True)\n", + " assert_equal(sol('hi man','hi man'),True)\n", + " assert_equal(sol('aabbcc','aabbc'),False)\n", + " assert_equal(sol('123','1 2'),False)\n", + " print('ALL TEST CASES PASSED')\n", + "\n", + "# Run Tests\n", + "t = AnagramTest()\n", + "t.test(anagram)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "t.test(anagram2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Array Pair Sum .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Array Pair Sum .ipynb new file mode 100644 index 00000000..36525741 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Array Pair Sum .ipynb @@ -0,0 +1,136 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Array Pair Sum\n", + "\n", + "## Problem\n", + "\n", + "Given an integer array, output all the ** *unique* ** pairs that sum up to a specific value **k**.\n", + "\n", + "So the input:\n", + " \n", + " pair_sum([1,3,2,2],4)\n", + "\n", + "would return **2** pairs:\n", + "\n", + " (1,3)\n", + " (2,2)\n", + "\n", + "**NOTE: FOR TESTING PURPOSES CHANGE YOUR FUNCTION SO IT OUTPUTS THE NUMBER OF PAIRS**\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def pair_sum(arr,k):\n", + " counter = 0\n", + " lookup = set()\n", + " for num in arr:\n", + " if k-num in lookup:\n", + " counter+=1\n", + " else:\n", + " lookup.add(num)\n", + " return counter\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pair_sum([1,3,2,2],4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPair(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([1,9,2,8,3,7,4,6,5,5,13,14,11,13,-1],10),6)\n", + " assert_equal(sol([1,2,3,1],3),1)\n", + " assert_equal(sol([1,3,2,2],4),2)\n", + " print('ALL TEST CASES PASSED')\n", + " \n", + "#Run tests\n", + "t = TestPair()\n", + "t.test(pair_sum)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Find the Missing Element .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Find the Missing Element .ipynb new file mode 100644 index 00000000..78327449 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Find the Missing Element .ipynb @@ -0,0 +1,181 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Find the Missing Element\n", + "\n", + "## Problem\n", + "\n", + "Consider an array of non-negative integers. A second array is formed by shuffling the elements of the first array and deleting a random element. Given these two arrays, find which element is missing in the second array. \n", + "\n", + "Here is an example input, the first array is shuffled and the number 5 is removed to construct the second array.\n", + "\n", + "Input:\n", + " \n", + " finder([1,2,3,4,5,6,7],[3,7,2,1,4,6])\n", + "\n", + "Output:\n", + "\n", + " 5 is the missing number\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def finder(arr1,arr2):\n", + " num = 0\n", + " for n in arr1:\n", + " num += n\n", + " for n in arr2:\n", + " num -= n\n", + " return num\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "28\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [1,2,3,4,5,6,7]\n", + "arr2 = [3,7,2,1,4,6]\n", + "finder(arr1,arr2)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "24\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [5,5,7,7]\n", + "arr2 = [5,7,7]\n", + "\n", + "finder(arr1,arr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "24\n", + "28\n", + "45\n", + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFinder(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([5,5,7,7],[5,7,7]),5)\n", + " assert_equal(sol([1,2,3,4,5,6,7],[3,7,2,1,4,6]),5)\n", + " assert_equal(sol([9,8,7,6,5,4,3,2,1],[9,8,7,5,4,3,2,1]),6)\n", + " print('ALL TEST CASES PASSED')\n", + "\n", + "# Run test\n", + "t = TestFinder()\n", + "t.test(finder)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Largest Continuous Sum .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Largest Continuous Sum .ipynb new file mode 100644 index 00000000..be1f654d --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Largest Continuous Sum .ipynb @@ -0,0 +1,128 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Largest Continuous Sum\n", + "\n", + "## Problem\n", + "Given an array of integers (positive and negative) find the largest continuous sum. \n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "def large_cont_sum(arr):\n", + " if len(arr) == 0:\n", + " return 0\n", + " \n", + " max_num = sum = arr[0]# max=sum=arr[0] bug: TypeError: 'int' object is not callable. (Do not use the keyword!)\n", + " \n", + " for n in arr[1:]:\n", + " sum = max(sum+n, n)\n", + " max_num = max(sum, max_num)\n", + " return max_num\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "29" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "large_cont_sum([1,2,-1,3,4,10,10,-10,-1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "Many times in an interview setting the question also requires you to report back the start and end points of the sum. Keep this in mind and see if you can solve that problem, we'll see it in the mock interview section of the course!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "from nose.tools import assert_equal\n", + "\n", + "class LargeContTest(object):\n", + " def test(self,sol):\n", + " assert_equal(sol([1,2,-1,3,4,-1]),9)\n", + " assert_equal(sol([1,2,-1,3,4,10,10,-10,-1]),29)\n", + " assert_equal(sol([-1,1]),1)\n", + " print ('ALL TEST CASES PASSED')\n", + " \n", + "#Run Test\n", + "t = LargeContTest()\n", + "t.test(large_cont_sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Sentence Reversal.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Sentence Reversal.ipynb new file mode 100644 index 00000000..f1ce5f7a --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/Sentence Reversal.ipynb @@ -0,0 +1,220 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sentence Reversal\n", + "\n", + "## Problem\n", + "\n", + "Given a string of words, reverse all the words. For example:\n", + "\n", + "Given:\n", + " \n", + " 'This is the best'\n", + "\n", + "Return:\n", + "\n", + " 'best the is This'\n", + "\n", + "As part of this exercise you should remove all leading and trailing whitespace. So that inputs such as:\n", + "\n", + " ' space here' and 'space here '\n", + "\n", + "both become:\n", + "\n", + " 'here space'\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "def rev_word(s):\n", + " return \" \".join(reversed(s.split()))\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'go? to ready you are John, Hi'" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word('Hi John, are you ready to go?')" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'before space'" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word(' space before')" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'after space'" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word('space after ')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Learn\n", + "- \" \".join()\n", + "- reversed()\n", + "- s.split()" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'\\nInit signature: reversed(self, /, *args, **kwargs)\\nDocstring: \\nreversed(sequence) -> reverse iterator over values of the sequence\\n\\nReturn a reverse iterator\\nType: type\\n'" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# reversed()\n", + "'''\n", + "Init signature: reversed(self, /, *args, **kwargs)\n", + "Docstring: \n", + "reversed(sequence) -> reverse iterator over values of the sequence\n", + "\n", + "Return a reverse iterator\n", + "Type: type\n", + "'''" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class ReversalTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(' space before'),'before space')\n", + " assert_equal(sol('space after '),'after space')\n", + " assert_equal(sol(' Hello John how are you '),'you are how John Hello')\n", + " assert_equal(sol('1'),'1')\n", + " print (\"ALL TEST CASES PASSED\")\n", + " \n", + "# Run and test\n", + "t = ReversalTest()\n", + "t.test(rev_word)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/String Compression .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/String Compression .ipynb new file mode 100644 index 00000000..00ca41f5 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - PRACTICE/String Compression .ipynb @@ -0,0 +1,143 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# String Compression\n", + "\n", + "## Problem\n", + "\n", + "Given a string in the form 'AAAABBBBCCCCCDDEEEE' compress it to become 'A4B4C5D2E4'. For this problem, you can falsely \"compress\" strings of single or double letters. For instance, it is okay for 'AAB' to return 'A2B1' even though this technically takes more space. \n", + "\n", + "The function should also be case sensitive, so that a string 'AAAaaa' returns 'A3a3'." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "def compress(s):\n", + " r = \"\"\n", + " l = len(s)\n", + " \n", + " if l==0:\n", + " return ''\n", + " if l==1:\n", + " return s+'1'\n", + " \n", + " last = s[0]\n", + " cnt = 1\n", + " i=1\n", + " \n", + " while i\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestUnique(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), True)\n", + " assert_equal(sol('goo'), False)\n", + " assert_equal(sol('abcdefg'), True)\n", + " print ('ALL TEST CASES PASSED')\n", + " \n", + "# Run Tests\n", + "t = TestUnique()\n", + "t.test(uni_char)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Anagram Check - SOLUTION-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Anagram Check - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..bff6a2f4 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Anagram Check - SOLUTION-checkpoint.ipynb @@ -0,0 +1,330 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Anagram Solution\n", + "\n", + "## Problem\n", + "\n", + "Given two strings, check to see if they are anagrams. An anagram is when the two strings can be written using the exact same letters (so you can just rearrange the letters to get a different phrase or word). \n", + "\n", + "For example:\n", + "\n", + " \"public relations\" is an anagram of \"crap built on lies.\"\n", + " \n", + " \"clint eastwood\" is an anagram of \"old west action\"\n", + " \n", + "**Note: Ignore spaces and capitalization. So \"d go\" is an anagram of \"God\" and \"dog\" and \"o d g\".**\n", + "\n", + "## Solution\n", + "\n", + "There are two ways of thinking about this problem, if two strings have the same frequency of letters/element (meaning each letter shows up the same number of times in both strings) then they are anagrams of eachother. On a similar vien of logic, if two strings are equal to each other once they are sorted, then they are also anagrams of each other.\n", + "\n", + "You would be able to implement this second solution pretty easily in Python:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def anagram(s1,s2):\n", + " \n", + " # Remove spaces and lowercase letters\n", + " s1 = s1.replace(' ','').lower()\n", + " s2 = s2.replace(' ','').lower()\n", + " \n", + " # Return boolean for sorted match.\n", + " return sorted(s1) == sorted(s2)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('dog','god')" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('clint eastwood','old west action')" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('aa','bb')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now the above sorting approach is simple, but is actually not optimal and in an interview setting you would probably be asked to implement a more manual solution involving just counting the number of letters in each string to test your ability to understand hash tables. Let's build out a fuller solution using counting and Python dictionaries:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def anagram2(s1,s2):\n", + " \n", + " # Remove spaces and lowercase letters\n", + " s1 = s1.replace(' ','').lower()\n", + " s2 = s2.replace(' ','').lower()\n", + " \n", + " # Edge Case to check if same number of letters\n", + " if len(s1) != len(s2):\n", + " return False\n", + " \n", + " # Create counting dictionary (Note could use DefaultDict from Collections module)\n", + " count = {}\n", + " \n", + " \n", + " \n", + " # Fill dictionary for first string (add counts)\n", + " for letter in s1:\n", + " if letter in count:\n", + " count[letter] += 1\n", + " else:\n", + " count[letter] = 1\n", + " \n", + " # Fill dictionary for second string (subtract counts)\n", + " for letter in s2:\n", + " if letter in count:\n", + " count[letter] -= 1\n", + " else:\n", + " count[letter] = 1\n", + " \n", + " # Check that all counts are 0\n", + " for k in count:\n", + " if count[k] != 0:\n", + " return False\n", + "\n", + " # Otherwise they're anagrams\n", + " return True" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram2('dog','god')" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram2('clint eastwood','old west action')" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram2('dd','aa')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A quick note on the second solution, the use of defaultdict form the collections module would clean up this code quite a bit, and the final for loop could be built into the second for loop, but in the above implementation every step is very clear." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "Run the cell below to test your solution" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class AnagramTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('go go go','gggooo'),True)\n", + " assert_equal(sol('abc','cba'),True)\n", + " assert_equal(sol('hi man','hi man'),True)\n", + " assert_equal(sol('aabbcc','aabbc'),False)\n", + " assert_equal(sol('123','1 2'),False)\n", + " print \"ALL TEST CASES PASSED\"\n", + "\n", + "# Run Tests\n", + "t = AnagramTest()\n", + "t.test(anagram)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "t.test(anagram2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Array Pair Sum - SOLUTION-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Array Pair Sum - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..2419f818 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Array Pair Sum - SOLUTION-checkpoint.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Array Pair Sum\n", + "\n", + "## Problem\n", + "\n", + "Given an integer array, output all the ** *unique* ** pairs that sum up to a specific value **k**.\n", + "\n", + "So the input:\n", + " \n", + " pair_sum([1,3,2,2],4)\n", + "\n", + "would return **2** pairs:\n", + "\n", + " (1,3)\n", + " (2,2)\n", + "\n", + "**NOTE: FOR TESTING PURPOSES< CHANGE YOUR FUNCTION SO IT OUTPUTS THE NUMBER OF PAIRS**\n", + "\n", + "## Solution\n", + "\n", + "The O(N) algorithm uses the set data structure. We perform a linear pass from the beginning and for each element we check whether k-element is in the set of seen numbers. If it is, then we found a pair of sum k and add it to the output. If not, this element doesn’t belong to a pair yet, and we add it to the set of seen elements. \n", + "\n", + "The algorithm is really simple once we figure out using a set. The complexity is O(N) because we do a single linear scan of the array, and for each element we just check whether the corresponding number to form a pair is in the set or add the current element to the set. Insert and find operations of a set are both average O(1), so the algorithm is O(N) in total. " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def pair_sum(arr,k):\n", + " \n", + " if len(arr)<2:\n", + " return\n", + " \n", + " # Sets for tracking\n", + " seen = set()\n", + " output = set()\n", + " \n", + " # For every number in array\n", + " for num in arr:\n", + " \n", + " # Set target difference\n", + " target = k-num\n", + " \n", + " # Add it to set if target hasn't been seen\n", + " if target not in seen:\n", + " seen.add(num)\n", + " \n", + " else:\n", + " # Add a tuple with the corresponding pair\n", + " output.add( (min(num,target), max(num,target)) )\n", + " \n", + " \n", + " # FOR TESTING\n", + " return len(output)\n", + " # Nice one-liner for printing output\n", + " #return '\\n'.join(map(str,list(output)))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pair_sum([1,3,2,2],4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPair(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([1,9,2,8,3,7,4,6,5,5,13,14,11,13,-1],10),6)\n", + " assert_equal(sol([1,2,3,1],3),1)\n", + " assert_equal(sol([1,3,2,2],4),2)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "#Run tests\n", + "t = TestPair()\n", + "t.test(pair_sum)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Find the Missing Element - SOLUTION-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Find the Missing Element - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..0b216746 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Find the Missing Element - SOLUTION-checkpoint.ipynb @@ -0,0 +1,272 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Find the Missing Element\n", + "\n", + "## Problem\n", + "\n", + "Consider an array of non-negative integers. A second array is formed by shuffling the elements of the first array and deleting a random element. Given these two arrays, find which element is missing in the second array. \n", + "\n", + "Here is an example input, the first array is shuffled and the number 5 is removed to construct the second array.\n", + "\n", + "Input:\n", + " \n", + " finder([1,2,3,4,5,6,7],[3,7,2,1,4,6])\n", + "\n", + "Output:\n", + "\n", + " 5 is the missing number\n", + "\n", + "## Solution\n", + "\n", + "The naive solution is go through every element in the second array and check whether it appears in the first array. Note that there may be duplicate elements in the arrays so we should pay special attention to it. The complexity of this approach is O(N^2), since we would need two for loops.\n", + "\n", + "A more efficient solution is to sort the first array, so while checking whether an element in the first array appears in the second, we can do binary search (we'll learn about binary search in more detail in a future section). But we should still be careful about duplicate elements. The complexity is O(NlogN). \n", + "\n", + "If we don’t want to deal with the special case of duplicate numbers, we can sort both arrays and iterate over them simultaneously. Once two iterators have different values we can stop. The value of the first iterator is the missing element. This solution is also O(NlogN). Here is the solution for this approach:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def finder(arr1,arr2):\n", + " \n", + " # Sort the arrays\n", + " arr1.sort()\n", + " arr2.sort()\n", + " \n", + " # Compare elements in the sorted arrays\n", + " for num1, num2 in zip(arr1,arr2):\n", + " if num1!= num2:\n", + " return num1\n", + " \n", + " # Otherwise return last element\n", + " return arr1[-1]" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [1,2,3,4,5,6,7]\n", + "arr2 = [3,7,2,1,4,6]\n", + "finder(arr1,arr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In most interviews, you would be expected to come up with a linear time solution. We can use a hashtable and store the number of times each element appears in the second array. Then for each element in the first array we decrement its counter. Once hit an element with zero count that’s the missing element. Here is this solution: " + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import collections\n", + "\n", + "def finder2(arr1, arr2): \n", + " \n", + " # Using default dict to avoid key errors\n", + " d=collections.defaultdict(int) \n", + " \n", + " # Add a count for every instance in Array 1\n", + " for num in arr2:\n", + " d[num]+=1 \n", + " \n", + " # Check if num not in dictionary\n", + " for num in arr1: \n", + " if d[num]==0: \n", + " return num \n", + " \n", + " # Otherwise, subtract a count\n", + " else: d[num]-=1 " + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [5,5,7,7]\n", + "arr2 = [5,7,7]\n", + "\n", + "finder2(arr1,arr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One possible solution is computing the sum of all the numbers in arr1 and arr2, and subtracting arr2’s sum from array1’s sum. The difference is the missing number in arr2. However, this approach could be problematic if the arrays are too long, or the numbers are very large. Then overflow will occur while summing up the numbers.\n", + "\n", + "By performing a very clever trick, we can achieve linear time and constant space complexity without any problems. Here it is: initialize a variable to 0, then [XOR](https://en.wikipedia.org/wiki/Exclusive_or) every element in the first and second arrays with that variable. In the end, the value of the variable is the result, missing element in array2." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def finder3(arr1, arr2): \n", + " result=0 \n", + " \n", + " # Perform an XOR between the numbers in the arrays\n", + " for num in arr1+arr2: \n", + " result^=num \n", + " print result\n", + " \n", + " return result " + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n", + "0\n", + "7\n", + "0\n", + "5\n", + "2\n", + "5\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "finder3(arr1,arr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFinder(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([5,5,7,7],[5,7,7]),5)\n", + " assert_equal(sol([1,2,3,4,5,6,7],[3,7,2,1,4,6]),5)\n", + " assert_equal(sol([9,8,7,6,5,4,3,2,1],[9,8,7,5,4,3,2,1]),6)\n", + " print 'ALL TEST CASES PASSED'\n", + "\n", + "# Run test\n", + "t = TestFinder()\n", + "t.test(finder)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Largest Continuous Sum - SOLUTION-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Largest Continuous Sum - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..153410ab --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Largest Continuous Sum - SOLUTION-checkpoint.ipynb @@ -0,0 +1,146 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Largest Continuous Sum\n", + "\n", + "## Problem\n", + "Given an array of integers (positive and negative) find the largest continuous sum. \n", + "\n", + "## Solution\n", + "\n", + "If the array is all positive, then the result is simply the sum of all numbers. The negative numbers in the array will cause us to need to begin checking sequences. \n", + "\n", + "The algorithm is, we start summing up the numbers and store in a current sum variable. After adding each element, we check whether the current sum is larger than maximum sum encountered so far. If it is, we update the maximum sum. As long as the current sum is positive, we keep adding the numbers. When the current sum becomes negative, we start with a new current sum. Because a negative current sum will only decrease the sum of a future sequence. Note that we don’t reset the current sum to 0 because the array can contain all negative integers. Then the result would be the largest negative number. \n", + "\n", + "Let's see the code:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def large_cont_sum(arr): \n", + " \n", + " # Check to see if array is length 0\n", + " if len(arr)==0: \n", + " return 0\n", + " \n", + " # Start the max and current sum at the first element\n", + " max_sum=current_sum=arr[0] \n", + " \n", + " # For every element in array\n", + " for num in arr[1:]: \n", + " \n", + " # Set current sum as the higher of the two\n", + " current_sum=max(current_sum+num, num)\n", + " \n", + " # Set max as the higher between the currentSum and the current max\n", + " max_sum=max(current_sum, max_sum) \n", + " \n", + " return max_sum " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "29" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "large_cont_sum([1,2,-1,3,4,10,10,-10,-1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "Many times in an interview setting the question also requires you to report back the start and end points of the sum. Keep this in mind and see if you can solve that problem, we'll see it in the mock interview section of the course!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "from nose.tools import assert_equal\n", + "\n", + "class LargeContTest(object):\n", + " def test(self,sol):\n", + " assert_equal(sol([1,2,-1,3,4,-1]),9)\n", + " assert_equal(sol([1,2,-1,3,4,10,10,-10,-1]),29)\n", + " assert_equal(sol([-1,1]),1)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "#Run Test\n", + "t = LargeContTest()\n", + "t.test(large_cont_sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Sentence Reversal - SOLUTION-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Sentence Reversal - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..6a78183c --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Sentence Reversal - SOLUTION-checkpoint.ipynb @@ -0,0 +1,267 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sentence Reversal\n", + "\n", + "## Problem\n", + "\n", + "Given a string of words, reverse all the words. For example:\n", + "\n", + "Given:\n", + " \n", + " 'This is the best'\n", + "\n", + "Return:\n", + "\n", + " 'best the is This'\n", + "\n", + "As part of this exercise you should remove all leading and trailing whitespace. So that inputs such as:\n", + "\n", + " ' space here' and 'space here '\n", + "\n", + "both become:\n", + "\n", + " 'here space'\n", + "\n", + "## Solution\n", + "\n", + "We could take advantage of Python's abilities and solve the problem with the use of **split()** and some slicing or use of **reversed**:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rev_word1(s):\n", + " return \" \".join(reversed(s.split()))\n", + "\n", + "#Or\n", + "\n", + "def rev_word2(s):\n", + " return \" \".join(s.split()[::-1])" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'go? to ready you are John, Hi'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word1('Hi John, are you ready to go?')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'go? to ready you are John, Hi'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word2('Hi John, are you ready to go?')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While these are valid solutions, in an interview setting you'll have to work out the basic algorithm that is used. In this case what we want to do is loop over the text and extract words form the string ourselves. Then we can push the words to a \"stack\" and in the end opo them all to reverse. Let's see what this actually looks like:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rev_word3(s):\n", + " \"\"\"\n", + " Manually doing the splits on the spaces.\n", + " \"\"\"\n", + " \n", + " words = []\n", + " length = len(s)\n", + " spaces = [' ']\n", + " \n", + " # Index Tracker\n", + " i = 0\n", + " \n", + " # While index is less than length of string\n", + " while i < length:\n", + " \n", + " # If element isn't a space\n", + " if s[i] not in spaces:\n", + " \n", + " # The word starts at this index\n", + " word_start = i\n", + " \n", + " while i < length and s[i] not in spaces:\n", + " \n", + " # Get index where word ends\n", + " i += 1\n", + " # Append that word to the list\n", + " words.append(s[word_start:i])\n", + " # Add to index\n", + " i += 1\n", + " \n", + " # Join the reversed words\n", + " return \" \".join(reversed(words))" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'you are how John Hello'" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word3(' Hello John how are you ')" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'before space'" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word3(' space before')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you want you can further develop this solution so its all manual, you can create your own reversal function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class ReversalTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(' space before'),'before space')\n", + " assert_equal(sol('space after '),'after space')\n", + " assert_equal(sol(' Hello John how are you '),'you are how John Hello')\n", + " assert_equal(sol('1'),'1')\n", + " print \"ALL TEST CASES PASSED\"\n", + " \n", + "# Run and test\n", + "t = ReversalTest()\n", + "t.test(rev_word)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/String Compression -SOLUTION-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/String Compression -SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..629aafd8 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/String Compression -SOLUTION-checkpoint.ipynb @@ -0,0 +1,168 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# String Compression\n", + "\n", + "## Problem\n", + "\n", + "Given a string in the form 'AAAABBBBCCCCCDDEEEE' compress it to become 'A4B4C5D2E4'. For this problem, you can falsely \"compress\" strings of single or double letters. For instance, it is okay for 'AAB' to return 'A2B1' even though this technically takes more space. \n", + "\n", + "The function should also be case sensitive, so that a string 'AAAaaa' returns 'A3a3'." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Since Python strings are immutable, we'll need to work off of a list of characters, and at the end convert that list back into a string with a **join** statement.\n", + "\n", + "The solution below should yield us with a Time and Space complexity of O(n). Let's take a look with careful attention to the explanatory comments:" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def compress(s):\n", + " \"\"\"\n", + " This solution compresses without checking. Known as the RunLength Compression algorithm.\n", + " \"\"\"\n", + " \n", + " # Begin Run as empty string\n", + " r = \"\"\n", + " l = len(s)\n", + " \n", + " # Check for length 0\n", + " if l == 0:\n", + " return \"\"\n", + " \n", + " # Check for length 1\n", + " if l == 1:\n", + " return s + \"1\"\n", + " \n", + " #Intialize Values\n", + " last = s[0]\n", + " cnt = 1\n", + " i = 1\n", + " \n", + " while i < l:\n", + " \n", + " # Check to see if it is the same letter\n", + " if s[i] == s[i - 1]: \n", + " # Add a count if same as previous\n", + " cnt += 1\n", + " else:\n", + " # Otherwise store the previous data\n", + " r = r + s[i - 1] + str(cnt)\n", + " cnt = 1\n", + " \n", + " # Add to index count to terminate while loop\n", + " i += 1\n", + " \n", + " # Put everything back into run\n", + " r = r + s[i - 1] + str(cnt)\n", + " \n", + " return r" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'A5B4C4'" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "compress('AAAAABBBBCCCC')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCompress(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), '')\n", + " assert_equal(sol('AABBCC'), 'A2B2C2')\n", + " assert_equal(sol('AAABCCDDDDD'), 'A3B1C2D5')\n", + " print 'ALL TEST CASES PASSED'\n", + "\n", + "# Run Tests\n", + "t = TestCompress()\n", + "t.test(compress)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Unique Characters in String - SOLUTION-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Unique Characters in String - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..c93f14c1 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/.ipynb_checkpoints/Unique Characters in String - SOLUTION-checkpoint.ipynb @@ -0,0 +1,124 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Unique Characters in String\n", + "\n", + "## Problem\n", + "Given a string,determine if it is compreised of all unique characters. For example, the string 'abcde' has all unique characters and should return True. The string 'aabcde' contains duplicate characters and should return false." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "We'll show two possible solutions, one using a built-in data structure and a built in function, and another using a built-in data structure but using a look-up method to check if the characters are unique." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def uni_char(s):\n", + " return len(set(s)) == len(s)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def uni_char2(s):\n", + " chars = set()\n", + " for let in s:\n", + " # Check if in set\n", + " if let in chars:\n", + " return False\n", + " else:\n", + " #Add it to the set\n", + " chars.add(let)\n", + " return True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR CODE>\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestUnique(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), True)\n", + " assert_equal(sol('goo'), False)\n", + " assert_equal(sol('abcdefg'), True)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run Tests\n", + "t = TestUnique()\n", + "t.test(uni_char)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Anagram Check - SOLUTION.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Anagram Check - SOLUTION.ipynb new file mode 100644 index 00000000..91e7d3d2 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Anagram Check - SOLUTION.ipynb @@ -0,0 +1,310 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Anagram Solution\n", + "\n", + "## Problem\n", + "\n", + "Given two strings, check to see if they are anagrams. An anagram is when the two strings can be written using the exact same letters (so you can just rearrange the letters to get a different phrase or word). \n", + "\n", + "For example:\n", + "\n", + " \"public relations\" is an anagram of \"crap built on lies.\"\n", + " \n", + " \"clint eastwood\" is an anagram of \"old west action\"\n", + " \n", + "**Note: Ignore spaces and capitalization. So \"d go\" is an anagram of \"God\" and \"dog\" and \"o d g\".**\n", + "\n", + "## Solution\n", + "\n", + "There are two ways of thinking about this problem, if two strings have the same frequency of letters/element (meaning each letter shows up the same number of times in both strings) then they are anagrams of eachother. On a similar vien of logic, if two strings are equal to each other once they are sorted, then they are also anagrams of each other.\n", + "\n", + "You would be able to implement this second solution pretty easily in Python:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "def anagram(s1,s2):\n", + " \n", + " # Remove spaces and lowercase letters\n", + " s1 = s1.replace(' ','').lower()\n", + " s2 = s2.replace(' ','').lower()\n", + " \n", + " # Return boolean for sorted match.\n", + " return sorted(s1) == sorted(s2)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('dog','god')" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('clint eastwood','old west action')" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('aa','bb')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now the above sorting approach is simple, but is actually not optimal and in an interview setting you would probably be asked to implement a more manual solution involving just counting the number of letters in each string to test your ability to understand hash tables. Let's build out a fuller solution using counting and Python dictionaries:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "def anagram2(s1,s2):\n", + " \n", + " # Remove spaces and lowercase letters\n", + " s1 = s1.replace(' ','').lower()\n", + " s2 = s2.replace(' ','').lower()\n", + " \n", + " # Edge Case to check if same number of letters\n", + " if len(s1) != len(s2):\n", + " return False\n", + " \n", + " # Create counting dictionary (Note could use DefaultDict from Collections module)\n", + " count = {}\n", + " \n", + " \n", + " \n", + " # Fill dictionary for first string (add counts)\n", + " for letter in s1:\n", + " if letter in count:\n", + " count[letter] += 1\n", + " else:\n", + " count[letter] = 1\n", + " \n", + " # Fill dictionary for second string (subtract counts)\n", + " for letter in s2:\n", + " if letter in count:\n", + " count[letter] -= 1\n", + " else:\n", + " count[letter] = 1\n", + " \n", + " # Check that all counts are 0\n", + " for k in count:\n", + " if count[k] != 0:\n", + " return False\n", + "\n", + " # Otherwise they're anagrams\n", + " return True" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram2('dog','god')" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram2('clint eastwood','old west action')" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram2('dd','aa')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A quick note on the second solution, the use of defaultdict form the collections module would clean up this code quite a bit, and the final for loop could be built into the second for loop, but in the above implementation every step is very clear." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "Run the cell below to test your solution" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class AnagramTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('go go go','gggooo'),True)\n", + " assert_equal(sol('abc','cba'),True)\n", + " assert_equal(sol('hi man','hi man'),True)\n", + " assert_equal(sol('aabbcc','aabbc'),False)\n", + " assert_equal(sol('123','1 2'),False)\n", + " print \"ALL TEST CASES PASSED\"\n", + "\n", + "# Run Tests\n", + "t = AnagramTest()\n", + "t.test(anagram)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "t.test(anagram2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Array Pair Sum - SOLUTION.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Array Pair Sum - SOLUTION.ipynb new file mode 100644 index 00000000..2419f818 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Array Pair Sum - SOLUTION.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Array Pair Sum\n", + "\n", + "## Problem\n", + "\n", + "Given an integer array, output all the ** *unique* ** pairs that sum up to a specific value **k**.\n", + "\n", + "So the input:\n", + " \n", + " pair_sum([1,3,2,2],4)\n", + "\n", + "would return **2** pairs:\n", + "\n", + " (1,3)\n", + " (2,2)\n", + "\n", + "**NOTE: FOR TESTING PURPOSES< CHANGE YOUR FUNCTION SO IT OUTPUTS THE NUMBER OF PAIRS**\n", + "\n", + "## Solution\n", + "\n", + "The O(N) algorithm uses the set data structure. We perform a linear pass from the beginning and for each element we check whether k-element is in the set of seen numbers. If it is, then we found a pair of sum k and add it to the output. If not, this element doesn’t belong to a pair yet, and we add it to the set of seen elements. \n", + "\n", + "The algorithm is really simple once we figure out using a set. The complexity is O(N) because we do a single linear scan of the array, and for each element we just check whether the corresponding number to form a pair is in the set or add the current element to the set. Insert and find operations of a set are both average O(1), so the algorithm is O(N) in total. " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def pair_sum(arr,k):\n", + " \n", + " if len(arr)<2:\n", + " return\n", + " \n", + " # Sets for tracking\n", + " seen = set()\n", + " output = set()\n", + " \n", + " # For every number in array\n", + " for num in arr:\n", + " \n", + " # Set target difference\n", + " target = k-num\n", + " \n", + " # Add it to set if target hasn't been seen\n", + " if target not in seen:\n", + " seen.add(num)\n", + " \n", + " else:\n", + " # Add a tuple with the corresponding pair\n", + " output.add( (min(num,target), max(num,target)) )\n", + " \n", + " \n", + " # FOR TESTING\n", + " return len(output)\n", + " # Nice one-liner for printing output\n", + " #return '\\n'.join(map(str,list(output)))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pair_sum([1,3,2,2],4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPair(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([1,9,2,8,3,7,4,6,5,5,13,14,11,13,-1],10),6)\n", + " assert_equal(sol([1,2,3,1],3),1)\n", + " assert_equal(sol([1,3,2,2],4),2)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "#Run tests\n", + "t = TestPair()\n", + "t.test(pair_sum)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Find the Missing Element - SOLUTION.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Find the Missing Element - SOLUTION.ipynb new file mode 100644 index 00000000..0b216746 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Find the Missing Element - SOLUTION.ipynb @@ -0,0 +1,272 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Find the Missing Element\n", + "\n", + "## Problem\n", + "\n", + "Consider an array of non-negative integers. A second array is formed by shuffling the elements of the first array and deleting a random element. Given these two arrays, find which element is missing in the second array. \n", + "\n", + "Here is an example input, the first array is shuffled and the number 5 is removed to construct the second array.\n", + "\n", + "Input:\n", + " \n", + " finder([1,2,3,4,5,6,7],[3,7,2,1,4,6])\n", + "\n", + "Output:\n", + "\n", + " 5 is the missing number\n", + "\n", + "## Solution\n", + "\n", + "The naive solution is go through every element in the second array and check whether it appears in the first array. Note that there may be duplicate elements in the arrays so we should pay special attention to it. The complexity of this approach is O(N^2), since we would need two for loops.\n", + "\n", + "A more efficient solution is to sort the first array, so while checking whether an element in the first array appears in the second, we can do binary search (we'll learn about binary search in more detail in a future section). But we should still be careful about duplicate elements. The complexity is O(NlogN). \n", + "\n", + "If we don’t want to deal with the special case of duplicate numbers, we can sort both arrays and iterate over them simultaneously. Once two iterators have different values we can stop. The value of the first iterator is the missing element. This solution is also O(NlogN). Here is the solution for this approach:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def finder(arr1,arr2):\n", + " \n", + " # Sort the arrays\n", + " arr1.sort()\n", + " arr2.sort()\n", + " \n", + " # Compare elements in the sorted arrays\n", + " for num1, num2 in zip(arr1,arr2):\n", + " if num1!= num2:\n", + " return num1\n", + " \n", + " # Otherwise return last element\n", + " return arr1[-1]" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [1,2,3,4,5,6,7]\n", + "arr2 = [3,7,2,1,4,6]\n", + "finder(arr1,arr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In most interviews, you would be expected to come up with a linear time solution. We can use a hashtable and store the number of times each element appears in the second array. Then for each element in the first array we decrement its counter. Once hit an element with zero count that’s the missing element. Here is this solution: " + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import collections\n", + "\n", + "def finder2(arr1, arr2): \n", + " \n", + " # Using default dict to avoid key errors\n", + " d=collections.defaultdict(int) \n", + " \n", + " # Add a count for every instance in Array 1\n", + " for num in arr2:\n", + " d[num]+=1 \n", + " \n", + " # Check if num not in dictionary\n", + " for num in arr1: \n", + " if d[num]==0: \n", + " return num \n", + " \n", + " # Otherwise, subtract a count\n", + " else: d[num]-=1 " + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [5,5,7,7]\n", + "arr2 = [5,7,7]\n", + "\n", + "finder2(arr1,arr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One possible solution is computing the sum of all the numbers in arr1 and arr2, and subtracting arr2’s sum from array1’s sum. The difference is the missing number in arr2. However, this approach could be problematic if the arrays are too long, or the numbers are very large. Then overflow will occur while summing up the numbers.\n", + "\n", + "By performing a very clever trick, we can achieve linear time and constant space complexity without any problems. Here it is: initialize a variable to 0, then [XOR](https://en.wikipedia.org/wiki/Exclusive_or) every element in the first and second arrays with that variable. In the end, the value of the variable is the result, missing element in array2." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def finder3(arr1, arr2): \n", + " result=0 \n", + " \n", + " # Perform an XOR between the numbers in the arrays\n", + " for num in arr1+arr2: \n", + " result^=num \n", + " print result\n", + " \n", + " return result " + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n", + "0\n", + "7\n", + "0\n", + "5\n", + "2\n", + "5\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "finder3(arr1,arr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFinder(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([5,5,7,7],[5,7,7]),5)\n", + " assert_equal(sol([1,2,3,4,5,6,7],[3,7,2,1,4,6]),5)\n", + " assert_equal(sol([9,8,7,6,5,4,3,2,1],[9,8,7,5,4,3,2,1]),6)\n", + " print 'ALL TEST CASES PASSED'\n", + "\n", + "# Run test\n", + "t = TestFinder()\n", + "t.test(finder)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Largest Continuous Sum - SOLUTION.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Largest Continuous Sum - SOLUTION.ipynb new file mode 100644 index 00000000..f5fd1e30 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Largest Continuous Sum - SOLUTION.ipynb @@ -0,0 +1,140 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Largest Continuous Sum\n", + "\n", + "## Problem\n", + "Given an array of integers (positive and negative) find the largest continuous sum. \n", + "\n", + "## Solution\n", + "\n", + "If the array is all positive, then the result is simply the sum of all numbers. The negative numbers in the array will cause us to need to begin checking sequences. \n", + "\n", + "The algorithm is, we start summing up the numbers and store in a current sum variable. After adding each element, we check whether the current sum is larger than maximum sum encountered so far. If it is, we update the maximum sum. As long as the current sum is positive, we keep adding the numbers. When the current sum becomes negative, we start with a new current sum. Because a negative current sum will only decrease the sum of a future sequence. Note that we don’t reset the current sum to 0 because the array can contain all negative integers. Then the result would be the largest negative number. \n", + "\n", + "Let's see the code:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "def large_cont_sum(arr): \n", + " \n", + " # Check to see if array is length 0\n", + " if len(arr)==0: \n", + " return 0\n", + " \n", + " # Start the max and current sum at the first element\n", + " max_sum=current_sum=arr[0] \n", + " \n", + " # For every element in array\n", + " for num in arr[1:]: \n", + " \n", + " # Set current sum as the higher of the two\n", + " current_sum=max(current_sum+num, num)\n", + " \n", + " # Set max as the higher between the currentSum and the current max\n", + " max_sum=max(current_sum, max_sum) \n", + " \n", + " return max_sum " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "29" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "large_cont_sum([1,2,-1,3,4,10,10,-10,-1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "Many times in an interview setting the question also requires you to report back the start and end points of the sum. Keep this in mind and see if you can solve that problem, we'll see it in the mock interview section of the course!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "from nose.tools import assert_equal\n", + "\n", + "class LargeContTest(object):\n", + " def test(self,sol):\n", + " assert_equal(sol([1,2,-1,3,4,-1]),9)\n", + " assert_equal(sol([1,2,-1,3,4,10,10,-10,-1]),29)\n", + " assert_equal(sol([-1,1]),1)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "#Run Test\n", + "t = LargeContTest()\n", + "t.test(large_cont_sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Sentence Reversal - SOLUTION.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Sentence Reversal - SOLUTION.ipynb new file mode 100644 index 00000000..0e6577a7 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Sentence Reversal - SOLUTION.ipynb @@ -0,0 +1,257 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sentence Reversal\n", + "\n", + "## Problem\n", + "\n", + "Given a string of words, reverse all the words. For example:\n", + "\n", + "Given:\n", + " \n", + " 'This is the best'\n", + "\n", + "Return:\n", + "\n", + " 'best the is This'\n", + "\n", + "As part of this exercise you should remove all leading and trailing whitespace. So that inputs such as:\n", + "\n", + " ' space here' and 'space here '\n", + "\n", + "both become:\n", + "\n", + " 'here space'\n", + "\n", + "## Solution\n", + "\n", + "We could take advantage of Python's abilities and solve the problem with the use of **split()** and some slicing or use of **reversed**:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rev_word1(s):\n", + " return \" \".join(reversed(s.split()))\n", + "\n", + "#Or\n", + "\n", + "def rev_word2(s):\n", + " return \" \".join(s.split()[::-1])" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'go? to ready you are John, Hi'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word1('Hi John, are you ready to go?')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'go? to ready you are John, Hi'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word2('Hi John, are you ready to go?')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While these are valid solutions, in an interview setting you'll have to work out the basic algorithm that is used. In this case what we want to do is loop over the text and extract words form the string ourselves. Then we can push the words to a \"stack\" and in the end opo them all to reverse. Let's see what this actually looks like:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rev_word3(s):\n", + " \"\"\"\n", + " Manually doing the splits on the spaces.\n", + " \"\"\"\n", + " \n", + " words = []\n", + " length = len(s)\n", + " spaces = [' ']\n", + " \n", + " # Index Tracker\n", + " i = 0\n", + " \n", + " # While index is less than length of string\n", + " while i < length:\n", + " \n", + " # If element isn't a space\n", + " if s[i] not in spaces:\n", + " \n", + " # The word starts at this index\n", + " word_start = i\n", + " \n", + " while i < length and s[i] not in spaces:\n", + " \n", + " # Get index where word ends\n", + " i += 1\n", + " # Append that word to the list\n", + " words.append(s[word_start:i])\n", + " # Add to index\n", + " i += 1\n", + " \n", + " # Join the reversed words\n", + " return \" \".join(reversed(words))" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'you are how John Hello'" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word3(' Hello John how are you ')" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'before space'" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word3(' space before')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you want you can further develop this solution so its all manual, you can create your own reversal function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class ReversalTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(' space before'),'before space')\n", + " assert_equal(sol('space after '),'after space')\n", + " assert_equal(sol(' Hello John how are you '),'you are how John Hello')\n", + " assert_equal(sol('1'),'1')\n", + " print \"ALL TEST CASES PASSED\"\n", + " \n", + "# Run and test\n", + "t = ReversalTest()\n", + "t.test(rev_word)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/String Compression -SOLUTION.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/String Compression -SOLUTION.ipynb new file mode 100644 index 00000000..68411f20 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/String Compression -SOLUTION.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# String Compression\n", + "\n", + "## Problem\n", + "\n", + "Given a string in the form 'AAAABBBBCCCCCDDEEEE' compress it to become 'A4B4C5D2E4'. For this problem, you can falsely \"compress\" strings of single or double letters. For instance, it is okay for 'AAB' to return 'A2B1' even though this technically takes more space. \n", + "\n", + "The function should also be case sensitive, so that a string 'AAAaaa' returns 'A3a3'." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Since Python strings are immutable, we'll need to work off of a list of characters, and at the end convert that list back into a string with a **join** statement.\n", + "\n", + "The solution below should yield us with a Time and Space complexity of O(n). Let's take a look with careful attention to the explanatory comments:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "def compress(s):\n", + " \"\"\"\n", + " This solution compresses without checking. Known as the RunLength Compression algorithm.\n", + " \"\"\"\n", + " \n", + " # Begin Run as empty string\n", + " r = \"\"\n", + " l = len(s)\n", + " \n", + " # Check for length 0\n", + " if l == 0:\n", + " return \"\"\n", + " \n", + " # Check for length 1\n", + " if l == 1:\n", + " return s + \"1\"\n", + " \n", + " #Intialize Values\n", + " last = s[0]\n", + " cnt = 1\n", + " i = 1\n", + " \n", + " while i < l:\n", + " \n", + " # Check to see if it is the same letter\n", + " if s[i] == s[i - 1]: \n", + " # Add a count if same as previous\n", + " cnt += 1\n", + " else:\n", + " # Otherwise store the previous data\n", + " r = r + s[i - 1] + str(cnt)\n", + " cnt = 1\n", + " \n", + " # Add to index count to terminate while loop\n", + " i += 1\n", + " \n", + " # Put everything back into run\n", + " r = r + s[i - 1] + str(cnt)\n", + " \n", + " return r" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'A5B4C4'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "compress('AAAAABBBBCCCC')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCompress(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), '')\n", + " assert_equal(sol('AABBCC'), 'A2B2C2')\n", + " assert_equal(sol('AAABCCDDDDD'), 'A3B1C2D5')\n", + " print 'ALL TEST CASES PASSED'\n", + "\n", + "# Run Tests\n", + "t = TestCompress()\n", + "t.test(compress)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Unique Characters in String - SOLUTION.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Unique Characters in String - SOLUTION.ipynb new file mode 100644 index 00000000..4b18c4c4 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions - SOLUTIONS/Unique Characters in String - SOLUTION.ipynb @@ -0,0 +1,122 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Unique Characters in String\n", + "\n", + "## Problem\n", + "Given a string,determine if it is compreised of all unique characters. For example, the string 'abcde' has all unique characters and should return True. The string 'aabcde' contains duplicate characters and should return false." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "We'll show two possible solutions, one using a built-in data structure and a built in function, and another using a built-in data structure but using a look-up method to check if the characters are unique." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def uni_char(s):\n", + " return len(set(s)) == len(s)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def uni_char2(s):\n", + " chars = set()\n", + " for let in s:\n", + " # Check if in set\n", + " if let in chars:\n", + " return False\n", + " else:\n", + " #Add it to the set\n", + " chars.add(let)\n", + " return True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR CODE>\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestUnique(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), True)\n", + " assert_equal(sol('goo'), False)\n", + " assert_equal(sol('abcdefg'), True)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run Tests\n", + "t = TestUnique()\n", + "t.test(uni_char)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Anagram Check -checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Anagram Check -checkpoint.ipynb new file mode 100644 index 00000000..fd6f0824 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Anagram Check -checkpoint.ipynb @@ -0,0 +1,197 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Anagram Check\n", + "\n", + "## Problem\n", + "\n", + "Given two strings, check to see if they are anagrams. An anagram is when the two strings can be written using the exact same letters (so you can just rearrange the letters to get a different phrase or word). \n", + "\n", + "For example:\n", + "\n", + " \"public relations\" is an anagram of \"crap built on lies.\"\n", + " \n", + " \"clint eastwood\" is an anagram of \"old west action\"\n", + " \n", + "**Note: Ignore spaces and capitalization. So \"d go\" is an anagram of \"God\" and \"dog\" and \"o d g\".**\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def anagram(s1,s2):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('dog','god')" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('clint eastwood','old west action')" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('aa','bb')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "Run the cell below to test your solution" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class AnagramTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('go go go','gggooo'),True)\n", + " assert_equal(sol('abc','cba'),True)\n", + " assert_equal(sol('hi man','hi man'),True)\n", + " assert_equal(sol('aabbcc','aabbc'),False)\n", + " assert_equal(sol('123','1 2'),False)\n", + " print \"ALL TEST CASES PASSED\"\n", + "\n", + "# Run Tests\n", + "t = AnagramTest()\n", + "t.test(anagram)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "t.test(anagram2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Array Pair Sum -checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Array Pair Sum -checkpoint.ipynb new file mode 100644 index 00000000..50ee6bfa --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Array Pair Sum -checkpoint.ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Array Pair Sum\n", + "\n", + "## Problem\n", + "\n", + "Given an integer array, output all the ** *unique* ** pairs that sum up to a specific value **k**.\n", + "\n", + "So the input:\n", + " \n", + " pair_sum([1,3,2,2],4)\n", + "\n", + "would return **2** pairs:\n", + "\n", + " (1,3)\n", + " (2,2)\n", + "\n", + "**NOTE: FOR TESTING PURPOSES CHANGE YOUR FUNCTION SO IT OUTPUTS THE NUMBER OF PAIRS**\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def pair_sum(arr,k):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pair_sum([1,3,2,2],4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPair(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([1,9,2,8,3,7,4,6,5,5,13,14,11,13,-1],10),6)\n", + " assert_equal(sol([1,2,3,1],3),1)\n", + " assert_equal(sol([1,3,2,2],4),2)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "#Run tests\n", + "t = TestPair()\n", + "t.test(pair_sum)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Find the Missing Element -checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Find the Missing Element -checkpoint.ipynb new file mode 100644 index 00000000..fe1e12d7 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Find the Missing Element -checkpoint.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Find the Missing Element\n", + "\n", + "## Problem\n", + "\n", + "Consider an array of non-negative integers. A second array is formed by shuffling the elements of the first array and deleting a random element. Given these two arrays, find which element is missing in the second array. \n", + "\n", + "Here is an example input, the first array is shuffled and the number 5 is removed to construct the second array.\n", + "\n", + "Input:\n", + " \n", + " finder([1,2,3,4,5,6,7],[3,7,2,1,4,6])\n", + "\n", + "Output:\n", + "\n", + " 5 is the missing number\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def finder(arr1,arr2):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [1,2,3,4,5,6,7]\n", + "arr2 = [3,7,2,1,4,6]\n", + "finder(arr1,arr2)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [5,5,7,7]\n", + "arr2 = [5,7,7]\n", + "\n", + "finder(arr1,arr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "_____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFinder(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([5,5,7,7],[5,7,7]),5)\n", + " assert_equal(sol([1,2,3,4,5,6,7],[3,7,2,1,4,6]),5)\n", + " assert_equal(sol([9,8,7,6,5,4,3,2,1],[9,8,7,5,4,3,2,1]),6)\n", + " print 'ALL TEST CASES PASSED'\n", + "\n", + "# Run test\n", + "t = TestFinder()\n", + "t.test(finder)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Largest Continuous Sum -checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Largest Continuous Sum -checkpoint.ipynb new file mode 100644 index 00000000..a4220bb0 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Largest Continuous Sum -checkpoint.ipynb @@ -0,0 +1,125 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Largest Continuous Sum\n", + "\n", + "## Problem\n", + "Given an array of integers (positive and negative) find the largest continuous sum. \n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def large_cont_sum(arr): \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "29" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "large_cont_sum([1,2,-1,3,4,10,10,-10,-1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "Many times in an interview setting the question also requires you to report back the start and end points of the sum. Keep this in mind and see if you can solve that problem, we'll see it in the mock interview section of the course!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "from nose.tools import assert_equal\n", + "\n", + "class LargeContTest(object):\n", + " def test(self,sol):\n", + " assert_equal(sol([1,2,-1,3,4,-1]),9)\n", + " assert_equal(sol([1,2,-1,3,4,10,10,-10,-1]),29)\n", + " assert_equal(sol([-1,1]),1)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "#Run Test\n", + "t = LargeContTest()\n", + "t.test(large_cont_sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Sentence Reversal-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Sentence Reversal-checkpoint.ipynb new file mode 100644 index 00000000..e6cf296a --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Sentence Reversal-checkpoint.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sentence Reversal\n", + "\n", + "## Problem\n", + "\n", + "Given a string of words, reverse all the words. For example:\n", + "\n", + "Given:\n", + " \n", + " 'This is the best'\n", + "\n", + "Return:\n", + "\n", + " 'best the is This'\n", + "\n", + "As part of this exercise you should remove all leading and trailing whitespace. So that inputs such as:\n", + "\n", + " ' space here' and 'space here '\n", + "\n", + "both become:\n", + "\n", + " 'here space'\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rev_word(s):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'go? to ready you are John, Hi'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word('Hi John, are you ready to go?')" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'before space'" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word(' space before')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class ReversalTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(' space before'),'before space')\n", + " assert_equal(sol('space after '),'after space')\n", + " assert_equal(sol(' Hello John how are you '),'you are how John Hello')\n", + " assert_equal(sol('1'),'1')\n", + " print \"ALL TEST CASES PASSED\"\n", + " \n", + "# Run and test\n", + "t = ReversalTest()\n", + "t.test(rev_word)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/String Compression -checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/String Compression -checkpoint.ipynb new file mode 100644 index 00000000..e8c7d5f4 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/String Compression -checkpoint.ipynb @@ -0,0 +1,128 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# String Compression\n", + "\n", + "## Problem\n", + "\n", + "Given a string in the form 'AAAABBBBCCCCCDDEEEE' compress it to become 'A4B4C5D2E4'. For this problem, you can falsely \"compress\" strings of single or double letters. For instance, it is okay for 'AAB' to return 'A2B1' even though this technically takes more space. \n", + "\n", + "The function should also be case sensitive, so that a string 'AAAaaa' returns 'A3a3'." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def compress(s):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'A5B4C4'" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "compress('AAAAABBBBCCCC')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCompress(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), '')\n", + " assert_equal(sol('AABBCC'), 'A2B2C2')\n", + " assert_equal(sol('AAABCCDDDDD'), 'A3B1C2D5')\n", + " print 'ALL TEST CASES PASSED'\n", + "\n", + "# Run Tests\n", + "t = TestCompress()\n", + "t.test(compress)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Unique Characters in String-checkpoint.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Unique Characters in String-checkpoint.ipynb new file mode 100644 index 00000000..9659d2bf --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/.ipynb_checkpoints/Unique Characters in String-checkpoint.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Unique Characters in String\n", + "\n", + "## Problem\n", + "Given a string,determine if it is compreised of all unique characters. For example, the string 'abcde' has all unique characters and should return True. The string 'aabcde' contains duplicate characters and should return false." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def uni_char(s):\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR CODE>\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestUnique(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), True)\n", + " assert_equal(sol('goo'), False)\n", + " assert_equal(sol('abcdefg'), True)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run Tests\n", + "t = TestUnique()\n", + "t.test(uni_char)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Anagram Check .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Anagram Check .ipynb new file mode 100644 index 00000000..fd6f0824 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Anagram Check .ipynb @@ -0,0 +1,197 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Anagram Check\n", + "\n", + "## Problem\n", + "\n", + "Given two strings, check to see if they are anagrams. An anagram is when the two strings can be written using the exact same letters (so you can just rearrange the letters to get a different phrase or word). \n", + "\n", + "For example:\n", + "\n", + " \"public relations\" is an anagram of \"crap built on lies.\"\n", + " \n", + " \"clint eastwood\" is an anagram of \"old west action\"\n", + " \n", + "**Note: Ignore spaces and capitalization. So \"d go\" is an anagram of \"God\" and \"dog\" and \"o d g\".**\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def anagram(s1,s2):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('dog','god')" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('clint eastwood','old west action')" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "anagram('aa','bb')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "Run the cell below to test your solution" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class AnagramTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('go go go','gggooo'),True)\n", + " assert_equal(sol('abc','cba'),True)\n", + " assert_equal(sol('hi man','hi man'),True)\n", + " assert_equal(sol('aabbcc','aabbc'),False)\n", + " assert_equal(sol('123','1 2'),False)\n", + " print \"ALL TEST CASES PASSED\"\n", + "\n", + "# Run Tests\n", + "t = AnagramTest()\n", + "t.test(anagram)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "t.test(anagram2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Array Pair Sum .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Array Pair Sum .ipynb new file mode 100644 index 00000000..50ee6bfa --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Array Pair Sum .ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Array Pair Sum\n", + "\n", + "## Problem\n", + "\n", + "Given an integer array, output all the ** *unique* ** pairs that sum up to a specific value **k**.\n", + "\n", + "So the input:\n", + " \n", + " pair_sum([1,3,2,2],4)\n", + "\n", + "would return **2** pairs:\n", + "\n", + " (1,3)\n", + " (2,2)\n", + "\n", + "**NOTE: FOR TESTING PURPOSES CHANGE YOUR FUNCTION SO IT OUTPUTS THE NUMBER OF PAIRS**\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def pair_sum(arr,k):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pair_sum([1,3,2,2],4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPair(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([1,9,2,8,3,7,4,6,5,5,13,14,11,13,-1],10),6)\n", + " assert_equal(sol([1,2,3,1],3),1)\n", + " assert_equal(sol([1,3,2,2],4),2)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "#Run tests\n", + "t = TestPair()\n", + "t.test(pair_sum)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Find the Missing Element .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Find the Missing Element .ipynb new file mode 100644 index 00000000..fe1e12d7 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Find the Missing Element .ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Find the Missing Element\n", + "\n", + "## Problem\n", + "\n", + "Consider an array of non-negative integers. A second array is formed by shuffling the elements of the first array and deleting a random element. Given these two arrays, find which element is missing in the second array. \n", + "\n", + "Here is an example input, the first array is shuffled and the number 5 is removed to construct the second array.\n", + "\n", + "Input:\n", + " \n", + " finder([1,2,3,4,5,6,7],[3,7,2,1,4,6])\n", + "\n", + "Output:\n", + "\n", + " 5 is the missing number\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def finder(arr1,arr2):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [1,2,3,4,5,6,7]\n", + "arr2 = [3,7,2,1,4,6]\n", + "finder(arr1,arr2)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr1 = [5,5,7,7]\n", + "arr2 = [5,7,7]\n", + "\n", + "finder(arr1,arr2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "_____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFinder(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol([5,5,7,7],[5,7,7]),5)\n", + " assert_equal(sol([1,2,3,4,5,6,7],[3,7,2,1,4,6]),5)\n", + " assert_equal(sol([9,8,7,6,5,4,3,2,1],[9,8,7,5,4,3,2,1]),6)\n", + " print 'ALL TEST CASES PASSED'\n", + "\n", + "# Run test\n", + "t = TestFinder()\n", + "t.test(finder)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Largest Continuous Sum .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Largest Continuous Sum .ipynb new file mode 100644 index 00000000..a4220bb0 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Largest Continuous Sum .ipynb @@ -0,0 +1,125 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Largest Continuous Sum\n", + "\n", + "## Problem\n", + "Given an array of integers (positive and negative) find the largest continuous sum. \n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def large_cont_sum(arr): \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "29" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "large_cont_sum([1,2,-1,3,4,10,10,-10,-1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "Many times in an interview setting the question also requires you to report back the start and end points of the sum. Keep this in mind and see if you can solve that problem, we'll see it in the mock interview section of the course!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "from nose.tools import assert_equal\n", + "\n", + "class LargeContTest(object):\n", + " def test(self,sol):\n", + " assert_equal(sol([1,2,-1,3,4,-1]),9)\n", + " assert_equal(sol([1,2,-1,3,4,10,10,-10,-1]),29)\n", + " assert_equal(sol([-1,1]),1)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "#Run Test\n", + "t = LargeContTest()\n", + "t.test(large_cont_sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Sentence Reversal.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Sentence Reversal.ipynb new file mode 100644 index 00000000..e6cf296a --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Sentence Reversal.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sentence Reversal\n", + "\n", + "## Problem\n", + "\n", + "Given a string of words, reverse all the words. For example:\n", + "\n", + "Given:\n", + " \n", + " 'This is the best'\n", + "\n", + "Return:\n", + "\n", + " 'best the is This'\n", + "\n", + "As part of this exercise you should remove all leading and trailing whitespace. So that inputs such as:\n", + "\n", + " ' space here' and 'space here '\n", + "\n", + "both become:\n", + "\n", + " 'here space'\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rev_word(s):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'go? to ready you are John, Hi'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word('Hi John, are you ready to go?')" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'before space'" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rev_word(' space before')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class ReversalTest(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(' space before'),'before space')\n", + " assert_equal(sol('space after '),'after space')\n", + " assert_equal(sol(' Hello John how are you '),'you are how John Hello')\n", + " assert_equal(sol('1'),'1')\n", + " print \"ALL TEST CASES PASSED\"\n", + " \n", + "# Run and test\n", + "t = ReversalTest()\n", + "t.test(rev_word)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/String Compression .ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/String Compression .ipynb new file mode 100644 index 00000000..e8c7d5f4 --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/String Compression .ipynb @@ -0,0 +1,128 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# String Compression\n", + "\n", + "## Problem\n", + "\n", + "Given a string in the form 'AAAABBBBCCCCCDDEEEE' compress it to become 'A4B4C5D2E4'. For this problem, you can falsely \"compress\" strings of single or double letters. For instance, it is okay for 'AAB' to return 'A2B1' even though this technically takes more space. \n", + "\n", + "The function should also be case sensitive, so that a string 'AAAaaa' returns 'A3a3'." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def compress(s):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'A5B4C4'" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "compress('AAAAABBBBCCCC')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCompress(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), '')\n", + " assert_equal(sol('AABBCC'), 'A2B2C2')\n", + " assert_equal(sol('AAABCCDDDDD'), 'A3B1C2D5')\n", + " print 'ALL TEST CASES PASSED'\n", + "\n", + "# Run Tests\n", + "t = TestCompress()\n", + "t.test(compress)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Unique Characters in String.ipynb b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Unique Characters in String.ipynb new file mode 100644 index 00000000..9659d2bf --- /dev/null +++ b/Array Sequences/Array Sequences Interview Questions/Array Sequence Interview Questions/Unique Characters in String.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Unique Characters in String\n", + "\n", + "## Problem\n", + "Given a string,determine if it is compreised of all unique characters. For example, the string 'abcde' has all unique characters and should return True. The string 'aabcde' contains duplicate characters and should return false." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def uni_char(s):\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR CODE>\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestUnique(object):\n", + "\n", + " def test(self, sol):\n", + " assert_equal(sol(''), True)\n", + " assert_equal(sol('goo'), False)\n", + " assert_equal(sol('abcdefg'), True)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run Tests\n", + "t = TestUnique()\n", + "t.test(uni_char)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Array Sequences/Dynamic Array Exercise.ipynb b/Array Sequences/Dynamic Array Exercise.ipynb new file mode 100644 index 00000000..2b484bd7 --- /dev/null +++ b/Array Sequences/Dynamic Array Exercise.ipynb @@ -0,0 +1,309 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Dynamic Array Exercise\n", + "____\n", + "\n", + "In this exercise we will create our own Dynamic Array class!\n", + "\n", + "We'll be using a built in library called [ctypes](https://docs.python.org/2/library/ctypes.html). Check out the documentation for more info, but its basically going to be used here as a raw array from the ctypes module.\n", + "If you find yourself very interested in it, check out: [Ctypes Tutorial](http://starship.python.net/crew/theller/ctypes/tutorial.html)\n", + "\n", + "Also..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**A quick note on public vs private methods, we can use an underscore _ before the method name to keep it non-public. For example:**" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class M(object):\n", + " \n", + " def public(self):\n", + " print 'Use Tab to see me!'\n", + " \n", + " def _private(self):\n", + " print \"You won't be able to Tab to see me!\"" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m = M()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Use Tab to see me!\n" + ] + } + ], + "source": [ + "m.public()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You won't be able to see me!\n" + ] + } + ], + "source": [ + "m._private()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check out PEP 8 and the Python docs for more info on this!\n", + "_____\n", + "\n", + "### Dynamic Array Implementation" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "import ctypes\n", + "\n", + "class DynamicArray(object):\n", + " '''\n", + " DYNAMIC ARRAY CLASS (Similar to Python List)\n", + " '''\n", + " \n", + " def __init__(self):\n", + " self.n = 0 # Count actual elements (Default is 0)\n", + " self.capacity = 1 # Default Capacity\n", + " self.A = self.make_array(self.capacity)\n", + " \n", + " def __len__(self):\n", + " \"\"\"\n", + " Return number of elements sorted in array\n", + " \"\"\"\n", + " return self.n\n", + " \n", + " def __getitem__(self,k):\n", + " \"\"\"\n", + " Return element at index k\n", + " \"\"\"\n", + " if not 0 <= k ,\n", + " 1: <__main__.Vertex instance at 0x104cce5f0>,\n", + " 2: <__main__.Vertex instance at 0x10395d950>,\n", + " 3: <__main__.Vertex instance at 0x1039c00e0>,\n", + " 4: <__main__.Vertex instance at 0x1039c4e60>,\n", + " 5: <__main__.Vertex instance at 0x1039c45f0>}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "g.vertList" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "g.addEdge(0,1,2)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 connectedTo: [1]\n", + "[<__main__.Vertex instance at 0x104cce5f0>]\n", + "\n", + "\n", + "1 connectedTo: []\n", + "[]\n", + "\n", + "\n", + "2 connectedTo: []\n", + "[]\n", + "\n", + "\n", + "3 connectedTo: []\n", + "[]\n", + "\n", + "\n", + "4 connectedTo: []\n", + "[]\n", + "\n", + "\n", + "5 connectedTo: []\n", + "[]\n", + "\n", + "\n" + ] + } + ], + "source": [ + "for vertex in g:\n", + " print vertex\n", + " print vertex.getConnections()\n", + " print '\\n'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Great Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/.ipynb_checkpoints/Implementation of Breadth First Search-checkpoint.ipynb b/Graphs/.ipynb_checkpoints/Implementation of Breadth First Search-checkpoint.ipynb new file mode 100644 index 00000000..cd18f9b7 --- /dev/null +++ b/Graphs/.ipynb_checkpoints/Implementation of Breadth First Search-checkpoint.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Implementation of Breadth First Search\n", + "\n", + "\n", + "An alternative algorithm called Breath-First search provides us with the ability to return the same results as DFS but with the added guarantee to return the shortest-path first. This algorithm is a little more tricky to implement in a recursive manner instead using the queue data-structure, as such I will only being documenting the iterative approach. The actions performed per each explored vertex are the same as the depth-first implementation, however, replacing the stack with a queue will instead explore the breadth of a vertex depth before moving on. This behavior guarantees that the first path located is one of the shortest-paths present, based on number of edges being the cost factor.\n", + "\n", + "We'll assume our Graph is in the form:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Connected Component\n", + "Similar to the iterative DFS implementation the only alteration required is to remove the next item from the beginning of the list structure instead of the stacks last." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'A', 'B', 'C', 'D', 'E', 'F'}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def bfs(graph, start):\n", + " visited, queue = set(), [start]\n", + " while queue:\n", + " vertex = queue.pop(0)\n", + " if vertex not in visited:\n", + " visited.add(vertex)\n", + " queue.extend(graph[vertex] - visited)\n", + " return visited\n", + "\n", + "bfs(graph, 'A')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Paths\n", + "This implementation can again be altered slightly to instead return all possible paths between two vertices, the first of which being one of the shortest such path." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[['A', 'C', 'F'], ['A', 'B', 'E', 'F']]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def bfs_paths(graph, start, goal):\n", + " queue = [(start, [start])]\n", + " while queue:\n", + " (vertex, path) = queue.pop(0)\n", + " for next in graph[vertex] - set(path):\n", + " if next == goal:\n", + " yield path + [next]\n", + " else:\n", + " queue.append((next, path + [next]))\n", + "\n", + "list(bfs_paths(graph, 'A', 'F'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Knowing that the shortest path will be returned first from the BFS path generator method we can create a useful method which simply returns the shortest path found or ‘None’ if no path exists. As we are using a generator this in theory should provide similar performance results as just breaking out and returning the first matching path in the BFS implementation." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['A', 'C', 'F']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def shortest_path(graph, start, goal):\n", + " try:\n", + " return next(bfs_paths(graph, start, goal))\n", + " except StopIteration:\n", + " return None\n", + "\n", + "shortest_path(graph, 'A', 'F')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resources\n", + "* [Depth-and Breadth-First Search](http://jeremykun.com/2013/01/22/depth-and-breadth-first-search/)\n", + "* [Connected component](https://en.wikipedia.org/wiki/Connected_component_(graph_theory))\n", + "* [Adjacency matrix](https://en.wikipedia.org/wiki/Adjacency_matrix)\n", + "* [Adjacency list](https://en.wikipedia.org/wiki/Adjacency_list)\n", + "* [Python Gotcha: Default arguments and mutable data structures](https://developmentality.wordpress.com/2010/08/23/python-gotcha-default-arguments/)\n", + "* [Generators](https://wiki.python.org/moin/Generators)" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/.ipynb_checkpoints/Implementation of Depth First Search-checkpoint.ipynb b/Graphs/.ipynb_checkpoints/Implementation of Depth First Search-checkpoint.ipynb new file mode 100644 index 00000000..9551040f --- /dev/null +++ b/Graphs/.ipynb_checkpoints/Implementation of Depth First Search-checkpoint.ipynb @@ -0,0 +1,184 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Depth-First Search\n", + "This algorithm we will be discussing is Depth-First search which as the name hints at, explores possible vertices (from a supplied root) down each branch before backtracking. This property allows the algorithm to be implemented succinctly in both iterative and recursive forms. Below is a listing of the actions performed upon each visit to a node.\n", + "\n", + "* Mark the current vertex as being visited.\n", + "* Explore each adjacent vertex that is not included in the visited set.\n", + "\n", + "We will assume a simplified version of a graph in the following form:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Connected Component\n", + "\n", + "The implementation below uses the stack data-structure to build-up and return a set of vertices that are accessible within the subjects connected component. Using Python’s overloading of the subtraction operator to remove items from a set, we are able to add only the unvisited adjacent vertices." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'A', 'B', 'C', 'D', 'E', 'F'}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def dfs(graph, start):\n", + " visited, stack = set(), [start]\n", + " while stack:\n", + " vertex = stack.pop()\n", + " if vertex not in visited:\n", + " visited.add(vertex)\n", + " stack.extend(graph[vertex] - visited)\n", + " return visited\n", + "\n", + "dfs(graph, 'A') " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The second implementation provides the same functionality as the first, however, this time we are using the more succinct recursive form. Due to a common Python gotcha with default parameter values being created only once, we are required to create a new visited set on each user invocation. Another Python language detail is that function variables are passed by reference, resulting in the visited mutable set not having to reassigned upon each recursive call." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'A', 'B', 'C', 'D', 'E', 'F'}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def dfs(graph, start, visited=None):\n", + " if visited is None:\n", + " visited = set()\n", + " visited.add(start)\n", + " for nxt in graph[start] - visited:\n", + " dfs(graph, nxt, visited)\n", + " return visited\n", + "\n", + "dfs(graph, 'A') " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Paths\n", + "We are able to tweak both of the previous implementations to return all possible paths between a start and goal vertex. The implementation below uses the stack data-structure again to iteratively solve the problem, yielding each possible path when we locate the goal. Using a generator allows the user to only compute the desired amount of alternative paths." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[['A', 'B', 'E', 'F'], ['A', 'C', 'F']]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def dfs_paths(graph, start, goal):\n", + " stack = [(start, [start])]\n", + " while stack:\n", + " (vertex, path) = stack.pop()\n", + " for nxt in graph[vertex] - set(path):\n", + " if nxt == goal:\n", + " yield path + [nxt]\n", + " else:\n", + " stack.append((nxt, path + [nxt]))\n", + "\n", + "list(dfs_paths(graph, 'A', 'F'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resources\n", + "* [Depth-and Breadth-First Search](http://jeremykun.com/2013/01/22/depth-and-breadth-first-search/)\n", + "* [Connected component](https://en.wikipedia.org/wiki/Connected_component_(graph_theory))\n", + "* [Adjacency matrix](https://en.wikipedia.org/wiki/Adjacency_matrix)\n", + "* [Adjacency list](https://en.wikipedia.org/wiki/Adjacency_list)\n", + "* [Python Gotcha: Default arguments and mutable data structures](https://developmentality.wordpress.com/2010/08/23/python-gotcha-default-arguments/)\n", + "* [Generators](https://wiki.python.org/moin/Generators)" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/.ipynb_checkpoints/Implementation of Graph Overview-checkpoint.ipynb b/Graphs/.ipynb_checkpoints/Implementation of Graph Overview-checkpoint.ipynb new file mode 100644 index 00000000..5d2d34d8 --- /dev/null +++ b/Graphs/.ipynb_checkpoints/Implementation of Graph Overview-checkpoint.ipynb @@ -0,0 +1,160 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Graph Overview\n", + "\n", + "In this lecture we will implement a simple graph by focusing on the Node class. Refer to this lecture for the solution to the Interview Problem\n", + "\n", + "___\n", + "The graph will be directed and the edges can hold weights.\n", + "\n", + "We will have three classes, a State class, a Node class, and finally the Graph class.\n", + "\n", + "We're going to be taking advantage of two built-in tools here, [OrderDict](https://docs.python.org/2/library/collections.html#collections.OrderedDict) and [Enum](https://docs.python.org/3/library/enum.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from enum import Enum \n", + "\n", + "class State(Enum):\n", + " unvisited = 1 #White\n", + " visited = 2 #Black\n", + " visiting = 3 #Gray" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now for the Node class we will take advantage of the OrderedDict object in case we want to keep trak of the order keys are added to the dictionary." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from collections import OrderedDict\n", + "\n", + "class Node:\n", + "\n", + " def __init__(self, num):\n", + " self.num = num\n", + " self.visit_state = State.unvisited\n", + " self.adjacent = OrderedDict() # key = node, val = weight\n", + "\n", + " def __str__(self):\n", + " return str(self.num)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then finally the Graph:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Graph:\n", + "\n", + " def __init__(self):\n", + " self.nodes = OrderedDict() # key = node id, val = node\n", + "\n", + " def add_node(self, num):\n", + " node = Node(num)\n", + " self.nodes[num] = node\n", + " return node\n", + "\n", + " def add_edge(self, source, dest, weight=0):\n", + " if source not in self.nodes:\n", + " self.add_node(source)\n", + " if dest not in self.nodes:\n", + " self.add_node(dest)\n", + " self.nodes[source].adjacent[self.nodes[dest]] = weight" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "g = Graph()\n", + "g.add_edge(0, 1, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "OrderedDict([(0, <__main__.Node instance at 0x103a761b8>),\n", + " (1, <__main__.Node instance at 0x104dfef80>)])" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "g.nodes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Great Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/.ipynb_checkpoints/Knight's Tour Example Problem-checkpoint.ipynb b/Graphs/.ipynb_checkpoints/Knight's Tour Example Problem-checkpoint.ipynb new file mode 100644 index 00000000..1504a502 --- /dev/null +++ b/Graphs/.ipynb_checkpoints/Knight's Tour Example Problem-checkpoint.ipynb @@ -0,0 +1,113 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Knight's Tour Code\n", + "\n", + "** Below is th ecode referenced in the video lecture. Please refer to the video lectures for full explanation.**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def knightGraph(bdSize):\n", + " ktGraph = Graph()\n", + " for row in range(bdSize):\n", + " for col in range(bdSize):\n", + " nodeId = posToNodeId(row,col,bdSize)\n", + " newPositions = genLegalMoves(row,col,bdSize)\n", + " for e in newPositions:\n", + " nid = posToNodeId(e[0],e[1],bdSize)\n", + " ktGraph.addEdge(nodeId,nid)\n", + " return ktGraph\n", + "\n", + "def posToNodeId(row, column, board_size):\n", + " return (row * board_size) + column\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def genLegalMoves(x,y,bdSize):\n", + " newMoves = []\n", + " moveOffsets = [(-1,-2),(-1,2),(-2,-1),(-2,1),\n", + " ( 1,-2),( 1,2),( 2,-1),( 2,1)]\n", + " for i in moveOffsets:\n", + " newX = x + i[0]\n", + " newY = y + i[1]\n", + " if legalCoord(newX,bdSize) and \\\n", + " legalCoord(newY,bdSize):\n", + " newMoves.append((newX,newY))\n", + " return newMoves\n", + "\n", + "def legalCoord(x,bdSize):\n", + " if x >= 0 and x < bdSize:\n", + " return True\n", + " else:\n", + " return False" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def knightTour(n,path,u,limit):\n", + " u.setColor('gray')\n", + " path.append(u)\n", + " if n < limit:\n", + " nbrList = list(u.getConnections())\n", + " i = 0\n", + " done = False\n", + " while i < len(nbrList) and not done:\n", + " if nbrList[i].getColor() == 'white':\n", + " done = knightTour(n+1, path, nbrList[i], limit)\n", + " i = i + 1\n", + " if not done: # prepare to backtrack\n", + " path.pop()\n", + " u.setColor('white')\n", + " else:\n", + " done = True\n", + " return done" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/.ipynb_checkpoints/Word Ladder Example Problem-checkpoint.ipynb b/Graphs/.ipynb_checkpoints/Word Ladder Example Problem-checkpoint.ipynb new file mode 100644 index 00000000..a90aefdd --- /dev/null +++ b/Graphs/.ipynb_checkpoints/Word Ladder Example Problem-checkpoint.ipynb @@ -0,0 +1,154 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Word Ladder Example Code\n", + "\n", + "Below is the Vertex and Graph class used for the Word Ladder example code:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Vertex:\n", + " def __init__(self,key):\n", + " self.id = key\n", + " self.connectedTo = {}\n", + "\n", + " def addNeighbor(self,nbr,weight=0):\n", + " self.connectedTo[nbr] = weight\n", + "\n", + " def __str__(self):\n", + " return str(self.id) + ' connectedTo: ' + str([x.id for x in self.connectedTo])\n", + "\n", + " def getConnections(self):\n", + " return self.connectedTo.keys()\n", + "\n", + " def getId(self):\n", + " return self.id\n", + "\n", + " def getWeight(self,nbr):\n", + " return self.connectedTo[nbr]" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Graph:\n", + " def __init__(self):\n", + " self.vertList = {}\n", + " self.numVertices = 0\n", + "\n", + " def addVertex(self,key):\n", + " self.numVertices = self.numVertices + 1\n", + " newVertex = Vertex(key)\n", + " self.vertList[key] = newVertex\n", + " return newVertex\n", + "\n", + " def getVertex(self,n):\n", + " if n in self.vertList:\n", + " return self.vertList[n]\n", + " else:\n", + " return None\n", + "\n", + " def __contains__(self,n):\n", + " return n in self.vertList\n", + "\n", + " def addEdge(self,f,t,cost=0):\n", + " if f not in self.vertList:\n", + " nv = self.addVertex(f)\n", + " if t not in self.vertList:\n", + " nv = self.addVertex(t)\n", + " self.vertList[f].addNeighbor(self.vertList[t], cost)\n", + "\n", + " def getVertices(self):\n", + " return self.vertList.keys()\n", + "\n", + " def __iter__(self):\n", + " return iter(self.vertList.values())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Code for buildGraph function:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def buildGraph(wordFile):\n", + " d = {}\n", + " g = Graph()\n", + " \n", + " wfile = open(wordFile,'r')\n", + " # create buckets of words that differ by one letter\n", + " for line in wfile:\n", + " print line\n", + " word = line[:-1]\n", + " print word\n", + " for i in range(len(word)):\n", + " bucket = word[:i] + '_' + word[i+1:]\n", + " if bucket in d:\n", + " d[bucket].append(word)\n", + " else:\n", + " d[bucket] = [word]\n", + " # add vertices and edges for words in the same bucket\n", + " for bucket in d.keys():\n", + " for word1 in d[bucket]:\n", + " for word2 in d[bucket]:\n", + " if word1 != word2:\n", + " g.addEdge(word1,word2)\n", + " return g" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Please reference the video for full explanation!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement Breadth First Search Algorithm-checkpoint.ipynb b/Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement Breadth First Search Algorithm-checkpoint.ipynb new file mode 100644 index 00000000..039d98f3 --- /dev/null +++ b/Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement Breadth First Search Algorithm-checkpoint.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Breadth First Search Algorithm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this problem, implement a BFS Algorithm! You can assume that the graph is in the simplified form:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement Depth First Search Algorithm-checkpoint.ipynb b/Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement Depth First Search Algorithm-checkpoint.ipynb new file mode 100644 index 00000000..94da601e --- /dev/null +++ b/Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement Depth First Search Algorithm-checkpoint.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Depth First Search Algorithm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this problem, implement a DFS Algorithm! You can assume that the graph is in the simplified form:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Graph-checkpoint.ipynb b/Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Graph-checkpoint.ipynb new file mode 100644 index 00000000..b6362791 --- /dev/null +++ b/Graphs/Graph Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Graph-checkpoint.ipynb @@ -0,0 +1,45 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Graph Class!\n", + "\n", + "That's it! \n", + "\n", + "Best of luck and reference the video lecture for any questions!\n", + "\n", + "You have to fully worked out implementations in the lectures, so make sure to refer to them!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions - PRACTICE/Implement Breadth First Search Algorithm.ipynb b/Graphs/Graph Interview Questions - PRACTICE/Implement Breadth First Search Algorithm.ipynb new file mode 100644 index 00000000..039d98f3 --- /dev/null +++ b/Graphs/Graph Interview Questions - PRACTICE/Implement Breadth First Search Algorithm.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Breadth First Search Algorithm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this problem, implement a BFS Algorithm! You can assume that the graph is in the simplified form:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions - PRACTICE/Implement Depth First Search Algorithm.ipynb b/Graphs/Graph Interview Questions - PRACTICE/Implement Depth First Search Algorithm.ipynb new file mode 100644 index 00000000..94da601e --- /dev/null +++ b/Graphs/Graph Interview Questions - PRACTICE/Implement Depth First Search Algorithm.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Depth First Search Algorithm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this problem, implement a DFS Algorithm! You can assume that the graph is in the simplified form:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions - PRACTICE/Implement a Graph.ipynb b/Graphs/Graph Interview Questions - PRACTICE/Implement a Graph.ipynb new file mode 100644 index 00000000..513c78ef --- /dev/null +++ b/Graphs/Graph Interview Questions - PRACTICE/Implement a Graph.ipynb @@ -0,0 +1,223 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Graph Class!\n", + "\n", + "That's it! \n", + "\n", + "Best of luck and reference the video lecture for any questions!\n", + "\n", + "You have to fully worked out implementations in the lectures, so make sure to refer to them!" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "class Graph:\n", + " '''\n", + " In order to implement a Graph as an Adjacency List what we need to do is define the methods our Adjacency List object will have:\n", + " Graph() creates a new, empty graph.\n", + " addVertex(vert) adds an instance of Vertex to the graph.\n", + " addEdge(fromVert, toVert) Adds a new, directed edge to the graph that connects two vertices.\n", + " addEdge(fromVert, toVert, weight) Adds a new, weighted, directed edge to the graph that connects two vertices.\n", + " getVertex(vertKey) finds the vertex in the graph named vertKey.\n", + " getVertices() returns the list of all vertices in the graph.\n", + " in returns True for a statement of the form vertex in graph, if the given vertex is in the graph, False otherwise.\n", + " '''\n", + " def __init__(self):\n", + "# self.nodes = set() # all the vertexes in the graph -- could be done in the edges part\n", + " self.connections = {} # all the connections start_vertex:{end_vertex:weigth}\n", + " \n", + "# def add_node(self, node):\n", + "# self.nodes.add(node)\n", + " \n", + " def contains(self, v):\n", + " return v in self.connections.keys()\n", + " \n", + " def connect(self, start, end, weight=1):\n", + "# v = self.get_vertex(str(from_vertex)) or Vertex(str(from_vertex))\n", + " if start not in self.connections:\n", + " self.connections[start] = {end:weight} \n", + " else:\n", + " self.connections[start][end] = weight\n", + " \n", + " if end not in self.connections:\n", + " self.connections[end] = {}\n", + "\n", + " def get_nodes(self):\n", + " return self.connections.keys()\n", + " \n", + "# assume there is one and only one start node (no one points to it) in the directed graph\n", + " def get_start_vertex(self):\n", + " cadidates = set(self.get_nodes())\n", + " for end in self.connections.values():\n", + " for k in end.keys():\n", + " if k in cadidates:\n", + " cadidates.remove(k)\n", + "# return set(self.get_nodes()) - set(end_nodes)\n", + " return cadidates\n", + " \n", + " def paint(self):\n", + " print(self.connections)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "g = Graph()\n", + "# v1 = Node(1)\n", + "g.connect(1, 2)\n", + "\n", + "g.connect(1,3)\n", + "g.connect(1,4)\n", + "g.connect(2,4)\n", + "g.connect(2,5)\n", + "g.connect(3,5)\n", + "g.connect(5,4)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1: {2: 1, 3: 1, 4: 1}, 2: {4: 1, 5: 1}, 3: {5: 1}, 4: {}, 5: {4: 1}}\n" + ] + } + ], + "source": [ + "g.paint()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys([1, 2, 3, 4, 5])" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "g.get_nodes()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "g.get_start_vertex()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "set" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(g.get_start_vertex())" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "s = set([1,2,3])" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1, 2, 3}" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement Breadth First Search Algorithm-checkpoint.ipynb b/Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement Breadth First Search Algorithm-checkpoint.ipynb new file mode 100644 index 00000000..039d98f3 --- /dev/null +++ b/Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement Breadth First Search Algorithm-checkpoint.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Breadth First Search Algorithm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this problem, implement a BFS Algorithm! You can assume that the graph is in the simplified form:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement Depth First Search Algorithm-checkpoint.ipynb b/Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement Depth First Search Algorithm-checkpoint.ipynb new file mode 100644 index 00000000..94da601e --- /dev/null +++ b/Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement Depth First Search Algorithm-checkpoint.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Depth First Search Algorithm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this problem, implement a DFS Algorithm! You can assume that the graph is in the simplified form:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement a Graph-checkpoint.ipynb b/Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement a Graph-checkpoint.ipynb new file mode 100644 index 00000000..b6362791 --- /dev/null +++ b/Graphs/Graph Interview Questions/.ipynb_checkpoints/Implement a Graph-checkpoint.ipynb @@ -0,0 +1,45 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Graph Class!\n", + "\n", + "That's it! \n", + "\n", + "Best of luck and reference the video lecture for any questions!\n", + "\n", + "You have to fully worked out implementations in the lectures, so make sure to refer to them!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions/Implement Breadth First Search Algorithm.ipynb b/Graphs/Graph Interview Questions/Implement Breadth First Search Algorithm.ipynb new file mode 100644 index 00000000..55bd824b --- /dev/null +++ b/Graphs/Graph Interview Questions/Implement Breadth First Search Algorithm.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Breadth First Search Algorithm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this problem, implement a BFS Algorithm! You can assume that the graph is in the simplified form:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Graphs/Graph Interview Questions/Implement Depth First Search Algorithm.ipynb b/Graphs/Graph Interview Questions/Implement Depth First Search Algorithm.ipynb new file mode 100644 index 00000000..94da601e --- /dev/null +++ b/Graphs/Graph Interview Questions/Implement Depth First Search Algorithm.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Depth First Search Algorithm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For this problem, implement a DFS Algorithm! You can assume that the graph is in the simplified form:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Graph Interview Questions/Implement a Graph.ipynb b/Graphs/Graph Interview Questions/Implement a Graph.ipynb new file mode 100644 index 00000000..b6362791 --- /dev/null +++ b/Graphs/Graph Interview Questions/Implement a Graph.ipynb @@ -0,0 +1,45 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Graph Class!\n", + "\n", + "That's it! \n", + "\n", + "Best of luck and reference the video lecture for any questions!\n", + "\n", + "You have to fully worked out implementations in the lectures, so make sure to refer to them!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Implementation of Adjacency List.ipynb b/Graphs/Implementation of Adjacency List.ipynb new file mode 100644 index 00000000..e415ad5e --- /dev/null +++ b/Graphs/Implementation of Adjacency List.ipynb @@ -0,0 +1,229 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of a Graph as an Adjacency List\n", + "\n", + "\n", + "Using dictionaries, it is easy to implement the adjacency list in Python. In our implementation of the Graph abstract data type we will create two classes: **Graph**, which holds the master list of vertices, and **Vertex**, which will represent each vertex in the graph.\n", + "\n", + "Each Vertex uses a dictionary to keep track of the vertices to which it is connected, and the weight of each edge. This dictionary is called **connectedTo**. The constructor simply initializes the id, which will typically be a string, and the **connectedTo** dictionary. The **addNeighbor** method is used add a connection from this vertex to another. The **getConnections** method returns all of the vertices in the adjacency list, as represented by the **connectedTo** instance variable. The **getWeight** method returns the weight of the edge from this vertex to the vertex passed as a parameter." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Vertex:\n", + " def __init__(self,key):\n", + " self.id = key\n", + " self.connectedTo = {}\n", + "\n", + " def addNeighbor(self,nbr,weight=0):\n", + " self.connectedTo[nbr] = weight\n", + "\n", + " def __str__(self):\n", + " return str(self.id) + ' connectedTo: ' + str([x.id for x in self.connectedTo])\n", + "\n", + " def getConnections(self):\n", + " return self.connectedTo.keys()\n", + "\n", + " def getId(self):\n", + " return self.id\n", + "\n", + " def getWeight(self,nbr):\n", + " return self.connectedTo[nbr]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "In order to implement a Graph as an Adjacency List what we need to do is define the methods our Adjacency List object will have:\n", + "\n", + "* **Graph()** creates a new, empty graph.\n", + "* **addVertex(vert)** adds an instance of Vertex to the graph.\n", + "* **addEdge(fromVert, toVert)** Adds a new, directed edge to the graph that connects two vertices.\n", + "* **addEdge(fromVert, toVert, weight)** Adds a new, weighted, directed edge to the graph that connects two vertices.\n", + "* **getVertex(vertKey)** finds the vertex in the graph named vertKey.\n", + "* **getVertices()** returns the list of all vertices in the graph. \n", + "* **in** returns True for a statement of the form vertex in graph, if the given vertex is in the graph, False otherwise." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Graph:\n", + " def __init__(self):\n", + " self.vertList = {}\n", + " self.numVertices = 0\n", + "\n", + " def addVertex(self,key):\n", + " self.numVertices = self.numVertices + 1\n", + " newVertex = Vertex(key)\n", + " self.vertList[key] = newVertex\n", + " return newVertex\n", + "\n", + " def getVertex(self,n):\n", + " if n in self.vertList:\n", + " return self.vertList[n]\n", + " else:\n", + " return None\n", + "\n", + " def __contains__(self,n):\n", + " return n in self.vertList\n", + "\n", + " def addEdge(self,f,t,cost=0):\n", + " if f not in self.vertList:\n", + " nv = self.addVertex(f)\n", + " if t not in self.vertList:\n", + " nv = self.addVertex(t)\n", + " self.vertList[f].addNeighbor(self.vertList[t], cost)\n", + "\n", + " def getVertices(self):\n", + " return self.vertList.keys()\n", + "\n", + " def __iter__(self):\n", + " return iter(self.vertList.values())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see a simple example of how to use this:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "g = Graph()\n", + "for i in range(6):\n", + " g.addVertex(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{0: <__main__.Vertex instance at 0x10476b680>,\n", + " 1: <__main__.Vertex instance at 0x104cce5f0>,\n", + " 2: <__main__.Vertex instance at 0x10395d950>,\n", + " 3: <__main__.Vertex instance at 0x1039c00e0>,\n", + " 4: <__main__.Vertex instance at 0x1039c4e60>,\n", + " 5: <__main__.Vertex instance at 0x1039c45f0>}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "g.vertList" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "g.addEdge(0,1,2)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 connectedTo: [1]\n", + "[<__main__.Vertex instance at 0x104cce5f0>]\n", + "\n", + "\n", + "1 connectedTo: []\n", + "[]\n", + "\n", + "\n", + "2 connectedTo: []\n", + "[]\n", + "\n", + "\n", + "3 connectedTo: []\n", + "[]\n", + "\n", + "\n", + "4 connectedTo: []\n", + "[]\n", + "\n", + "\n", + "5 connectedTo: []\n", + "[]\n", + "\n", + "\n" + ] + } + ], + "source": [ + "for vertex in g:\n", + " print vertex\n", + " print vertex.getConnections()\n", + " print '\\n'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Great Job!" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Graphs/Implementation of Breadth First Search.ipynb b/Graphs/Implementation of Breadth First Search.ipynb new file mode 100644 index 00000000..185b0183 --- /dev/null +++ b/Graphs/Implementation of Breadth First Search.ipynb @@ -0,0 +1,176 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Implementation of Breadth First Search\n", + "\n", + "\n", + "An alternative algorithm called Breath-First search provides us with the ability to return the same results as DFS but with the added guarantee to return the shortest-path first. This algorithm is a little more tricky to implement in a recursive manner instead using the queue data-structure, as such I will only being documenting the iterative approach. The actions performed per each explored vertex are the same as the depth-first implementation, however, replacing the stack with a queue will instead explore the breadth of a vertex depth before moving on. This behavior guarantees that the first path located is one of the shortest-paths present, based on number of edges being the cost factor.\n", + "\n", + "We'll assume our Graph is in the form:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Connected Component\n", + "Similar to the iterative DFS implementation the only alteration required is to remove the next item from the beginning of the list structure instead of the stacks last." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'A', 'B', 'C', 'D', 'E', 'F'}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def bfs(graph, start):\n", + " visited, queue = set(), [start]\n", + " while queue:\n", + " vertex = queue.pop(0)\n", + " if vertex not in visited:\n", + " visited.add(vertex)\n", + " queue.extend(graph[vertex] - visited)\n", + " return visited\n", + "\n", + "bfs(graph, 'A')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Paths\n", + "This implementation can again be altered slightly to instead return all possible paths between two vertices, the first of which being one of the shortest such path." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['A', 'C', 'F'], ['A', 'B', 'E', 'F']]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def bfs_paths(graph, start, goal):\n", + " queue = [(start, [start])]\n", + " while queue:\n", + " (vertex, path) = queue.pop(0)\n", + " for next in graph[vertex] - set(path):\n", + " if next == goal:\n", + " yield path + [next]\n", + " else:\n", + " queue.append((next, path + [next]))\n", + "\n", + "list(bfs_paths(graph, 'A', 'F'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Knowing that the shortest path will be returned first from the BFS path generator method we can create a useful method which simply returns the shortest path found or ‘None’ if no path exists. As we are using a generator this in theory should provide similar performance results as just breaking out and returning the first matching path in the BFS implementation." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['A', 'C', 'F']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def shortest_path(graph, start, goal):\n", + " try:\n", + " return next(bfs_paths(graph, start, goal))\n", + " except StopIteration:\n", + " return None\n", + "\n", + "shortest_path(graph, 'A', 'F')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resources\n", + "* [Depth-and Breadth-First Search](http://jeremykun.com/2013/01/22/depth-and-breadth-first-search/)\n", + "* [Connected component](https://en.wikipedia.org/wiki/Connected_component_(graph_theory))\n", + "* [Adjacency matrix](https://en.wikipedia.org/wiki/Adjacency_matrix)\n", + "* [Adjacency list](https://en.wikipedia.org/wiki/Adjacency_list)\n", + "* [Python Gotcha: Default arguments and mutable data structures](https://developmentality.wordpress.com/2010/08/23/python-gotcha-default-arguments/)\n", + "* [Generators](https://wiki.python.org/moin/Generators)" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Graphs/Implementation of Depth First Search.ipynb b/Graphs/Implementation of Depth First Search.ipynb new file mode 100644 index 00000000..c111e89d --- /dev/null +++ b/Graphs/Implementation of Depth First Search.ipynb @@ -0,0 +1,178 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Depth-First Search\n", + "This algorithm we will be discussing is Depth-First search which as the name hints at, explores possible vertices (from a supplied root) down each branch before backtracking. This property allows the algorithm to be implemented succinctly in both iterative and recursive forms. Below is a listing of the actions performed upon each visit to a node.\n", + "\n", + "* Mark the current vertex as being visited.\n", + "* Explore each adjacent vertex that is not included in the visited set.\n", + "\n", + "We will assume a simplified version of a graph in the following form:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "graph = {'A': set(['B', 'C']),\n", + " 'B': set(['A', 'D', 'E']),\n", + " 'C': set(['A', 'F']),\n", + " 'D': set(['B']),\n", + " 'E': set(['B', 'F']),\n", + " 'F': set(['C', 'E'])}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Connected Component\n", + "\n", + "The implementation below uses the stack data-structure to build-up and return a set of vertices that are accessible within the subjects connected component. Using Python’s overloading of the subtraction operator to remove items from a set, we are able to add only the unvisited adjacent vertices." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'A', 'B', 'C', 'D', 'E', 'F'}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def dfs(graph, start):\n", + " visited, stack = set(), [start]\n", + " while stack:\n", + " vertex = stack.pop()\n", + " if vertex not in visited:\n", + " visited.add(vertex)\n", + " stack.extend(graph[vertex] - visited)\n", + " return visited\n", + "\n", + "dfs(graph, 'A') " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The second implementation provides the same functionality as the first, however, this time we are using the more succinct recursive form. Due to a common Python gotcha with default parameter values being created only once, we are required to create a new visited set on each user invocation. Another Python language detail is that function variables are passed by reference, resulting in the visited mutable set not having to reassigned upon each recursive call." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'A', 'B', 'C', 'D', 'E', 'F'}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def dfs(graph, start, visited=None):\n", + " if visited is None:\n", + " visited = set()\n", + " visited.add(start)\n", + " for nxt in graph[start] - visited:\n", + " dfs(graph, nxt, visited)\n", + " return visited\n", + "\n", + "dfs(graph, 'A') " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Paths\n", + "We are able to tweak both of the previous implementations to return all possible paths between a start and goal vertex. The implementation below uses the stack data-structure again to iteratively solve the problem, yielding each possible path when we locate the goal. Using a generator allows the user to only compute the desired amount of alternative paths." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['A', 'B', 'E', 'F'], ['A', 'C', 'F']]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def dfs_paths(graph, start, goal):\n", + " stack = [(start, [start])]\n", + " while stack:\n", + " (vertex, path) = stack.pop()\n", + " for nxt in graph[vertex] - set(path):\n", + " if nxt == goal:\n", + " yield path + [nxt]\n", + " else:\n", + " stack.append((nxt, path + [nxt]))\n", + "\n", + "list(dfs_paths(graph, 'A', 'F'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Resources\n", + "* [Depth-and Breadth-First Search](http://jeremykun.com/2013/01/22/depth-and-breadth-first-search/)\n", + "* [Connected component](https://en.wikipedia.org/wiki/Connected_component_(graph_theory))\n", + "* [Adjacency matrix](https://en.wikipedia.org/wiki/Adjacency_matrix)\n", + "* [Adjacency list](https://en.wikipedia.org/wiki/Adjacency_list)\n", + "* [Python Gotcha: Default arguments and mutable data structures](https://developmentality.wordpress.com/2010/08/23/python-gotcha-default-arguments/)\n", + "* [Generators](https://wiki.python.org/moin/Generators)" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Graphs/Implementation of Graph Overview.ipynb b/Graphs/Implementation of Graph Overview.ipynb new file mode 100644 index 00000000..3363f9a8 --- /dev/null +++ b/Graphs/Implementation of Graph Overview.ipynb @@ -0,0 +1,156 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Graph Overview\n", + "\n", + "In this lecture we will implement a simple graph by focusing on the Node class. Refer to this lecture for the solution to the Interview Problem\n", + "\n", + "___\n", + "The graph will be directed and the edges can hold weights.\n", + "\n", + "We will have three classes, a State class, a Node class, and finally the Graph class.\n", + "\n", + "We're going to be taking advantage of two built-in tools here, [OrderDict](https://docs.python.org/2/library/collections.html#collections.OrderedDict) and [Enum](https://docs.python.org/3/library/enum.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from enum import Enum \n", + "\n", + "class State(Enum):\n", + " unvisited = 1 #White\n", + " visited = 2 #Black\n", + " visiting = 3 #Gray" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now for the Node class we will take advantage of the OrderedDict object in case we want to keep trak of the order keys are added to the dictionary." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from collections import OrderedDict\n", + "\n", + "class Node:\n", + "\n", + " def __init__(self, num):\n", + " self.num = num\n", + " self.visit_state = State.unvisited\n", + " self.adjacent = OrderedDict() # key = node, val = weight\n", + "\n", + " def __str__(self):\n", + " return str(self.num)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then finally the Graph:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Graph:\n", + "\n", + " def __init__(self):\n", + " self.nodes = OrderedDict() # key = node id, val = node\n", + "\n", + " def add_node(self, num):\n", + " node = Node(num)\n", + " self.nodes[num] = node\n", + " return node\n", + "\n", + " def add_edge(self, source, dest, weight=0):\n", + " if source not in self.nodes:\n", + " self.add_node(source)\n", + " if dest not in self.nodes:\n", + " self.add_node(dest)\n", + " self.nodes[source].adjacent[self.nodes[dest]] = weight" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "g = Graph()\n", + "g.add_edge(0, 1, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "OrderedDict([(0, <__main__.Node instance at 0x103a761b8>),\n", + " (1, <__main__.Node instance at 0x104dfef80>)])" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "g.nodes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Great Job!" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Graphs/Knight's Tour Example Problem.ipynb b/Graphs/Knight's Tour Example Problem.ipynb new file mode 100644 index 00000000..1504a502 --- /dev/null +++ b/Graphs/Knight's Tour Example Problem.ipynb @@ -0,0 +1,113 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Knight's Tour Code\n", + "\n", + "** Below is th ecode referenced in the video lecture. Please refer to the video lectures for full explanation.**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def knightGraph(bdSize):\n", + " ktGraph = Graph()\n", + " for row in range(bdSize):\n", + " for col in range(bdSize):\n", + " nodeId = posToNodeId(row,col,bdSize)\n", + " newPositions = genLegalMoves(row,col,bdSize)\n", + " for e in newPositions:\n", + " nid = posToNodeId(e[0],e[1],bdSize)\n", + " ktGraph.addEdge(nodeId,nid)\n", + " return ktGraph\n", + "\n", + "def posToNodeId(row, column, board_size):\n", + " return (row * board_size) + column\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def genLegalMoves(x,y,bdSize):\n", + " newMoves = []\n", + " moveOffsets = [(-1,-2),(-1,2),(-2,-1),(-2,1),\n", + " ( 1,-2),( 1,2),( 2,-1),( 2,1)]\n", + " for i in moveOffsets:\n", + " newX = x + i[0]\n", + " newY = y + i[1]\n", + " if legalCoord(newX,bdSize) and \\\n", + " legalCoord(newY,bdSize):\n", + " newMoves.append((newX,newY))\n", + " return newMoves\n", + "\n", + "def legalCoord(x,bdSize):\n", + " if x >= 0 and x < bdSize:\n", + " return True\n", + " else:\n", + " return False" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def knightTour(n,path,u,limit):\n", + " u.setColor('gray')\n", + " path.append(u)\n", + " if n < limit:\n", + " nbrList = list(u.getConnections())\n", + " i = 0\n", + " done = False\n", + " while i < len(nbrList) and not done:\n", + " if nbrList[i].getColor() == 'white':\n", + " done = knightTour(n+1, path, nbrList[i], limit)\n", + " i = i + 1\n", + " if not done: # prepare to backtrack\n", + " path.pop()\n", + " u.setColor('white')\n", + " else:\n", + " done = True\n", + " return done" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/Word Ladder Example Problem.ipynb b/Graphs/Word Ladder Example Problem.ipynb new file mode 100644 index 00000000..a90aefdd --- /dev/null +++ b/Graphs/Word Ladder Example Problem.ipynb @@ -0,0 +1,154 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Word Ladder Example Code\n", + "\n", + "Below is the Vertex and Graph class used for the Word Ladder example code:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Vertex:\n", + " def __init__(self,key):\n", + " self.id = key\n", + " self.connectedTo = {}\n", + "\n", + " def addNeighbor(self,nbr,weight=0):\n", + " self.connectedTo[nbr] = weight\n", + "\n", + " def __str__(self):\n", + " return str(self.id) + ' connectedTo: ' + str([x.id for x in self.connectedTo])\n", + "\n", + " def getConnections(self):\n", + " return self.connectedTo.keys()\n", + "\n", + " def getId(self):\n", + " return self.id\n", + "\n", + " def getWeight(self,nbr):\n", + " return self.connectedTo[nbr]" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Graph:\n", + " def __init__(self):\n", + " self.vertList = {}\n", + " self.numVertices = 0\n", + "\n", + " def addVertex(self,key):\n", + " self.numVertices = self.numVertices + 1\n", + " newVertex = Vertex(key)\n", + " self.vertList[key] = newVertex\n", + " return newVertex\n", + "\n", + " def getVertex(self,n):\n", + " if n in self.vertList:\n", + " return self.vertList[n]\n", + " else:\n", + " return None\n", + "\n", + " def __contains__(self,n):\n", + " return n in self.vertList\n", + "\n", + " def addEdge(self,f,t,cost=0):\n", + " if f not in self.vertList:\n", + " nv = self.addVertex(f)\n", + " if t not in self.vertList:\n", + " nv = self.addVertex(t)\n", + " self.vertList[f].addNeighbor(self.vertList[t], cost)\n", + "\n", + " def getVertices(self):\n", + " return self.vertList.keys()\n", + "\n", + " def __iter__(self):\n", + " return iter(self.vertList.values())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Code for buildGraph function:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def buildGraph(wordFile):\n", + " d = {}\n", + " g = Graph()\n", + " \n", + " wfile = open(wordFile,'r')\n", + " # create buckets of words that differ by one letter\n", + " for line in wfile:\n", + " print line\n", + " word = line[:-1]\n", + " print word\n", + " for i in range(len(word)):\n", + " bucket = word[:i] + '_' + word[i+1:]\n", + " if bucket in d:\n", + " d[bucket].append(word)\n", + " else:\n", + " d[bucket] = [word]\n", + " # add vertices and edges for words in the same bucket\n", + " for bucket in d.keys():\n", + " for word1 in d[bucket]:\n", + " for word2 in d[bucket]:\n", + " if word1 != word2:\n", + " g.addEdge(word1,word2)\n", + " return g" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Please reference the video for full explanation!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Graphs/words.txt b/Graphs/words.txt new file mode 100644 index 00000000..0c2fba05 --- /dev/null +++ b/Graphs/words.txt @@ -0,0 +1,6 @@ +pope +rope +sage +best +ripe +pipe \ No newline at end of file diff --git a/Linked Lists/.ipynb_checkpoints/Doubly Linked List Implementation-checkpoint.ipynb b/Linked Lists/.ipynb_checkpoints/Doubly Linked List Implementation-checkpoint.ipynb new file mode 100644 index 00000000..d409f9d3 --- /dev/null +++ b/Linked Lists/.ipynb_checkpoints/Doubly Linked List Implementation-checkpoint.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Doubly Linked List Implementation\n", + "\n", + "In this lecture we will implement a Doubly Linked List " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class DoublyLinkedListNode(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.next_node = None\n", + " self.prev_node = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have our node that can reference next *and* previous values, let's begin to build out our linked list!" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a = DoublyLinkedListNode(1)\n", + "b = DoublyLinkedListNode(2)\n", + "c = DoublyLinkedListNode(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting b after a\n", + "b.prev_node = a\n", + "a.next_node = b" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting c after a\n", + "b.next_node = c\n", + "c.prev_node = b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Having a Doubly Linked list allows us to go though our Linked List forwards **and** backwards." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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 +} diff --git a/Linked Lists/.ipynb_checkpoints/Doubly Linked Lists-checkpoint.ipynb b/Linked Lists/.ipynb_checkpoints/Doubly Linked Lists-checkpoint.ipynb new file mode 100644 index 00000000..929355be --- /dev/null +++ b/Linked Lists/.ipynb_checkpoints/Doubly Linked Lists-checkpoint.ipynb @@ -0,0 +1,34 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Doubly Linked Lists\n", + "\n", + "**Please refer to the video lecture for the full explanation of the Doubly Linked Lists**" + ] + } + ], + "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 +} diff --git a/Linked Lists/.ipynb_checkpoints/Linked List Overview-checkpoint.ipynb b/Linked Lists/.ipynb_checkpoints/Linked List Overview-checkpoint.ipynb new file mode 100644 index 00000000..16a79138 --- /dev/null +++ b/Linked Lists/.ipynb_checkpoints/Linked List Overview-checkpoint.ipynb @@ -0,0 +1,42 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked Lists\n", + "\n", + "In this lecture we will get a brief overview of what we will learn in the Linked List section of this course.\n", + "\n", + "We will cover the following topics:\n", + "\n", + "* Singly Linked Lists\n", + "* Implementing a Singly Linked List\n", + "* Doubly Linked Lists\n", + "* Implementing a Doubly Linked list\n", + "* Linked Lists Interview Problems" + ] + } + ], + "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 +} diff --git a/Linked Lists/.ipynb_checkpoints/Singly Linked List Implementation-checkpoint.ipynb b/Linked Lists/.ipynb_checkpoints/Singly Linked List Implementation-checkpoint.ipynb new file mode 100644 index 00000000..efa1ee5c --- /dev/null +++ b/Linked Lists/.ipynb_checkpoints/Singly Linked List Implementation-checkpoint.ipynb @@ -0,0 +1,120 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Singly Linked List Implementation\n", + "\n", + "In this lecture we will implement a basic Singly Linked List.\n", + "\n", + "Remember, in a singly linked list, we have an ordered list of items as individual Nodes that have pointers to other Nodes." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can build out Linked List with the collection of nodes:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a.nextnode = b" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "b.nextnode = c" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In a Linked List the first node is called the **head** and the last node is called the **tail**. Let's discuss the pros and cons of Linked Lists:\n", + "\n", + "## Pros\n", + "\n", + "* Linked Lists have constant-time insertions and deletions in any position, in comparison, arrays require O(n) time to do the same thing.\n", + "\n", + "* Linked lists can continue to expand without having to specify their size ahead of time (remember our lectures on Array sizing form the Array Sequence section of the course!)\n", + "\n", + "## Cons\n", + "\n", + "* To access an element in a linked list, you need to take O(k) time to go from the head of the list to the kth element. In contrast, arrays have constant time operations to access elements in an array." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!\n", + "\n", + "That's it for the implementation (pretty simple right?). Up next we will learn about Doubly Linked Lists!" + ] + } + ], + "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 +} diff --git a/Linked Lists/.ipynb_checkpoints/Singly Linked Lists-checkpoint.ipynb b/Linked Lists/.ipynb_checkpoints/Singly Linked Lists-checkpoint.ipynb new file mode 100644 index 00000000..f0f1677d --- /dev/null +++ b/Linked Lists/.ipynb_checkpoints/Singly Linked Lists-checkpoint.ipynb @@ -0,0 +1,36 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Singly Linked Lists\n", + "\n", + "**Please refer to the Lecture Video for full Explanation of Singly Linked Lists**" + ] + } + ], + "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 +} diff --git a/Linked Lists/Doubly Linked List Implementation.ipynb b/Linked Lists/Doubly Linked List Implementation.ipynb new file mode 100644 index 00000000..d409f9d3 --- /dev/null +++ b/Linked Lists/Doubly Linked List Implementation.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Doubly Linked List Implementation\n", + "\n", + "In this lecture we will implement a Doubly Linked List " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class DoublyLinkedListNode(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.next_node = None\n", + " self.prev_node = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have our node that can reference next *and* previous values, let's begin to build out our linked list!" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a = DoublyLinkedListNode(1)\n", + "b = DoublyLinkedListNode(2)\n", + "c = DoublyLinkedListNode(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting b after a\n", + "b.prev_node = a\n", + "a.next_node = b" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting c after a\n", + "b.next_node = c\n", + "c.prev_node = b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Having a Doubly Linked list allows us to go though our Linked List forwards **and** backwards." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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 +} diff --git a/Linked Lists/Doubly Linked Lists.ipynb b/Linked Lists/Doubly Linked Lists.ipynb new file mode 100644 index 00000000..929355be --- /dev/null +++ b/Linked Lists/Doubly Linked Lists.ipynb @@ -0,0 +1,34 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Doubly Linked Lists\n", + "\n", + "**Please refer to the video lecture for the full explanation of the Doubly Linked Lists**" + ] + } + ], + "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 +} diff --git a/Linked Lists/Linked List Overview.ipynb b/Linked Lists/Linked List Overview.ipynb new file mode 100644 index 00000000..16a79138 --- /dev/null +++ b/Linked Lists/Linked List Overview.ipynb @@ -0,0 +1,42 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked Lists\n", + "\n", + "In this lecture we will get a brief overview of what we will learn in the Linked List section of this course.\n", + "\n", + "We will cover the following topics:\n", + "\n", + "* Singly Linked Lists\n", + "* Implementing a Singly Linked List\n", + "* Doubly Linked Lists\n", + "* Implementing a Doubly Linked list\n", + "* Linked Lists Interview Problems" + ] + } + ], + "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 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Implement a Doubly Linked List-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Implement a Doubly Linked List-checkpoint.ipynb new file mode 100644 index 00000000..789493fe --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Implement a Doubly Linked List-checkpoint.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Doubly Linked List\n", + "\n", + "For this interview problem, implement a node class and show how it can be used to create a doubly linked list." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "class Node(object):\n", + " def __init__(self, value):\n", + " self.prev = None\n", + " self.val = value\n", + " self.next = None\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a Doubly Linked List here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "Note that there is no test for this solution (because it would give away the answer structure).\n", + "\n", + "Check out the Implement a Linked List Solution Notebook for the answer to this interview problem, as well as the answer for the implementation of a singly linked list." + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Implement a Singly Linked List-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Implement a Singly Linked List-checkpoint.ipynb new file mode 100644 index 00000000..340116ee --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Implement a Singly Linked List-checkpoint.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Singly Linked List\n", + "\n", + "For this interview problem, create a node class and show how it can be used to create a Singly Linked List" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "class Node(object):\n", + " def __init__(self, value):\n", + " self.val = value\n", + " self.next = None\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a Singly Linked List here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Note that there is no test for this solution (because it would give away the answer structure).\n", + "\n", + "Check out the Implement a Linked List Solution Notebook for the answer to this interview problem, as well as the answer for the implementation of a doubly linked list." + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Linked List Nth to Last Node -checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Linked List Nth to Last Node -checkpoint.ipynb new file mode 100644 index 00000000..83d1468a --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Linked List Nth to Last Node -checkpoint.ipynb @@ -0,0 +1,192 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Nth to Last Node \n", + "\n", + "## Problem Statement\n", + "Write a function that takes a head node and an integer value **n** and then returns the nth to last node in the linked list. For example, given:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "class Node:\n", + "\n", + " def __init__(self, value):\n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Example Input and Output:**" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "# This would return the node d with a value of 4, because its the 2nd to last node.\n", + "target_node = nth_to_last_node(2, a) " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_node.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def nth_to_last_node(n, head):\n", + " slow, fast = head, head\n", + " while n > 0 and fast:\n", + " fast=fast.nextnode\n", + " n-=1\n", + " if not fast:\n", + " return head\n", + " while fast:\n", + " fast=fast.nextnode\n", + " slow=slow.nextnode\n", + " return slow\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION AGAINST A TEST CASE \n", + "\n", + "PLEASE NOTE THIS IS JUST ONE CASE\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "####\n", + "\n", + "class TestNLast(object):\n", + " \n", + " def test(self,sol):\n", + " \n", + " assert_equal(sol(2,a),d)\n", + " print ('ALL TEST CASES PASSED')\n", + " \n", + "# Run tests\n", + "t = TestNLast()\n", + "t.test(nth_to_last_node)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Linked List Reversal -checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Linked List Reversal -checkpoint.ipynb new file mode 100644 index 00000000..d6d333eb --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Linked List Reversal -checkpoint.ipynb @@ -0,0 +1,244 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Reversal \n", + "\n", + "## Problem\n", + "\n", + "Write a function to reverse a Linked List in place. The function will take in the head of the list as input and return the new head of the list.\n", + "\n", + "You are given the example Linked List Node class:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def reverse(head):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "**Note, this isn't a classic run cell for testing your solution, please read the statements below carefully**\n", + "\n", + "You should be able to easily test your own solution to make sure it works. Given the short list a,b,c,d with values 1,2,3,4. Check the effect of your reverse function and make sure the results match the logic here below:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a list of 4 nodes\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "\n", + "# Set up order a,b,c,d with values 1,2,3,4\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's check the values of the nodes coming after a, b and c:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "print a.nextnode.value\n", + "print b.nextnode.value\n", + "print c.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "d.nextnode.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far so good. Note how there is no value proceeding the last node, this makes sense! Now let's reverse the linked list, we should see the opposite order of values!" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Node at 0x104bd7dd0>" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "2\n", + "1\n" + ] + } + ], + "source": [ + "print d.nextnode.value\n", + "print c.nextnode.value\n", + "print b.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mprint\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m \u001b[0;31m# This will give an error since it now points to None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "print a.nextnode.value # This will give an error since it now points to None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great, now we can see that each of the values points to its previous value (although now that the linked list is reversed we can see the ordering has also reversed)\n", + "\n", + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Singly Linked List Cycle Check-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Singly Linked List Cycle Check-checkpoint.ipynb new file mode 100644 index 00000000..157dd789 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/.ipynb_checkpoints/Singly Linked List Cycle Check-checkpoint.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Singly Linked List Cycle Check \n", + "\n", + "## Problem\n", + "\n", + "Given a singly linked list, write a function which takes in the first node in a singly linked list and returns a boolean indicating if the linked list contains a \"cycle\".\n", + "\n", + "A cycle is when a node's next point actually points back to a previous node in the list. This is also sometimes known as a circularly linked list.\n", + "\n", + "You've been given the Linked List Node class code:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def cycle_check(node):\n", + "# Use fast and slow pointer\n", + " fast, slow = node, node\n", + " while fast and fast.nextnode:\n", + " fast = fast.nextnode\n", + " if fast == slow:\n", + " return True\n", + " fast = fast.nextnode\n", + " slow = slow.nextnode\n", + " return False\n", + " pass #Your function should return a boolean" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "# CREATE CYCLE LIST\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = a # Cycle Here!\n", + "\n", + "\n", + "# CREATE NON CYCLE LIST\n", + "x = Node(1)\n", + "y = Node(2)\n", + "z = Node(3)\n", + "\n", + "x.nextnode = y\n", + "y.nextnode = z\n", + "\n", + "\n", + "#############\n", + "class TestCycleCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(a),True)\n", + " assert_equal(sol(x),False)\n", + " \n", + " print (\"ALL TEST CASES PASSED\")\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestCycleCheck()\n", + "t.test(cycle_check)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Implement a Doubly Linked List.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Implement a Doubly Linked List.ipynb new file mode 100644 index 00000000..789493fe --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Implement a Doubly Linked List.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Doubly Linked List\n", + "\n", + "For this interview problem, implement a node class and show how it can be used to create a doubly linked list." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "class Node(object):\n", + " def __init__(self, value):\n", + " self.prev = None\n", + " self.val = value\n", + " self.next = None\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a Doubly Linked List here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "Note that there is no test for this solution (because it would give away the answer structure).\n", + "\n", + "Check out the Implement a Linked List Solution Notebook for the answer to this interview problem, as well as the answer for the implementation of a singly linked list." + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Implement a Singly Linked List.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Implement a Singly Linked List.ipynb new file mode 100644 index 00000000..340116ee --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Implement a Singly Linked List.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Singly Linked List\n", + "\n", + "For this interview problem, create a node class and show how it can be used to create a Singly Linked List" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "class Node(object):\n", + " def __init__(self, value):\n", + " self.val = value\n", + " self.next = None\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a Singly Linked List here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Note that there is no test for this solution (because it would give away the answer structure).\n", + "\n", + "Check out the Implement a Linked List Solution Notebook for the answer to this interview problem, as well as the answer for the implementation of a doubly linked list." + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Linked List Nth to Last Node .ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Linked List Nth to Last Node .ipynb new file mode 100644 index 00000000..83d1468a --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Linked List Nth to Last Node .ipynb @@ -0,0 +1,192 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Nth to Last Node \n", + "\n", + "## Problem Statement\n", + "Write a function that takes a head node and an integer value **n** and then returns the nth to last node in the linked list. For example, given:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "class Node:\n", + "\n", + " def __init__(self, value):\n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Example Input and Output:**" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "# This would return the node d with a value of 4, because its the 2nd to last node.\n", + "target_node = nth_to_last_node(2, a) " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_node.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def nth_to_last_node(n, head):\n", + " slow, fast = head, head\n", + " while n > 0 and fast:\n", + " fast=fast.nextnode\n", + " n-=1\n", + " if not fast:\n", + " return head\n", + " while fast:\n", + " fast=fast.nextnode\n", + " slow=slow.nextnode\n", + " return slow\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION AGAINST A TEST CASE \n", + "\n", + "PLEASE NOTE THIS IS JUST ONE CASE\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "####\n", + "\n", + "class TestNLast(object):\n", + " \n", + " def test(self,sol):\n", + " \n", + " assert_equal(sol(2,a),d)\n", + " print ('ALL TEST CASES PASSED')\n", + " \n", + "# Run tests\n", + "t = TestNLast()\n", + "t.test(nth_to_last_node)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Linked List Reversal .ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Linked List Reversal .ipynb new file mode 100644 index 00000000..129617e9 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Linked List Reversal .ipynb @@ -0,0 +1,246 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Reversal \n", + "\n", + "## Problem\n", + "\n", + "Write a function to reverse a Linked List in place. The function will take in the head of the list as input and return the new head of the list.\n", + "\n", + "You are given the example Linked List Node class:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [], + "source": [ + "def reverse(head):\n", + " cur = head\n", + " pre, nxt = None, None\n", + " while cur:# watch out\n", + " nxt = cur.nextnode\n", + " cur.nextnode = pre\n", + " pre = cur\n", + " cur = nxt\n", + " return pre #watch out\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "**Note, this isn't a classic run cell for testing your solution, please read the statements below carefully**\n", + "\n", + "You should be able to easily test your own solution to make sure it works. Given the short list a,b,c,d with values 1,2,3,4. Check the effect of your reverse function and make sure the results match the logic here below:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a list of 4 nodes\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "\n", + "# Set up order a,b,c,d with values 1,2,3,4\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's check the values of the nodes coming after a, b and c:" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "print (a.nextnode.value)\n", + "print (b.nextnode.value)\n", + "print (c.nextnode.value)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "d.nextnode.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far so good. Note how there is no value proceeding the last node, this makes sense! Now let's reverse the linked list, we should see the opposite order of values!" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Node at 0x1067a2f28>" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "2\n", + "1\n" + ] + } + ], + "source": [ + "print (d.nextnode.value)\n", + "print (c.nextnode.value)\n", + "print (b.nextnode.value)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "Missing parentheses in call to 'print' (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m print a.nextnode.value # This will give an error since it now points to None\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m Missing parentheses in call to 'print'\n" + ] + } + ], + "source": [ + "print a.nextnode.value # This will give an error since it now points to None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great, now we can see that each of the values points to its previous value (although now that the linked list is reversed we can see the ordering has also reversed)\n", + "\n", + "## Good Job!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Singly Linked List Cycle Check.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Singly Linked List Cycle Check.ipynb new file mode 100644 index 00000000..157dd789 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - PRACTICE/Singly Linked List Cycle Check.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Singly Linked List Cycle Check \n", + "\n", + "## Problem\n", + "\n", + "Given a singly linked list, write a function which takes in the first node in a singly linked list and returns a boolean indicating if the linked list contains a \"cycle\".\n", + "\n", + "A cycle is when a node's next point actually points back to a previous node in the list. This is also sometimes known as a circularly linked list.\n", + "\n", + "You've been given the Linked List Node class code:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def cycle_check(node):\n", + "# Use fast and slow pointer\n", + " fast, slow = node, node\n", + " while fast and fast.nextnode:\n", + " fast = fast.nextnode\n", + " if fast == slow:\n", + " return True\n", + " fast = fast.nextnode\n", + " slow = slow.nextnode\n", + " return False\n", + " pass #Your function should return a boolean" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "# CREATE CYCLE LIST\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = a # Cycle Here!\n", + "\n", + "\n", + "# CREATE NON CYCLE LIST\n", + "x = Node(1)\n", + "y = Node(2)\n", + "z = Node(3)\n", + "\n", + "x.nextnode = y\n", + "y.nextnode = z\n", + "\n", + "\n", + "#############\n", + "class TestCycleCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(a),True)\n", + " assert_equal(sol(x),False)\n", + " \n", + " print (\"ALL TEST CASES PASSED\")\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestCycleCheck()\n", + "t.test(cycle_check)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Implement a Linked List -SOLUTION-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Implement a Linked List -SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..303ba52f --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Implement a Linked List -SOLUTION-checkpoint.ipynb @@ -0,0 +1,158 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Linked List - SOLUTION\n", + "\n", + "## Problem Statement\n", + "\n", + "Implement a Linked List by using a Node class object. Show how you would implement a Singly Linked List *and* a Doubly Linked List!\n", + "\n", + "## Solution\n", + "\n", + "Since this is asking the same thing as the implementation lectures, please refer to those video lectures and notes for a full explanation. The code from those lectures is displayed below:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Singly Linked List" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class LinkedListNode(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a = LinkedListNode(1)\n", + "b = LinkedListNode(2)\n", + "c = LinkedListNode(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a.nextnode = b\n", + "b.nextnode = c" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Doubly Linked List" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class DoublyLinkedListNode(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.next_node = None\n", + " self.prev_node = None" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a = DoublyLinkedListNode(1)\n", + "b = DoublyLinkedListNode(2)\n", + "c = DoublyLinkedListNode(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting b after a\n", + "b.prev_node = a\n", + "a.next_node = b" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting c after a\n", + "b.next_node = c\n", + "c.prev_node = b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Linked List Nth to Last Node - SOLUTION-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Linked List Nth to Last Node - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..457e6e48 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Linked List Nth to Last Node - SOLUTION-checkpoint.ipynb @@ -0,0 +1,210 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Nth to Last Node - SOLUTION\n", + "\n", + "## Problem Statement\n", + "Write a function that takes a head node and an integer value **n** and then returns the nth to last node in the linked list. For example, given:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node:\n", + "\n", + " def __init__(self, value):\n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "# This would return the node d with a value of 4, because its the 2nd to last node.\n", + "target_node = nth_to_last_node(2, a) " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_node.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "One approach to this problem is this:\n", + "\n", + "Imagine you have a bunch of nodes and a \"block\" which is n-nodes wide. We could walk this \"block\" all the way down the list, and once the front of the block reached the end, then the other end of the block would be a the Nth node! \n", + "\n", + "So to implement this \"block\" we would just have two pointers a left and right pair of pointers. Let's mark out the steps we will need to take:\n", + "\n", + "* Walk one pointer **n** nodes from the head, this will be the right_point\n", + "* Put the other pointer at the head, this will be the left_point\n", + "* Walk/traverse the block (both pointers) towards the tail, one node at a time, keeping a distance **n** between them.\n", + "* Once the right_point has hit the tail, we know that the left point is at the target.\n", + "\n", + "Let's see the code for this!" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def nth_to_last_node(n, head):\n", + "\n", + " left_pointer = head\n", + " right_pointer = head\n", + "\n", + " # Set right pointer at n nodes away from head\n", + " for i in xrange(n-1):\n", + " \n", + " # Check for edge case of not having enough nodes!\n", + " if not right_pointer.nextnode:\n", + " raise LookupError('Error: n is larger than the linked list.')\n", + "\n", + " # Otherwise, we can set the block\n", + " right_pointer = right_pointer.nextnode\n", + "\n", + " # Move the block down the linked list\n", + " while right_pointer.nextnode:\n", + " left_pointer = left_pointer.nextnode\n", + " right_pointer = right_pointer.nextnode\n", + "\n", + " # Now return left pointer, its at the nth to last element!\n", + " return left_pointer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION AGAINST A TEST CASE \n", + "\n", + "PLEASE NOTE THIS IS JUST ONE CASE\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "####\n", + "\n", + "class TestNLast(object):\n", + " \n", + " def test(self,sol):\n", + " \n", + " assert_equal(sol(2,a),d)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run tests\n", + "t = TestNLast()\n", + "t.test(nth_to_last_node)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Linked List Reversal - SOLUTION-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Linked List Reversal - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..5ac84405 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Linked List Reversal - SOLUTION-checkpoint.ipynb @@ -0,0 +1,267 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Reversal - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "Write a function to reverse a Linked List in place. The function will take in the head of the list as input and return the new head of the list.\n", + "\n", + "You are given the example Linked List Node class:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution\n", + "\n", + "Since we want to do this in place we want to make the funciton operate in O(1) space, meaning we don't want to create a new list, so we will simply use the current nodes! Time wise, we can perform the reversal in O(n) time.\n", + "\n", + "We can reverse the list by changing the next pointer of each node. Each node's next pointer should point to the previous node.\n", + "\n", + "In one pass from head to tail of our input list, we will point each node's next pointer to the previous element.\n", + "\n", + "Make sure to copy current.next_node into next_node **before** setting current.next_node to previous. Let's see this solution coded out:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def reverse(head):\n", + " \n", + " # Set up current,previous, and next nodes\n", + " current = head\n", + " previous = None\n", + " nextnode = None\n", + "\n", + " # until we have gone through to the end of the list\n", + " while current:\n", + " \n", + " # Make sure to copy the current nodes next node to a variable next_node\n", + " # Before overwriting as the previous node for reversal\n", + " nextnode = current.nextnode\n", + "\n", + " # Reverse the pointer ot the next_node\n", + " current.nextnode = previous\n", + "\n", + " # Go one forward in the list\n", + " previous = current\n", + " current = nextnode\n", + "\n", + " return previous" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "You should be able to easily test your own solution to make sure it works. Given the short list a,b,c,d with values 1,2,3,4. Check the effect of your reverse function and maek sure the results match the logic here below:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a list of 4 nodes\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "\n", + "# Set up order a,b,c,d with values 1,2,3,4\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's check the values of the nodes coming after a, b and c:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "print a.nextnode.value\n", + "print b.nextnode.value\n", + "print c.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "d.nextnode.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far so good. Note how there is no value proceeding the last node, this makes sense! Now let's reverse the linked list, we should see the opposite order of values!" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Node at 0x104bd7dd0>" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "2\n", + "1\n" + ] + } + ], + "source": [ + "print d.nextnode.value\n", + "print c.nextnode.value\n", + "print b.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mprint\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m \u001b[0;31m# This will give an error since it now points to None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "print a.nextnode.value # This will give an error since it now points to None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great, now we can see that each of the values points to its previous value (although now that the linked list is reversed we can see the ordering has also reversed)\n", + "\n", + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Singly Linked List Cycle Check - SOLUTION-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Singly Linked List Cycle Check - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..f0752ac6 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/.ipynb_checkpoints/Singly Linked List Cycle Check - SOLUTION-checkpoint.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Singly Linked List Cycle Check - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "Given a singly linked list, write a function which takes in the first node in a singly linked list and returns a boolean indicating if the linked list contains a \"cycle\".\n", + "\n", + "A cycle is when a node's next point actually points back to a previous node in the list. This is also sometimes known as a circularly linked list.\n", + "\n", + "You've been given the Linked List Node class code:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "To solve this problem we will have two markers traversing through the list. **marker1** and **marker2**. We will have both makers begin at the first node of the list and traverse through the linked list. However the second marker, marker2, will move two nodes ahead for every one node that marker1 moves.\n", + "\n", + "By this logic we can imagine that the markers are \"racing\" through the linked list, with marker2 moving faster. If the linked list has a cylce and is circularly connected we will have the analogy of a track, in this case the marker2 will eventually be \"lapping\" the marker1 and they will equal each other. \n", + "\n", + "If the linked list has no cycle, then marker2 should be able to continue on until the very end, never equaling the first marker.\n", + "\n", + "Let's see this logic coded out:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def cycle_check(node):\n", + "\n", + " # Begin both markers at the first node\n", + " marker1 = node\n", + " marker2 = node\n", + "\n", + " # Go until end of list\n", + " while marker2 != None and marker2.nextnode != None:\n", + " \n", + " # Note\n", + " marker1 = marker1.nextnode\n", + " marker2 = marker2.nextnode.nextnode\n", + "\n", + " # Check if the markers have matched\n", + " if marker2 == marker1:\n", + " return True\n", + "\n", + " # Case where marker ahead reaches the end of the list\n", + " return False" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "# CREATE CYCLE LIST\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = a # Cycle Here!\n", + "\n", + "\n", + "# CREATE NON CYCLE LIST\n", + "x = Node(1)\n", + "y = Node(2)\n", + "z = Node(3)\n", + "\n", + "x.nextnode = y\n", + "y.nextnode = z\n", + "\n", + "\n", + "#############\n", + "class TestCycleCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(a),True)\n", + " assert_equal(sol(x),False)\n", + " \n", + " print \"ALL TEST CASES PASSED\"\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestCycleCheck()\n", + "t.test(cycle_check)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Implement a Linked List -SOLUTION.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Implement a Linked List -SOLUTION.ipynb new file mode 100644 index 00000000..303ba52f --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Implement a Linked List -SOLUTION.ipynb @@ -0,0 +1,158 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Linked List - SOLUTION\n", + "\n", + "## Problem Statement\n", + "\n", + "Implement a Linked List by using a Node class object. Show how you would implement a Singly Linked List *and* a Doubly Linked List!\n", + "\n", + "## Solution\n", + "\n", + "Since this is asking the same thing as the implementation lectures, please refer to those video lectures and notes for a full explanation. The code from those lectures is displayed below:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Singly Linked List" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class LinkedListNode(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a = LinkedListNode(1)\n", + "b = LinkedListNode(2)\n", + "c = LinkedListNode(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a.nextnode = b\n", + "b.nextnode = c" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Doubly Linked List" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class DoublyLinkedListNode(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.next_node = None\n", + " self.prev_node = None" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a = DoublyLinkedListNode(1)\n", + "b = DoublyLinkedListNode(2)\n", + "c = DoublyLinkedListNode(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting b after a\n", + "b.prev_node = a\n", + "a.next_node = b" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Setting c after a\n", + "b.next_node = c\n", + "c.prev_node = b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Linked List Nth to Last Node - SOLUTION.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Linked List Nth to Last Node - SOLUTION.ipynb new file mode 100644 index 00000000..457e6e48 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Linked List Nth to Last Node - SOLUTION.ipynb @@ -0,0 +1,210 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Nth to Last Node - SOLUTION\n", + "\n", + "## Problem Statement\n", + "Write a function that takes a head node and an integer value **n** and then returns the nth to last node in the linked list. For example, given:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node:\n", + "\n", + " def __init__(self, value):\n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "# This would return the node d with a value of 4, because its the 2nd to last node.\n", + "target_node = nth_to_last_node(2, a) " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_node.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "One approach to this problem is this:\n", + "\n", + "Imagine you have a bunch of nodes and a \"block\" which is n-nodes wide. We could walk this \"block\" all the way down the list, and once the front of the block reached the end, then the other end of the block would be a the Nth node! \n", + "\n", + "So to implement this \"block\" we would just have two pointers a left and right pair of pointers. Let's mark out the steps we will need to take:\n", + "\n", + "* Walk one pointer **n** nodes from the head, this will be the right_point\n", + "* Put the other pointer at the head, this will be the left_point\n", + "* Walk/traverse the block (both pointers) towards the tail, one node at a time, keeping a distance **n** between them.\n", + "* Once the right_point has hit the tail, we know that the left point is at the target.\n", + "\n", + "Let's see the code for this!" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def nth_to_last_node(n, head):\n", + "\n", + " left_pointer = head\n", + " right_pointer = head\n", + "\n", + " # Set right pointer at n nodes away from head\n", + " for i in xrange(n-1):\n", + " \n", + " # Check for edge case of not having enough nodes!\n", + " if not right_pointer.nextnode:\n", + " raise LookupError('Error: n is larger than the linked list.')\n", + "\n", + " # Otherwise, we can set the block\n", + " right_pointer = right_pointer.nextnode\n", + "\n", + " # Move the block down the linked list\n", + " while right_pointer.nextnode:\n", + " left_pointer = left_pointer.nextnode\n", + " right_pointer = right_pointer.nextnode\n", + "\n", + " # Now return left pointer, its at the nth to last element!\n", + " return left_pointer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION AGAINST A TEST CASE \n", + "\n", + "PLEASE NOTE THIS IS JUST ONE CASE\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "####\n", + "\n", + "class TestNLast(object):\n", + " \n", + " def test(self,sol):\n", + " \n", + " assert_equal(sol(2,a),d)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run tests\n", + "t = TestNLast()\n", + "t.test(nth_to_last_node)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Linked List Reversal - SOLUTION.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Linked List Reversal - SOLUTION.ipynb new file mode 100644 index 00000000..5ac84405 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Linked List Reversal - SOLUTION.ipynb @@ -0,0 +1,267 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Reversal - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "Write a function to reverse a Linked List in place. The function will take in the head of the list as input and return the new head of the list.\n", + "\n", + "You are given the example Linked List Node class:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution\n", + "\n", + "Since we want to do this in place we want to make the funciton operate in O(1) space, meaning we don't want to create a new list, so we will simply use the current nodes! Time wise, we can perform the reversal in O(n) time.\n", + "\n", + "We can reverse the list by changing the next pointer of each node. Each node's next pointer should point to the previous node.\n", + "\n", + "In one pass from head to tail of our input list, we will point each node's next pointer to the previous element.\n", + "\n", + "Make sure to copy current.next_node into next_node **before** setting current.next_node to previous. Let's see this solution coded out:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def reverse(head):\n", + " \n", + " # Set up current,previous, and next nodes\n", + " current = head\n", + " previous = None\n", + " nextnode = None\n", + "\n", + " # until we have gone through to the end of the list\n", + " while current:\n", + " \n", + " # Make sure to copy the current nodes next node to a variable next_node\n", + " # Before overwriting as the previous node for reversal\n", + " nextnode = current.nextnode\n", + "\n", + " # Reverse the pointer ot the next_node\n", + " current.nextnode = previous\n", + "\n", + " # Go one forward in the list\n", + " previous = current\n", + " current = nextnode\n", + "\n", + " return previous" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "You should be able to easily test your own solution to make sure it works. Given the short list a,b,c,d with values 1,2,3,4. Check the effect of your reverse function and maek sure the results match the logic here below:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a list of 4 nodes\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "\n", + "# Set up order a,b,c,d with values 1,2,3,4\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's check the values of the nodes coming after a, b and c:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "print a.nextnode.value\n", + "print b.nextnode.value\n", + "print c.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "d.nextnode.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far so good. Note how there is no value proceeding the last node, this makes sense! Now let's reverse the linked list, we should see the opposite order of values!" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Node at 0x104bd7dd0>" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "2\n", + "1\n" + ] + } + ], + "source": [ + "print d.nextnode.value\n", + "print c.nextnode.value\n", + "print b.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mprint\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m \u001b[0;31m# This will give an error since it now points to None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "print a.nextnode.value # This will give an error since it now points to None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great, now we can see that each of the values points to its previous value (although now that the linked list is reversed we can see the ordering has also reversed)\n", + "\n", + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Singly Linked List Cycle Check - SOLUTION.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Singly Linked List Cycle Check - SOLUTION.ipynb new file mode 100644 index 00000000..f0752ac6 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems - SOLUTIONS/Singly Linked List Cycle Check - SOLUTION.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Singly Linked List Cycle Check - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "Given a singly linked list, write a function which takes in the first node in a singly linked list and returns a boolean indicating if the linked list contains a \"cycle\".\n", + "\n", + "A cycle is when a node's next point actually points back to a previous node in the list. This is also sometimes known as a circularly linked list.\n", + "\n", + "You've been given the Linked List Node class code:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "To solve this problem we will have two markers traversing through the list. **marker1** and **marker2**. We will have both makers begin at the first node of the list and traverse through the linked list. However the second marker, marker2, will move two nodes ahead for every one node that marker1 moves.\n", + "\n", + "By this logic we can imagine that the markers are \"racing\" through the linked list, with marker2 moving faster. If the linked list has a cylce and is circularly connected we will have the analogy of a track, in this case the marker2 will eventually be \"lapping\" the marker1 and they will equal each other. \n", + "\n", + "If the linked list has no cycle, then marker2 should be able to continue on until the very end, never equaling the first marker.\n", + "\n", + "Let's see this logic coded out:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def cycle_check(node):\n", + "\n", + " # Begin both markers at the first node\n", + " marker1 = node\n", + " marker2 = node\n", + "\n", + " # Go until end of list\n", + " while marker2 != None and marker2.nextnode != None:\n", + " \n", + " # Note\n", + " marker1 = marker1.nextnode\n", + " marker2 = marker2.nextnode.nextnode\n", + "\n", + " # Check if the markers have matched\n", + " if marker2 == marker1:\n", + " return True\n", + "\n", + " # Case where marker ahead reaches the end of the list\n", + " return False" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "# CREATE CYCLE LIST\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = a # Cycle Here!\n", + "\n", + "\n", + "# CREATE NON CYCLE LIST\n", + "x = Node(1)\n", + "y = Node(2)\n", + "z = Node(3)\n", + "\n", + "x.nextnode = y\n", + "y.nextnode = z\n", + "\n", + "\n", + "#############\n", + "class TestCycleCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(a),True)\n", + " assert_equal(sol(x),False)\n", + " \n", + " print \"ALL TEST CASES PASSED\"\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestCycleCheck()\n", + "t.test(cycle_check)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Implement a Doubly Linked List-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Implement a Doubly Linked List-checkpoint.ipynb new file mode 100644 index 00000000..047d0421 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Implement a Doubly Linked List-checkpoint.ipynb @@ -0,0 +1,67 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Doubly Linked List\n", + "\n", + "For this interview problem, implement a node class and show how it can be used to create a doubly linked list." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a Doubly Linked List here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "Note that there is no test for this solution (because it would give away the answer structure).\n", + "\n", + "Check out the Implement a Linked List Solution Notebook for the answer to this interview problem, as well as the answer for the implementation of a singly linked list." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Implement a Singly Linked List-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Implement a Singly Linked List-checkpoint.ipynb new file mode 100644 index 00000000..92b84693 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Implement a Singly Linked List-checkpoint.ipynb @@ -0,0 +1,68 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Singly Linked List\n", + "\n", + "For this interview problem, create a node class and show how it can be used to create a Singly Linked List" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a Singly Linked List here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Note that there is no test for this solution (because it would give away the answer structure).\n", + "\n", + "Check out the Implement a Linked List Solution Notebook for the answer to this interview problem, as well as the answer for the implementation of a doubly linked list." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Linked List Nth to Last Node -checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Linked List Nth to Last Node -checkpoint.ipynb new file mode 100644 index 00000000..de16594d --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Linked List Nth to Last Node -checkpoint.ipynb @@ -0,0 +1,186 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Nth to Last Node \n", + "\n", + "## Problem Statement\n", + "Write a function that takes a head node and an integer value **n** and then returns the nth to last node in the linked list. For example, given:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node:\n", + "\n", + " def __init__(self, value):\n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Example Input and Output:**" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "# This would return the node d with a value of 4, because its the 2nd to last node.\n", + "target_node = nth_to_last_node(2, a) " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_node.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def nth_to_last_node(n, head):\n", + "\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION AGAINST A TEST CASE \n", + "\n", + "PLEASE NOTE THIS IS JUST ONE CASE\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "####\n", + "\n", + "class TestNLast(object):\n", + " \n", + " def test(self,sol):\n", + " \n", + " assert_equal(sol(2,a),d)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run tests\n", + "t = TestNLast()\n", + "t.test(nth_to_last_node)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Linked List Reversal -checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Linked List Reversal -checkpoint.ipynb new file mode 100644 index 00000000..d6d333eb --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Linked List Reversal -checkpoint.ipynb @@ -0,0 +1,244 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Reversal \n", + "\n", + "## Problem\n", + "\n", + "Write a function to reverse a Linked List in place. The function will take in the head of the list as input and return the new head of the list.\n", + "\n", + "You are given the example Linked List Node class:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def reverse(head):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "**Note, this isn't a classic run cell for testing your solution, please read the statements below carefully**\n", + "\n", + "You should be able to easily test your own solution to make sure it works. Given the short list a,b,c,d with values 1,2,3,4. Check the effect of your reverse function and make sure the results match the logic here below:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a list of 4 nodes\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "\n", + "# Set up order a,b,c,d with values 1,2,3,4\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's check the values of the nodes coming after a, b and c:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "print a.nextnode.value\n", + "print b.nextnode.value\n", + "print c.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "d.nextnode.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far so good. Note how there is no value proceeding the last node, this makes sense! Now let's reverse the linked list, we should see the opposite order of values!" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Node at 0x104bd7dd0>" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "2\n", + "1\n" + ] + } + ], + "source": [ + "print d.nextnode.value\n", + "print c.nextnode.value\n", + "print b.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mprint\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m \u001b[0;31m# This will give an error since it now points to None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "print a.nextnode.value # This will give an error since it now points to None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great, now we can see that each of the values points to its previous value (although now that the linked list is reversed we can see the ordering has also reversed)\n", + "\n", + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Singly Linked List Cycle Check-checkpoint.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Singly Linked List Cycle Check-checkpoint.ipynb new file mode 100644 index 00000000..8c41dde7 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/.ipynb_checkpoints/Singly Linked List Cycle Check-checkpoint.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Singly Linked List Cycle Check \n", + "\n", + "## Problem\n", + "\n", + "Given a singly linked list, write a function which takes in the first node in a singly linked list and returns a boolean indicating if the linked list contains a \"cycle\".\n", + "\n", + "A cycle is when a node's next point actually points back to a previous node in the list. This is also sometimes known as a circularly linked list.\n", + "\n", + "You've been given the Linked List Node class code:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def cycle_check(node):\n", + "\n", + " pass #Your function should return a boolean" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "# CREATE CYCLE LIST\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = a # Cycle Here!\n", + "\n", + "\n", + "# CREATE NON CYCLE LIST\n", + "x = Node(1)\n", + "y = Node(2)\n", + "z = Node(3)\n", + "\n", + "x.nextnode = y\n", + "y.nextnode = z\n", + "\n", + "\n", + "#############\n", + "class TestCycleCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(a),True)\n", + " assert_equal(sol(x),False)\n", + " \n", + " print \"ALL TEST CASES PASSED\"\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestCycleCheck()\n", + "t.test(cycle_check)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Implement a Doubly Linked List.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Implement a Doubly Linked List.ipynb new file mode 100644 index 00000000..047d0421 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Implement a Doubly Linked List.ipynb @@ -0,0 +1,67 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Doubly Linked List\n", + "\n", + "For this interview problem, implement a node class and show how it can be used to create a doubly linked list." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a Doubly Linked List here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "Note that there is no test for this solution (because it would give away the answer structure).\n", + "\n", + "Check out the Implement a Linked List Solution Notebook for the answer to this interview problem, as well as the answer for the implementation of a singly linked list." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Implement a Singly Linked List.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Implement a Singly Linked List.ipynb new file mode 100644 index 00000000..92b84693 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Implement a Singly Linked List.ipynb @@ -0,0 +1,68 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Singly Linked List\n", + "\n", + "For this interview problem, create a node class and show how it can be used to create a Singly Linked List" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a Singly Linked List here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Note that there is no test for this solution (because it would give away the answer structure).\n", + "\n", + "Check out the Implement a Linked List Solution Notebook for the answer to this interview problem, as well as the answer for the implementation of a doubly linked list." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Linked List Nth to Last Node .ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Linked List Nth to Last Node .ipynb new file mode 100644 index 00000000..de16594d --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Linked List Nth to Last Node .ipynb @@ -0,0 +1,186 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Nth to Last Node \n", + "\n", + "## Problem Statement\n", + "Write a function that takes a head node and an integer value **n** and then returns the nth to last node in the linked list. For example, given:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node:\n", + "\n", + " def __init__(self, value):\n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Example Input and Output:**" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "# This would return the node d with a value of 4, because its the 2nd to last node.\n", + "target_node = nth_to_last_node(2, a) " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target_node.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def nth_to_last_node(n, head):\n", + "\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION AGAINST A TEST CASE \n", + "\n", + "PLEASE NOTE THIS IS JUST ONE CASE\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "e = Node(5)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d\n", + "d.nextnode = e\n", + "\n", + "####\n", + "\n", + "class TestNLast(object):\n", + " \n", + " def test(self,sol):\n", + " \n", + " assert_equal(sol(2,a),d)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run tests\n", + "t = TestNLast()\n", + "t.test(nth_to_last_node)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Linked List Reversal .ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Linked List Reversal .ipynb new file mode 100644 index 00000000..d6d333eb --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Linked List Reversal .ipynb @@ -0,0 +1,244 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Linked List Reversal \n", + "\n", + "## Problem\n", + "\n", + "Write a function to reverse a Linked List in place. The function will take in the head of the list as input and return the new head of the list.\n", + "\n", + "You are given the example Linked List Node class:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def reverse(head):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "**Note, this isn't a classic run cell for testing your solution, please read the statements below carefully**\n", + "\n", + "You should be able to easily test your own solution to make sure it works. Given the short list a,b,c,d with values 1,2,3,4. Check the effect of your reverse function and make sure the results match the logic here below:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create a list of 4 nodes\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "d = Node(4)\n", + "\n", + "# Set up order a,b,c,d with values 1,2,3,4\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's check the values of the nodes coming after a, b and c:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "print a.nextnode.value\n", + "print b.nextnode.value\n", + "print c.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "d.nextnode.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So far so good. Note how there is no value proceeding the last node, this makes sense! Now let's reverse the linked list, we should see the opposite order of values!" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Node at 0x104bd7dd0>" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "2\n", + "1\n" + ] + } + ], + "source": [ + "print d.nextnode.value\n", + "print c.nextnode.value\n", + "print b.nextnode.value" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'value'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mprint\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnextnode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue\u001b[0m \u001b[0;31m# This will give an error since it now points to None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'value'" + ] + } + ], + "source": [ + "print a.nextnode.value # This will give an error since it now points to None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great, now we can see that each of the values points to its previous value (although now that the linked list is reversed we can see the ordering has also reversed)\n", + "\n", + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Singly Linked List Cycle Check.ipynb b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Singly Linked List Cycle Check.ipynb new file mode 100644 index 00000000..8c41dde7 --- /dev/null +++ b/Linked Lists/Linked Lists Interview Problems/Linked List Interview Problems_/Singly Linked List Cycle Check.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Singly Linked List Cycle Check \n", + "\n", + "## Problem\n", + "\n", + "Given a singly linked list, write a function which takes in the first node in a singly linked list and returns a boolean indicating if the linked list contains a \"cycle\".\n", + "\n", + "A cycle is when a node's next point actually points back to a previous node in the list. This is also sometimes known as a circularly linked list.\n", + "\n", + "You've been given the Linked List Node class code:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def cycle_check(node):\n", + "\n", + " pass #Your function should return a boolean" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "# CREATE CYCLE LIST\n", + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)\n", + "\n", + "a.nextnode = b\n", + "b.nextnode = c\n", + "c.nextnode = a # Cycle Here!\n", + "\n", + "\n", + "# CREATE NON CYCLE LIST\n", + "x = Node(1)\n", + "y = Node(2)\n", + "z = Node(3)\n", + "\n", + "x.nextnode = y\n", + "y.nextnode = z\n", + "\n", + "\n", + "#############\n", + "class TestCycleCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol(a),True)\n", + " assert_equal(sol(x),False)\n", + " \n", + " print \"ALL TEST CASES PASSED\"\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestCycleCheck()\n", + "t.test(cycle_check)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Linked Lists/Singly Linked List Implementation.ipynb b/Linked Lists/Singly Linked List Implementation.ipynb new file mode 100644 index 00000000..efa1ee5c --- /dev/null +++ b/Linked Lists/Singly Linked List Implementation.ipynb @@ -0,0 +1,120 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Singly Linked List Implementation\n", + "\n", + "In this lecture we will implement a basic Singly Linked List.\n", + "\n", + "Remember, in a singly linked list, we have an ordered list of items as individual Nodes that have pointers to other Nodes." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node(object):\n", + " \n", + " def __init__(self,value):\n", + " \n", + " self.value = value\n", + " self.nextnode = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can build out Linked List with the collection of nodes:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "a = Node(1)\n", + "b = Node(2)\n", + "c = Node(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a.nextnode = b" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "b.nextnode = c" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In a Linked List the first node is called the **head** and the last node is called the **tail**. Let's discuss the pros and cons of Linked Lists:\n", + "\n", + "## Pros\n", + "\n", + "* Linked Lists have constant-time insertions and deletions in any position, in comparison, arrays require O(n) time to do the same thing.\n", + "\n", + "* Linked lists can continue to expand without having to specify their size ahead of time (remember our lectures on Array sizing form the Array Sequence section of the course!)\n", + "\n", + "## Cons\n", + "\n", + "* To access an element in a linked list, you need to take O(k) time to go from the head of the list to the kth element. In contrast, arrays have constant time operations to access elements in an array." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!\n", + "\n", + "That's it for the implementation (pretty simple right?). Up next we will learn about Doubly Linked Lists!" + ] + } + ], + "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 +} diff --git a/Linked Lists/Singly Linked Lists.ipynb b/Linked Lists/Singly Linked Lists.ipynb new file mode 100644 index 00000000..f0f1677d --- /dev/null +++ b/Linked Lists/Singly Linked Lists.ipynb @@ -0,0 +1,36 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Singly Linked Lists\n", + "\n", + "**Please refer to the Lecture Video for full Explanation of Singly Linked Lists**" + ] + } + ], + "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 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..2ac17359 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,232 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** You've been given a list of historical stock prices for a single day for Amazon stock. The index of the list represents the timestamp, so the element at index of 0 is the initial price of the stock, the element at index 1 is the next recorded price of the stock for that day, etc. Your task is to write a function that will return the maximum profit possible from the purchase and sale of a single share of Amazon stock on that day. Keep in mind to try to make this as efficient as possible.**\n", + "\n", + "\n", + "For example, if you were given the list of stock prices:\n", + "\n", + "prices = [12,11,15,3,10]\n", + "\n", + "Then your function would return the maximum possible profit, which would be 7 (buying at 3 and selling at 10).\n", + "\n", + "## Requirements\n", + "\n", + "** Try to solve this problem with paper/pencil first without using an IDE. Also keep in mind you should be able to come up with a better solution than just brute forcing every possible sale combination **\n", + "\n", + "** Also you can't \"short\" a stock, you must buy *before* you sell the stock. **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "Let's think about a few things before we start coding. One thing to think about right off the bat is that we can't just find the maximum price and the lowest price and then subtract the two, because the max could come before the min.\n", + "\n", + "The brute force method would be to try every possible pair of price combinations, but this would be O(N^2), pretty bad. Also since this is an interview setting you should probably already know that there is a smarter solution.\n", + "\n", + "In this case we will use a [greedy algorithm](https://en.wikipedia.org/wiki/Greedy_algorithm) approach. We will iterate through the list of stock prices while keeping track of our maximum profit.\n", + "\n", + "That means for every price we will keep track of the lowest price so far and then check if we can get a better profit than our current max.\n", + "\n", + "Let's see an implementation of this:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def profit(stock_prices):\n", + " \n", + " # Start minimum price marker at first price\n", + " min_stock_price = stock_prices[0]\n", + " \n", + " # Start off with a profit of zero\n", + " max_profit = 0\n", + " \n", + " for price in stock_prices:\n", + " \n", + " # Check to set the lowest stock price so far\n", + " min_stock_price = min(min_stock_price,price)\n", + " \n", + " # Check the current price against our minimum for a profit \n", + " # comparison against the max_profit\n", + " comparison_profit = price - min_stock_price\n", + " \n", + " # Compare against our max_profit so far\n", + " max_profit = max(max_profit,comparison_profit)\n", + " \n", + " return max_profit" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "39" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "profit([10,12,14,12,13,11,8,7,6,13,23,45,11,10])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Currently we're finding the max profit in one pass O(n) and in constant space O(1). However, we still aren't thinking about any edge cases. For example, we need to address the following scenarios:\n", + "\n", + "* Stock price always goes down\n", + "* If there's less than two stock prices in the list.\n", + "\n", + "We can take care of the first scenario by returning a negative profit if the price decreases all day (that way we can know how much we lost). And the second issue can be solved with a quick **len()** check. Let's see the full solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def profit2(stock_prices):\n", + " \n", + " # Check length\n", + " if len(stock_prices) < 2:\n", + " raise Exception('Need at least two stock prices!')\n", + " \n", + " # Start minimum price marker at first price\n", + " min_stock_price = stock_prices[0]\n", + " \n", + " # Start off with an initial max profit\n", + " max_profit = stock_prices[1] - stock_prices[0]\n", + " \n", + " # Skip first index of 0\n", + " for price in stock_prices[1:]:\n", + " \n", + " \n", + " # NOTE THE REORDERING HERE DUE TO THE NEGATIVE PROFIT TRACKING\n", + " \n", + " # Check the current price against our minimum for a profit \n", + " # comparison against the max_profit\n", + " comparison_profit = price - min_stock_price\n", + " \n", + " # Compare against our max_profit so far\n", + " max_profit = max(max_profit,comparison_profit)\n", + " \n", + " # Check to set the lowest stock price so far\n", + " min_stock_price = min(min_stock_price,price)\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " return max_profit" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "Exception", + "evalue": "Need at least two stock prices!", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mException\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Exception Raised\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprofit2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mprofit2\u001b[0;34m(stock_prices)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;31m# Check length\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstock_prices\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Need at least two stock prices!'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;31m# Start minimum price marker at first price\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mException\u001b[0m: Need at least two stock prices!" + ] + } + ], + "source": [ + "# Exception Raised\n", + "profit2([1])" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "-1" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "profit2([30,22,21,5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great! Now we can prepare for worst case scenarios. Its important to keep edge cases in mind, especially if you are able to solve the original question fairly quickly.\n", + "\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..f4f594ff --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,164 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers, write a function that will return a list, in which for each index the element will be the product of all the integers except for the element at that index **\n", + "\n", + "**For example, an input of [1,2,3,4] would return [24,12,8,6] by performing [2×3×4,1×3×4,1×2×4,1×2×3] **\n", + "\n", + "## Requirements\n", + "\n", + "** You can not use division in your answer! Meaning you can't simply multiply all the numbers and then divide by eahc element for each index!**\n", + "\n", + "** Try to do this on a white board or with paper/pencil.**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "___\n", + "## Solution\n", + "\n", + "If you look at the list above with the multiplication you'll notice we are repeating multiplications, such as 2 times 3 or 3 times 4 for multiple entries in the new list. \n", + "\n", + "We'll want to take a greedy approach and keep track of these results for later re-use at other indices. We'll also need to think about what if a number is zero!\n", + "\n", + "In order to find the products of all the integers (except for the integer at that index) we will actually go through our list twice in a greedy fashion. \n", + "\n", + "On the first pass we will get the products of all the integers **before** each index, and then on the second pass we will go **backwards** to get the products of all the integers after each index.\n", + "\n", + "Then we just need to multiply all the products before and after each index in order to get the final product answer!\n", + "\n", + "Let's see this in action:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def index_prod(lst):\n", + " \n", + " # Create an empty output list\n", + " output = [None] * len(lst)\n", + " \n", + " # Set initial product and index for greedy run forward\n", + " product = 1\n", + " i = 0\n", + " \n", + " while i < len(lst):\n", + " \n", + " # Set index as cumulative product\n", + " output[i] = product\n", + " \n", + " # Cumulative product\n", + " product *= lst[i]\n", + " \n", + " # Move forward\n", + " i +=1\n", + " \n", + " \n", + " # Now for our Greedy run Backwards\n", + " product = 1\n", + " \n", + " # Start index at last (taking into account index 0)\n", + " i = len(lst) - 1\n", + " \n", + " # Until the beginning of the list\n", + " while i >=0:\n", + " \n", + " # Same operations as before, just backwards\n", + " output[i] *= product\n", + " product *= lst[i]\n", + " i -= 1\n", + " \n", + " return output " + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[24, 12, 8, 6]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "index_prod([1,2,3,4])" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[24, 0, 0, 0, 0]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "index_prod([0,1,2,3,4])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Review the solution and make sure you understand it! It uses O(n) time and O(n) space complexity!\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..f3b22b3b --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "**Given two rectangles, determine if they overlap. The rectangles are defined as a Dictionary, for example:**" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "r1 = {\n", + " \n", + " # x and y coordinates of the bottom-left corner of the rectangle\n", + " 'x': 2 , 'y': 4,\n", + " \n", + " # Width and Height of rectangle\n", + " 'w':5,'h':12}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** If the rectangles do overlap, return the dictionary which describes the overlapping section**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Requirements\n", + "\n", + "** Make sure the dictionary you output is in the same form as the input.**\n", + "\n", + "** Feel free to use an IDE for the code, but make sure you use paper/pencil or whiteboard to draw out your plan and logic**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "This is a problem where it helps a lot to draw out your thinking. There are a few things we will need to think about:\n", + "\n", + "* How can we determine an intersection?\n", + "* What if a rectangle is fully inside another rectangle?\n", + "* What if there is no intersection, but the rectangles share an edge?\n", + "\n", + "The key to solving this problem is to *break it up in to sub-problems*. We can split up the problem into an x-axis problem and a y-axis problem. \n", + "\n", + "We will create a function that can detect overlap in 1 dimension. Then we will split the rectangles into x and width, and y and height components. We can then determine that if there is overlap on both dimensions, then the rectangles themselves intersect!\n", + "\n", + "In order to understand the **calc_overlap** function, draw out two flat lines and follow along with the function and notice how it detects an overlap!\n", + "\n", + "Let's begin by creating a general function to detect overlap in a single dimension:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def calc_overlap(coor1,dim1,coor2,dim2):\n", + " \"\"\"\n", + " Takes in 2 coordinates and their length in that dimension\n", + " \"\"\"\n", + " \n", + " # Find greater of the two coordinates\n", + " # (this is either the point to the most right\n", + " # or the higher point, depending on the dimension)\n", + " \n", + " # The greater point would be the start of the overlap\n", + " greater = max(coor1,coor2)\n", + " \n", + " # The lower point is the end of the overlap\n", + " lower = min(coor1+dim1,coor2+dim2)\n", + " \n", + " # Return a tuple of Nones if there is no overlap\n", + " \n", + " if greater >= lower:\n", + " return (None,None)\n", + " \n", + " # Otherwise, get the overlap length\n", + " overlap = lower-greater\n", + " \n", + " return (greater,overlap)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's use this function to detect if the rectangles overlap!" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def calc_rect_overlap(r1,r2):\n", + " \n", + " \n", + " x_overlap, w_overlap = calc_overlap(r1['x'],r1['w'],r2['x'],r2['w'])\n", + " \n", + " y_overlap, h_overlap = calc_overlap(r1['y'],r1['h'],r2['y'],r2['h'])\n", + " \n", + " # If either returned None tuples, then there is no overlap!\n", + " if not w_overlap or not h_overlap:\n", + " print 'There was no overlap!'\n", + " return None\n", + " \n", + " # Otherwise return the dictionary format of the overlapping rectangle\n", + " return { 'x':x_overlap,'y': y_overlap,'w':w_overlap,'h':h_overlap}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our solution is O(1) for both time and space! Let's see it in action:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'h': 11, 'w': 5, 'x': 2, 'y': 5}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "r1 = {'x': 2 , 'y': 4,'w':5,'h':12}\n", + "r2 = {'x': 1 , 'y': 5,'w':7,'h':14}\n", + "calc_rect_overlap(r1,r2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Make sure to review the answer and practice writing it out by hand!\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..042f7a06 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb @@ -0,0 +1,85 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "**A tower has 100 floors. You've been given two eggs. The eggs are strong enough that they can be dropped from a particular floor in the tower without breaking. You've been tasked to find the highest floor an egg can be dropped without breaking, in as few drops as possible. If an egg is dropped from above its target floor it will break. If it is dropped from that floor or below, it will be intact and you can test drop the egg again on another floor.**\n", + "\n", + "**Show algorithmically how you would go about doing this in as few drops as possible**\n", + "## Requirements\n", + "\n", + "** Use paper/pencil or a whiteboard for this problem **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "** We've already seen this problem in the Riddles section, here is the answer from that section.(Alternatively just google \"2 eggs 100 floors\" for a plethora of explanations regarding this same solution **\n", + "\n", + "\n", + "Start from the 10th floor and go up to floors in multiples of 10.\n", + "\n", + "If first egg breaks, say at 20th floor then you can check all the floors between 11th and 19th with the second egg to see which floor it will not break.\n", + "\n", + "In this case, the worst-case number of drops is 19. If the threshold was 99th floor, then you would have to drop the first egg 10 times and the second egg 9 times in linear fashion.\n", + "\n", + "**Best solution:**\n", + "We need to minimize this worst-case number of drops. For that, we need to generalize the problem to have n floors. What would be the step value, for the first egg? Would it still be 10? Suppose we have 200 floors. Would the step value be still 10? \n", + "\n", + "The point to note here is that we are trying to minimize the worst-case number of drops which happens if the threshold is at the highest floors. So, our steps should be of some value which reduces the number of drops of the first egg.\n", + "\n", + "Let's assume we take some step value m initially. If every subsequent step is m-1,\n", + "then, \n", + "$$m+m−1+m−2+.....+1=n$$\n", + "\n", + "This is \n", + "\n", + "$$\\frac{m∗(m+1)}{2}=n$$\n", + "\n", + "If n =100, then m would be 13.65 which since we can't drop from a decimal of a floor, we actually use 14.\n", + "\n", + "So, the worst case scenario is now when the threshold is in the first 14 floors with number of drops being 14.\n", + "\n", + "Note that this is simply a binary search!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb new file mode 100644 index 00000000..c33d49c1 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb @@ -0,0 +1,226 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** You've been given a list of historical stock prices for a single day for Amazon stock. The index of the list represents the timestamp, so the element at index of 0 is the initial price of the stock, the element at index 1 is the next recorded price of the stock for that day, etc. Your task is to write a function that will return the maximum profit possible from the purchase and sale of a single share of Amazon stock on that day. Keep in mind to try to make this as efficient as possible.**\n", + "\n", + "\n", + "For example, if you were given the list of stock prices:\n", + "\n", + "prices = [12,11,15,3,10]\n", + "\n", + "Then your function would return the maximum possible profit, which would be 7 (buying at 3 and selling at 10).\n", + "\n", + "## Requirements\n", + "\n", + "** Try to solve this problem with paper/pencil first without using an IDE. Also keep in mind you should be able to come up with a better solution than just brute forcing every possible sale combination **\n", + "\n", + "** Also you can't \"short\" a stock, you must buy *before* you sell the stock. **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "Let's think about a few things before we start coding. One thing to think about right off the bat is that we can't just find the maximum price and the lowest price and then subtract the two, because the max could come before the min.\n", + "\n", + "The brute force method would be to try every possible pair of price combinations, but this would be O(N^2), pretty bad. Also since this is an interview setting you should probably already know that there is a smarter solution.\n", + "\n", + "In this case we will use a [greedy algorithm](https://en.wikipedia.org/wiki/Greedy_algorithm) approach. We will iterate through the list of stock prices while keeping track of our maximum profit.\n", + "\n", + "That means for every price we will keep track of the lowest price so far and then check if we can get a better profit than our current max.\n", + "\n", + "Let's see an implementation of this:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def profit(stock_prices):\n", + " \n", + " # Start minimum price marker at first price\n", + " min_stock_price = stock_prices[0]\n", + " \n", + " # Start off with a profit of zero\n", + " max_profit = 0\n", + " \n", + " for price in stock_prices:\n", + " \n", + " # Check to set the lowest stock price so far\n", + " min_stock_price = min(min_stock_price,price)\n", + " \n", + " # Check the current price against our minimum for a profit \n", + " # comparison against the max_profit\n", + " comparison_profit = price - min_stock_price\n", + " \n", + " # Compare against our max_profit so far\n", + " max_profit = max(max_profit,comparison_profit)\n", + " \n", + " return max_profit" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "39" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "profit([10,12,14,12,13,11,8,7,6,13,23,45,11,10])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Currently we're finding the max profit in one pass O(n) and in constant space O(1). However, we still aren't thinking about any edge cases. For example, we need to address the following scenarios:\n", + "\n", + "* Stock price always goes down\n", + "* If there's less than two stock prices in the list.\n", + "\n", + "We can take care of the first scenario by returning a negative profit if the price decreases all day (that way we can know how much we lost). And the second issue can be solved with a quick **len()** check. Let's see the full solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def profit2(stock_prices):\n", + " \n", + " # Check length\n", + " if len(stock_prices) < 2:\n", + " raise Exception('Need at least two stock prices!')\n", + " \n", + " # Start minimum price marker at first price\n", + " min_stock_price = stock_prices[0]\n", + " \n", + " # Start off with an initial max profit\n", + " max_profit = stock_prices[1] - stock_prices[0]\n", + " \n", + " # Skip first index of 0\n", + " for price in stock_prices[1:]:\n", + " \n", + " \n", + " # NOTE THE REORDERING HERE DUE TO THE NEGATIVE PROFIT TRACKING\n", + " \n", + " # Check the current price against our minimum for a profit \n", + " # comparison against the max_profit\n", + " comparison_profit = price - min_stock_price\n", + " \n", + " # Compare against our max_profit so far\n", + " max_profit = max(max_profit,comparison_profit)\n", + " \n", + " # Check to set the lowest stock price so far\n", + " min_stock_price = min(min_stock_price,price)\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " return max_profit" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "ename": "Exception", + "evalue": "Need at least two stock prices!", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mException\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Exception Raised\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprofit2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mprofit2\u001b[0;34m(stock_prices)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;31m# Check length\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstock_prices\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Need at least two stock prices!'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;31m# Start minimum price marker at first price\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mException\u001b[0m: Need at least two stock prices!" + ] + } + ], + "source": [ + "# Exception Raised\n", + "profit2([1])" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "-1" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "profit2([30,22,21,5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great! Now we can prepare for worst case scenarios. Its important to keep edge cases in mind, especially if you are able to solve the original question fairly quickly.\n", + "\n", + "# Good Job!" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb new file mode 100644 index 00000000..ba4352ba --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb @@ -0,0 +1,160 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers, write a function that will return a list, in which for each index the element will be the product of all the integers except for the element at that index **\n", + "\n", + "**For example, an input of [1,2,3,4] would return [24,12,8,6] by performing [2×3×4,1×3×4,1×2×4,1×2×3] **\n", + "\n", + "## Requirements\n", + "\n", + "** You can not use division in your answer! Meaning you can't simply multiply all the numbers and then divide by eahc element for each index!**\n", + "\n", + "** Try to do this on a white board or with paper/pencil.**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "___\n", + "## Solution\n", + "\n", + "If you look at the list above with the multiplication you'll notice we are repeating multiplications, such as 2 times 3 or 3 times 4 for multiple entries in the new list. \n", + "\n", + "We'll want to take a greedy approach and keep track of these results for later re-use at other indices. We'll also need to think about what if a number is zero!\n", + "\n", + "In order to find the products of all the integers (except for the integer at that index) we will actually go through our list twice in a greedy fashion. \n", + "\n", + "On the first pass we will get the products of all the integers **before** each index, and then on the second pass we will go **backwards** to get the products of all the integers after each index.\n", + "\n", + "Then we just need to multiply all the products before and after each index in order to get the final product answer!\n", + "\n", + "Let's see this in action:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def index_prod(lst):\n", + " \n", + " # Create an empty output list\n", + " output = [None] * len(lst)\n", + " \n", + " # Set initial product and index for greedy run forward\n", + " product = 1\n", + " i = 0\n", + " \n", + " while i < len(lst):\n", + " \n", + " # Set index as cumulative product\n", + " output[i] = product\n", + " \n", + " # Cumulative product\n", + " product *= lst[i]\n", + " \n", + " # Move forward\n", + " i +=1\n", + " \n", + " \n", + " # Now for our Greedy run Backwards\n", + " product = 1\n", + " \n", + " # Start index at last (taking into account index 0)\n", + " i = len(lst) - 1\n", + " \n", + " # Until the beginning of the list\n", + " while i >=0:\n", + " \n", + " # Same operations as before, just backwards\n", + " output[i] *= product\n", + " product *= lst[i]\n", + " i -= 1\n", + " \n", + " return output " + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[24, 12, 8, 6]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "index_prod([1,2,3,4])" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[24, 0, 0, 0, 0]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "index_prod([0,1,2,3,4])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Review the solution and make sure you understand it! It uses O(n) time and O(n) space complexity!\n", + "# Good Job!" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb new file mode 100644 index 00000000..f3b22b3b --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb @@ -0,0 +1,196 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "**Given two rectangles, determine if they overlap. The rectangles are defined as a Dictionary, for example:**" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "r1 = {\n", + " \n", + " # x and y coordinates of the bottom-left corner of the rectangle\n", + " 'x': 2 , 'y': 4,\n", + " \n", + " # Width and Height of rectangle\n", + " 'w':5,'h':12}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** If the rectangles do overlap, return the dictionary which describes the overlapping section**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Requirements\n", + "\n", + "** Make sure the dictionary you output is in the same form as the input.**\n", + "\n", + "** Feel free to use an IDE for the code, but make sure you use paper/pencil or whiteboard to draw out your plan and logic**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "This is a problem where it helps a lot to draw out your thinking. There are a few things we will need to think about:\n", + "\n", + "* How can we determine an intersection?\n", + "* What if a rectangle is fully inside another rectangle?\n", + "* What if there is no intersection, but the rectangles share an edge?\n", + "\n", + "The key to solving this problem is to *break it up in to sub-problems*. We can split up the problem into an x-axis problem and a y-axis problem. \n", + "\n", + "We will create a function that can detect overlap in 1 dimension. Then we will split the rectangles into x and width, and y and height components. We can then determine that if there is overlap on both dimensions, then the rectangles themselves intersect!\n", + "\n", + "In order to understand the **calc_overlap** function, draw out two flat lines and follow along with the function and notice how it detects an overlap!\n", + "\n", + "Let's begin by creating a general function to detect overlap in a single dimension:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def calc_overlap(coor1,dim1,coor2,dim2):\n", + " \"\"\"\n", + " Takes in 2 coordinates and their length in that dimension\n", + " \"\"\"\n", + " \n", + " # Find greater of the two coordinates\n", + " # (this is either the point to the most right\n", + " # or the higher point, depending on the dimension)\n", + " \n", + " # The greater point would be the start of the overlap\n", + " greater = max(coor1,coor2)\n", + " \n", + " # The lower point is the end of the overlap\n", + " lower = min(coor1+dim1,coor2+dim2)\n", + " \n", + " # Return a tuple of Nones if there is no overlap\n", + " \n", + " if greater >= lower:\n", + " return (None,None)\n", + " \n", + " # Otherwise, get the overlap length\n", + " overlap = lower-greater\n", + " \n", + " return (greater,overlap)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's use this function to detect if the rectangles overlap!" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def calc_rect_overlap(r1,r2):\n", + " \n", + " \n", + " x_overlap, w_overlap = calc_overlap(r1['x'],r1['w'],r2['x'],r2['w'])\n", + " \n", + " y_overlap, h_overlap = calc_overlap(r1['y'],r1['h'],r2['y'],r2['h'])\n", + " \n", + " # If either returned None tuples, then there is no overlap!\n", + " if not w_overlap or not h_overlap:\n", + " print 'There was no overlap!'\n", + " return None\n", + " \n", + " # Otherwise return the dictionary format of the overlapping rectangle\n", + " return { 'x':x_overlap,'y': y_overlap,'w':w_overlap,'h':h_overlap}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our solution is O(1) for both time and space! Let's see it in action:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'h': 11, 'w': 5, 'x': 2, 'y': 5}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "r1 = {'x': 2 , 'y': 4,'w':5,'h':12}\n", + "r2 = {'x': 1 , 'y': 5,'w':7,'h':14}\n", + "calc_rect_overlap(r1,r2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Make sure to review the answer and practice writing it out by hand!\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/Phone Screen - SOLUTION.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/Phone Screen - SOLUTION.ipynb new file mode 100644 index 00000000..042f7a06 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems - SOLUTIONS/Phone Screen - SOLUTION.ipynb @@ -0,0 +1,85 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "**A tower has 100 floors. You've been given two eggs. The eggs are strong enough that they can be dropped from a particular floor in the tower without breaking. You've been tasked to find the highest floor an egg can be dropped without breaking, in as few drops as possible. If an egg is dropped from above its target floor it will break. If it is dropped from that floor or below, it will be intact and you can test drop the egg again on another floor.**\n", + "\n", + "**Show algorithmically how you would go about doing this in as few drops as possible**\n", + "## Requirements\n", + "\n", + "** Use paper/pencil or a whiteboard for this problem **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "** We've already seen this problem in the Riddles section, here is the answer from that section.(Alternatively just google \"2 eggs 100 floors\" for a plethora of explanations regarding this same solution **\n", + "\n", + "\n", + "Start from the 10th floor and go up to floors in multiples of 10.\n", + "\n", + "If first egg breaks, say at 20th floor then you can check all the floors between 11th and 19th with the second egg to see which floor it will not break.\n", + "\n", + "In this case, the worst-case number of drops is 19. If the threshold was 99th floor, then you would have to drop the first egg 10 times and the second egg 9 times in linear fashion.\n", + "\n", + "**Best solution:**\n", + "We need to minimize this worst-case number of drops. For that, we need to generalize the problem to have n floors. What would be the step value, for the first egg? Would it still be 10? Suppose we have 200 floors. Would the step value be still 10? \n", + "\n", + "The point to note here is that we are trying to minimize the worst-case number of drops which happens if the threshold is at the highest floors. So, our steps should be of some value which reduces the number of drops of the first egg.\n", + "\n", + "Let's assume we take some step value m initially. If every subsequent step is m-1,\n", + "then, \n", + "$$m+m−1+m−2+.....+1=n$$\n", + "\n", + "This is \n", + "\n", + "$$\\frac{m∗(m+1)}{2}=n$$\n", + "\n", + "If n =100, then m would be 13.65 which since we can't drop from a decimal of a floor, we actually use 14.\n", + "\n", + "So, the worst case scenario is now when the threshold is in the first 14 floors with number of drops being 14.\n", + "\n", + "Note that this is simply a binary search!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 1-checkpoint.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 1-checkpoint.ipynb new file mode 100644 index 00000000..301d05a0 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 1-checkpoint.ipynb @@ -0,0 +1,56 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 \n", + "\n", + "## Problem\n", + "\n", + "** You've been given a list of historical stock prices for a single day for Amazon stock. The index of the list represents the timestamp, so the element at index of 0 is the initial price of the stock, the element at index 1 is the next recorded price of the stock for that day, etc. Your task is to write a function that will return the maximum profit possible from the purchase and sale of a single share of Amazon stock on that day. Keep in mind to try to make this as efficient as possible.**\n", + "\n", + "\n", + "For example, if you were given the list of stock prices:\n", + "\n", + "prices = [12,11,15,3,10]\n", + "\n", + "Then your function would return the maximum possible profit, which would be 7 (buying at 3 and selling at 10).\n", + "\n", + "## Requirements\n", + "\n", + "** Try to solve this problem with paper/pencil first without using an IDE. Also keep in mind you should be able to come up with a better solution than just brute forcing every possible sale combination **\n", + "\n", + "** Also you can't \"short\" a stock, you must buy *before* you sell the stock. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb new file mode 100644 index 00000000..03231384 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb @@ -0,0 +1,51 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 \n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers, write a function that will return a list, in which for each index the element will be the product of all the integers except for the element at that index **\n", + "\n", + "**For example, an input of [1,2,3,4] would return [24,12,8,6] by performing [2×3×4,1×3×4,1×2×4,1×2×3] **\n", + "\n", + "## Requirements\n", + "\n", + "** You can not use division in your answer! Meaning you can't simply multiply all the numbers and then divide by eahc element for each index!**\n", + "\n", + "** Try to do this on a white board or with paper/pencil.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 3-checkpoint.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 3-checkpoint.ipynb new file mode 100644 index 00000000..b7d2c7e4 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/On-Site Question 3-checkpoint.ipynb @@ -0,0 +1,78 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3\n", + "\n", + "## Problem\n", + "\n", + "**Given two rectangles, determine if they overlap. The rectangles are defined as a Dictionary, for example:**" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "r1 = {\n", + " \n", + " # x and y coordinates of the bottom-left corner of the rectangle\n", + " 'x': 2 , 'y': 4,\n", + " \n", + " # Width and Height of rectangle\n", + " 'w':5,'h':12}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** If the rectangles do overlap, return the dictionary which describes the overlapping section**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Requirements\n", + "\n", + "** Make sure the dictionary you output is in the same form as the input.**\n", + "\n", + "** Feel free to use an IDE for the code, but make sure you use paper/pencil or whiteboard to draw out your plan and logic**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb new file mode 100644 index 00000000..f9dd3787 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen \n", + "\n", + "## Problem\n", + "\n", + "**A tower has 100 floors. You've been given two eggs. The eggs are strong enough that they can be dropped from a particular floor in the tower without breaking. You've been tasked to find the highest floor an egg can be dropped without breaking, in as few drops as possible. If an egg is dropped from above its target floor it will break. If it is dropped from that floor or below, it will be intact and you can test drop the egg again on another floor.**\n", + "\n", + "**Show algorithmically how you would go about doing this in as few drops as possible**\n", + "\n", + "## Requirements\n", + "\n", + "** Use paper/pencil or a whiteboard for this problem **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 1.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 1.ipynb new file mode 100644 index 00000000..301d05a0 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 1.ipynb @@ -0,0 +1,56 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 \n", + "\n", + "## Problem\n", + "\n", + "** You've been given a list of historical stock prices for a single day for Amazon stock. The index of the list represents the timestamp, so the element at index of 0 is the initial price of the stock, the element at index 1 is the next recorded price of the stock for that day, etc. Your task is to write a function that will return the maximum profit possible from the purchase and sale of a single share of Amazon stock on that day. Keep in mind to try to make this as efficient as possible.**\n", + "\n", + "\n", + "For example, if you were given the list of stock prices:\n", + "\n", + "prices = [12,11,15,3,10]\n", + "\n", + "Then your function would return the maximum possible profit, which would be 7 (buying at 3 and selling at 10).\n", + "\n", + "## Requirements\n", + "\n", + "** Try to solve this problem with paper/pencil first without using an IDE. Also keep in mind you should be able to come up with a better solution than just brute forcing every possible sale combination **\n", + "\n", + "** Also you can't \"short\" a stock, you must buy *before* you sell the stock. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 2 .ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 2 .ipynb new file mode 100644 index 00000000..a68bb887 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 2 .ipynb @@ -0,0 +1,51 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 \n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers, write a function that will return a list, in which for each index the element will be the product of all the integers except for the element at that index **\n", + "\n", + "**For example, an input of [1,2,3,4] would return [24,12,8,6] by performing [2×3×4,1×3×4,1×2×4,1×2×3] **\n", + "\n", + "## Requirements\n", + "\n", + "** You can not use division in your answer! Meaning you can't simply multiply all the numbers and then divide by eahc element for each index!**\n", + "\n", + "** Try to do this on a white board or with paper/pencil.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 3.ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 3.ipynb new file mode 100644 index 00000000..b7d2c7e4 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/On-Site Question 3.ipynb @@ -0,0 +1,78 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3\n", + "\n", + "## Problem\n", + "\n", + "**Given two rectangles, determine if they overlap. The rectangles are defined as a Dictionary, for example:**" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "r1 = {\n", + " \n", + " # x and y coordinates of the bottom-left corner of the rectangle\n", + " 'x': 2 , 'y': 4,\n", + " \n", + " # Width and Height of rectangle\n", + " 'w':5,'h':12}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** If the rectangles do overlap, return the dictionary which describes the overlapping section**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Requirements\n", + "\n", + "** Make sure the dictionary you output is in the same form as the input.**\n", + "\n", + "** Feel free to use an IDE for the code, but make sure you use paper/pencil or whiteboard to draw out your plan and logic**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/Phone Screen .ipynb b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/Phone Screen .ipynb new file mode 100644 index 00000000..f9dd3787 --- /dev/null +++ b/Mock Interviews/Large E-Commerce Company/E-Commerce Company - Interview Problems/Phone Screen .ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen \n", + "\n", + "## Problem\n", + "\n", + "**A tower has 100 floors. You've been given two eggs. The eggs are strong enough that they can be dropped from a particular floor in the tower without breaking. You've been tasked to find the highest floor an egg can be dropped without breaking, in as few drops as possible. If an egg is dropped from above its target floor it will break. If it is dropped from that floor or below, it will be intact and you can test drop the egg again on another floor.**\n", + "\n", + "**Show algorithmically how you would go about doing this in as few drops as possible**\n", + "\n", + "## Requirements\n", + "\n", + "** Use paper/pencil or a whiteboard for this problem **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..df89907a --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,127 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 - SOLUTION\n", + "___\n", + "\n", + "## Question\n", + "** Given a dice which rolls 1 to 7 (with uniform probability), simulate a 5 sided dice. Preferably, write your solution as a function. **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST do this on pen and paper or on a whiteboard. No actual coding is allowed until you've solved it on pen and paper! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SOLUTION\n", + "\n", + "This is a new problem we haven't seen directly before! Many times this question is asked in the form of functions e.g. your given a function random_7() and you have to take it as an input and create random_5()\n", + "\n", + "The key to solving this problem is to make sure you focus on the requirement that the final distribution of the rolls be uniform, also you were not given any requirements on Time and Space, so the solution is actually *very* simple, just keep re-rolling if you get a number greater than 5!\n", + "\n", + "We can code this out:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from random import randint\n", + " \n", + "def dice7():\n", + " return randint(1, 7)\n", + " \n", + "# Our Solution\n", + "def convert7to5():\n", + " \n", + " # Starting roll (just needs to be larger than 5)\n", + " roll = 7\n", + " \n", + " while roll > 5:\n", + " \n", + " roll = dice7()\n", + " print 'dice7() produced a roll of ',roll\n", + " print ' Your final returned roll is below:'\n", + " return roll" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dice7() produced a roll of 7\n", + "dice7() produced a roll of 5\n", + " Your final returned roll is below:\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "convert7to5()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, the next problem (On-Site Question 2) will be harder, the reverse conversion of rolls! This question should serve as a reminder not to overthink the solution to a question! Keep in mind that our solution has the potential to run for infinity if we keep rolling 6s and 7s (although this is highly unlikely).\n", + "\n", + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..6d44e71a --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 - SOLUTION\n", + "___\n", + "\n", + "## Question\n", + "** Given a dice which rolls from 1 to 5, simulate a uniform 7 sided dice! **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST do this on pen and paper or on a whiteboard. No actual coding is allowed until you've come up with a solution by hand! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SOLUTION\n", + "\n", + "Because the 5 sided dice can not produce 7 possible outcomes on a single roll, we immediately know that we need to roll the dice at least twice. \n", + "\n", + "If we roll the dice twice we have 25 possible combinations of the results of the two rolls. While 25 is not divisible by 7, 21 is. This means we can implement our previous strategy of throwing out rolls not in our intended range.\n", + "\n", + "It's also important to note that we can't expand the solution to implement more rolls in order to not throw any out, because 5 and 7 are both prime which means that no exponent of 5 will be divisible by 7 no matter how high you go.\n", + "\n", + "We will define our range as a section of the 25 possible combinations of rolls. A good way to do this is by converting the two rolls into a unique outcome number in the range 1 through 25.\n", + "\n", + "We will create this number by taking the rolls, then we take the first roll and after subtracting 1 from it we multiply it by 4. Now the first roll corresponds with a value of 1 - 20.\n", + "\n", + "Then we take the second roll and add it to the result of the first manipulation. Giving us a range of 1-25.\n", + "\n", + "So our final solution is to roll the dice twice. Check the manipulated range from 1 to 25, if its greater than 21, do a reroll. Let's see it in action:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from random import randint\n", + " \n", + "def dice5():\n", + " return randint(1, 5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now for our conversion function:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def convert5to7():\n", + "\n", + " # For constant re-roll purposes\n", + " while True:\n", + "\n", + " # Roll the dice twice\n", + " roll_1 = dice5()\n", + " roll_2 = dice5()\n", + " \n", + " #print 'The rolls were {} and {}'.format(roll_1,roll_2)\n", + "\n", + " # Convert the combination to the range 1 to 25\n", + " num = ( (roll_1-1) * 5 ) + ( roll_2 ) \n", + "\n", + " #print 'The converted range number was:',num\n", + " if num > 21:\n", + "\n", + " # re-roll if we are out of range\n", + " continue\n", + "\n", + " return num %7 + 1 " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "convert5to7()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 -SOLUTION-checkpoint.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 -SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..1e53ad72 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 -SOLUTION-checkpoint.ipynb @@ -0,0 +1,91 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 - SOLUTION\n", + "\n", + "## Question\n", + "\n", + "**Given a string, write a function that uses recursion to reverse it. **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST use pen and paper or a whiteboard to answer this, no coding allowed! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SOLUTION\n", + "\n", + "Hopefully you remember this problem, you've already seen it! The solution is:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def reverse(s):\n", + " \n", + " # Base Case\n", + " if len(s) <= 1:\n", + " return s\n", + "\n", + " # Recursion\n", + " return reverse(s[1:]) + s[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___\n", + "## Notes\n", + "\n", + "Remember when recursion questions arise, think about the base case and the recursive case. Review the recusion section of the course for review for this problem." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 4 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 4 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..8c32f0a1 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 4 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,263 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 4 - SOLUTION\n", + "\n", + "## Question\n", + "**Find the squareroot of a given number rounded down to the nearest integer, without using the sqrt function. For example, squareroot of a number between [9, 15] should return 3, and [16, 24] should be 4.**\n", + "\n", + "## Requirements\n", + "\n", + "** Feel free to code this out (but its recommended that you use paper/pencil or whiteboard)**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "The squareroot of a (non-negative) number N always lies between 0 and N/2. The straightforward way to solve this problem would be to check every number k between 0 and N/2, until the square of k becomes greater than or rqual to N. If k^2 becomes equal to N, then we return k. Otherwise, we return k-1 because we're rounding down. Here's the code:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(num): \n", + " if num<0: \n", + " raise ValueError \n", + " if num==1: \n", + " return 1 \n", + " for k in range(1+(num/2)): \n", + " if k**2==num: \n", + " return k \n", + " elif k**2>num: \n", + " return k-1 \n", + " return k " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution(14)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution(15)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution(16)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The complexity of this approach is O(N), because we have to check N/2 numbers in the worst case. This linear algorithm is pretty inefficient, we can use some sort of binary search to speed it up. We know that the result is between 0 and N/2, so we can first try N/4 to see whether its square is less than, greater than, or equal to N. If it’s equal then we simply return that value. If it’s less, then we continue our search between N/4 and N/2. Otherwise if it’s greater, then we search between 0 and N/4. In both cases we reduce the potential range by half and continue, this is the logic of binary search. We’re not performing regular binary search though, it’s modified. We want to ensure that we stop at a number k, where k^2<=N but (k+1)^2>N. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def better_solution(num): \n", + " if num<0: \n", + " raise ValueError \n", + " if num==1: \n", + " return 1 \n", + " low=0 \n", + " high=1+(num/2) \n", + " \n", + " while low+1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " Fib(n=15000)\n", + "\n", + "\n", + "loops\n", + "recursion\n", + "generators\n", + "memoization\n", + "memoization as decorator\n", + "\n", + "\n", + "45\n", + "87\n", + "58\n", + "44\n", + "43\n", + "\n", + "\n", + "47\n", + "88\n", + "58\n", + "42\n", + "42\n", + "\n", + "\n", + "51\n", + "92\n", + "60\n", + "44\n", + "43\n", + "\n", + "\n", + "43\n", + "87\n", + "58\n", + "42\n", + "43\n", + "\n", + "\n", + "48\n", + "92\n", + "61\n", + "42\n", + "44\n", + "\n", + "\n", + "45\n", + "87\n", + "59\n", + "43\n", + "44\n", + "\n", + "\n", + "44\n", + "85\n", + "57\n", + "42\n", + "44\n", + "\n", + "\n", + "44\n", + "87\n", + "62\n", + "43\n", + "43\n", + "\n", + "\n", + "48\n", + "86\n", + "59\n", + "42\n", + "43\n", + "\n", + "\n", + "45\n", + "91\n", + "61\n", + "45\n", + "45\n", + "\n", + "\n", + "46\n", + "88.2\n", + "59.3\n", + "42.9\n", + "43.4 (Avg)\n", + "\n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb new file mode 100644 index 00000000..df89907a --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb @@ -0,0 +1,127 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 - SOLUTION\n", + "___\n", + "\n", + "## Question\n", + "** Given a dice which rolls 1 to 7 (with uniform probability), simulate a 5 sided dice. Preferably, write your solution as a function. **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST do this on pen and paper or on a whiteboard. No actual coding is allowed until you've solved it on pen and paper! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SOLUTION\n", + "\n", + "This is a new problem we haven't seen directly before! Many times this question is asked in the form of functions e.g. your given a function random_7() and you have to take it as an input and create random_5()\n", + "\n", + "The key to solving this problem is to make sure you focus on the requirement that the final distribution of the rolls be uniform, also you were not given any requirements on Time and Space, so the solution is actually *very* simple, just keep re-rolling if you get a number greater than 5!\n", + "\n", + "We can code this out:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from random import randint\n", + " \n", + "def dice7():\n", + " return randint(1, 7)\n", + " \n", + "# Our Solution\n", + "def convert7to5():\n", + " \n", + " # Starting roll (just needs to be larger than 5)\n", + " roll = 7\n", + " \n", + " while roll > 5:\n", + " \n", + " roll = dice7()\n", + " print 'dice7() produced a roll of ',roll\n", + " print ' Your final returned roll is below:'\n", + " return roll" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dice7() produced a roll of 7\n", + "dice7() produced a roll of 5\n", + " Your final returned roll is below:\n" + ] + }, + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "convert7to5()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, the next problem (On-Site Question 2) will be harder, the reverse conversion of rolls! This question should serve as a reminder not to overthink the solution to a question! Keep in mind that our solution has the potential to run for infinity if we keep rolling 6s and 7s (although this is highly unlikely).\n", + "\n", + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb new file mode 100644 index 00000000..b3c51b99 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 - SOLUTION\n", + "___\n", + "\n", + "## Question\n", + "** Given a dice which rolls from 1 to 5, simulate a uniform 7 sided dice! **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST do this on pen and paper or on a whiteboard. No actual coding is allowed until you've come up with a solution by hand! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SOLUTION\n", + "\n", + "Because the 5 sided dice can not produce 7 possible outcomes on a single roll, we immediately know that we need to roll the dice at least twice. \n", + "\n", + "If we roll the dice twice we have 25 possible combinations of the results of the two rolls. While 25 is not divisible by 7, 21 is. This means we can implement our previous strategy of throwing out rolls not in our intended range.\n", + "\n", + "It's also important to note that we can't expand the solution to implement more rolls in order to not throw any out, because 5 and 7 are both prime which means that no exponent of 5 will be divisible by 7 no matter how high you go.\n", + "\n", + "We will define our range as a section of the 25 possible combinations of rolls. A good way to do this is by converting the two rolls into a unique outcome number in the range 1 through 25.\n", + "\n", + "We will create this number by taking the rolls, then we take the first roll and after subtracting 1 from it we multiply it by 5. Now the first roll corresponds with a value of 0, 5, 10, 15 and 20.\n", + "\n", + "Then we take the second roll and add it to the result of the first manipulation. Giving us a range of 1-25.\n", + "\n", + "So our final solution is to roll the dice twice. Check the manipulated range from 1 to 25, if its greater than 21, do a reroll. Let's see it in action:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from random import randint\n", + " \n", + "def dice5():\n", + " return randint(1, 5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now for our conversion function:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def convert5to7():\n", + "\n", + " # For constant re-roll purposes\n", + " while True:\n", + "\n", + " # Roll the dice twice\n", + " roll_1 = dice5()\n", + " roll_2 = dice5()\n", + " \n", + " #print 'The rolls were {} and {}'.format(roll_1,roll_2)\n", + "\n", + " # Convert the combination to the range 1 to 25\n", + " num = ( (roll_1-1) * 5 ) + ( roll_2 ) \n", + "\n", + " #print 'The converted range number was:',num\n", + " if num > 21:\n", + "\n", + " # re-roll if we are out of range\n", + " continue\n", + "\n", + " return num %7 + 1 " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "convert5to7()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 3 -SOLUTION.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 3 -SOLUTION.ipynb new file mode 100644 index 00000000..1e53ad72 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 3 -SOLUTION.ipynb @@ -0,0 +1,91 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 - SOLUTION\n", + "\n", + "## Question\n", + "\n", + "**Given a string, write a function that uses recursion to reverse it. **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST use pen and paper or a whiteboard to answer this, no coding allowed! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SOLUTION\n", + "\n", + "Hopefully you remember this problem, you've already seen it! The solution is:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def reverse(s):\n", + " \n", + " # Base Case\n", + " if len(s) <= 1:\n", + " return s\n", + "\n", + " # Recursion\n", + " return reverse(s[1:]) + s[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___\n", + "## Notes\n", + "\n", + "Remember when recursion questions arise, think about the base case and the recursive case. Review the recusion section of the course for review for this problem." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 4 - SOLUTION.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 4 - SOLUTION.ipynb new file mode 100644 index 00000000..8c32f0a1 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems - SOLUTIONS/On-Site Question 4 - SOLUTION.ipynb @@ -0,0 +1,263 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 4 - SOLUTION\n", + "\n", + "## Question\n", + "**Find the squareroot of a given number rounded down to the nearest integer, without using the sqrt function. For example, squareroot of a number between [9, 15] should return 3, and [16, 24] should be 4.**\n", + "\n", + "## Requirements\n", + "\n", + "** Feel free to code this out (but its recommended that you use paper/pencil or whiteboard)**" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "The squareroot of a (non-negative) number N always lies between 0 and N/2. The straightforward way to solve this problem would be to check every number k between 0 and N/2, until the square of k becomes greater than or rqual to N. If k^2 becomes equal to N, then we return k. Otherwise, we return k-1 because we're rounding down. Here's the code:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(num): \n", + " if num<0: \n", + " raise ValueError \n", + " if num==1: \n", + " return 1 \n", + " for k in range(1+(num/2)): \n", + " if k**2==num: \n", + " return k \n", + " elif k**2>num: \n", + " return k-1 \n", + " return k " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution(14)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution(15)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution(16)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The complexity of this approach is O(N), because we have to check N/2 numbers in the worst case. This linear algorithm is pretty inefficient, we can use some sort of binary search to speed it up. We know that the result is between 0 and N/2, so we can first try N/4 to see whether its square is less than, greater than, or equal to N. If it’s equal then we simply return that value. If it’s less, then we continue our search between N/4 and N/2. Otherwise if it’s greater, then we search between 0 and N/4. In both cases we reduce the potential range by half and continue, this is the logic of binary search. We’re not performing regular binary search though, it’s modified. We want to ensure that we stop at a number k, where k^2<=N but (k+1)^2>N. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def better_solution(num): \n", + " if num<0: \n", + " raise ValueError \n", + " if num==1: \n", + " return 1 \n", + " low=0 \n", + " high=1+(num/2) \n", + " \n", + " while low+1\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " Fib(n=15000)\n", + "\n", + "\n", + "loops\n", + "recursion\n", + "generators\n", + "memoization\n", + "memoization as decorator\n", + "\n", + "\n", + "45\n", + "87\n", + "58\n", + "44\n", + "43\n", + "\n", + "\n", + "47\n", + "88\n", + "58\n", + "42\n", + "42\n", + "\n", + "\n", + "51\n", + "92\n", + "60\n", + "44\n", + "43\n", + "\n", + "\n", + "43\n", + "87\n", + "58\n", + "42\n", + "43\n", + "\n", + "\n", + "48\n", + "92\n", + "61\n", + "42\n", + "44\n", + "\n", + "\n", + "45\n", + "87\n", + "59\n", + "43\n", + "44\n", + "\n", + "\n", + "44\n", + "85\n", + "57\n", + "42\n", + "44\n", + "\n", + "\n", + "44\n", + "87\n", + "62\n", + "43\n", + "43\n", + "\n", + "\n", + "48\n", + "86\n", + "59\n", + "42\n", + "43\n", + "\n", + "\n", + "45\n", + "91\n", + "61\n", + "45\n", + "45\n", + "\n", + "\n", + "46\n", + "88.2\n", + "59.3\n", + "42.9\n", + "43.4 (Avg)\n", + "\n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 1 -checkpoint.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 1 -checkpoint.ipynb new file mode 100644 index 00000000..c4514711 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 1 -checkpoint.ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 \n", + "___\n", + "\n", + "## Question\n", + "** Given a dice which rolls 1 to 7 (with uniform probability), simulate a 5 sided dice. Preferably, write your solution as a function. **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST do this on pen and paper or on a whiteboard. No actual coding is allowed until you've solved it on pen and paper! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb new file mode 100644 index 00000000..a63ca005 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 \n", + "___\n", + "\n", + "## Question\n", + "** Given a dice which rolls from 1 to 5, simulate a uniform 7 sided dice! **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST do this on pen and paper or on a whiteboard. No actual coding is allowed until you've come up with a solution by hand! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 3 -checkpoint.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 3 -checkpoint.ipynb new file mode 100644 index 00000000..49a04c0d --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 3 -checkpoint.ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 \n", + "\n", + "## Question\n", + "\n", + "**Given a string, write a function that uses recursion to reverse it. **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST use pen and paper or a whiteboard to answer this, no coding allowed! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 4 -checkpoint.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 4 -checkpoint.ipynb new file mode 100644 index 00000000..d69bf130 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/On-Site Question 4 -checkpoint.ipynb @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 4 \n", + "\n", + "## Question\n", + "**Find the squareroot of a given number rounded down to the nearest integer, without using the sqrt function. For example, squareroot of a number between [9, 15] should return 3, and [16, 24] should be 4.**\n", + "\n", + "## Requirements\n", + "\n", + "** Feel free to code this out (but its recommended that you use paper/pencil or whiteboard)**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/Phone Screen-checkpoint.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/Phone Screen-checkpoint.ipynb new file mode 100644 index 00000000..8edb0203 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/.ipynb_checkpoints/Phone Screen-checkpoint.ipynb @@ -0,0 +1,80 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen\n", + "\n", + "**This phone screen will consist of a non-technical series of questions about you and the company, and then a second half of a simple technical question to be coded out**\n", + "___\n", + "## Non-Technical Questions\n", + "\n", + "**Answer the following questions (2-5 minute responses) technical answers not required, more interested in hearing about your reasoning**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Give me some quick background about you (go over your resume)\n", + "* Why do you want to work here?\n", + "* What's your favorite programming language and why?\n", + "* Where do you see yourself in 5 years?\n", + "* Do you have any questions about the company for me?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___\n", + "## Technical Questions\n", + "\n", + "**Answer the following question in the *Markdown* cell below. It's important to note that the cell below does NOT have syntax highlighting, its common in a phone screen interview to be given a text editor hich doesn't have anything more than basic text support**\n", + "\n", + "1. Write a function that computes the Nth fibonacci number" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 1 .ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 1 .ipynb new file mode 100644 index 00000000..c4514711 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 1 .ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 \n", + "___\n", + "\n", + "## Question\n", + "** Given a dice which rolls 1 to 7 (with uniform probability), simulate a 5 sided dice. Preferably, write your solution as a function. **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST do this on pen and paper or on a whiteboard. No actual coding is allowed until you've solved it on pen and paper! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 2 .ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 2 .ipynb new file mode 100644 index 00000000..a63ca005 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 2 .ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 \n", + "___\n", + "\n", + "## Question\n", + "** Given a dice which rolls from 1 to 5, simulate a uniform 7 sided dice! **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST do this on pen and paper or on a whiteboard. No actual coding is allowed until you've come up with a solution by hand! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 3 .ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 3 .ipynb new file mode 100644 index 00000000..49a04c0d --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 3 .ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 \n", + "\n", + "## Question\n", + "\n", + "**Given a string, write a function that uses recursion to reverse it. **\n", + "\n", + "## Requirements\n", + "\n", + "** You MUST use pen and paper or a whiteboard to answer this, no coding allowed! **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 4 .ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 4 .ipynb new file mode 100644 index 00000000..d69bf130 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/On-Site Question 4 .ipynb @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 4 \n", + "\n", + "## Question\n", + "**Find the squareroot of a given number rounded down to the nearest integer, without using the sqrt function. For example, squareroot of a number between [9, 15] should return 3, and [16, 24] should be 4.**\n", + "\n", + "## Requirements\n", + "\n", + "** Feel free to code this out (but its recommended that you use paper/pencil or whiteboard)**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/Phone Screen.ipynb b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/Phone Screen.ipynb new file mode 100644 index 00000000..8edb0203 --- /dev/null +++ b/Mock Interviews/Large Search Engine Company_/Search Engine Company - Interview Problems/Phone Screen.ipynb @@ -0,0 +1,80 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen\n", + "\n", + "**This phone screen will consist of a non-technical series of questions about you and the company, and then a second half of a simple technical question to be coded out**\n", + "___\n", + "## Non-Technical Questions\n", + "\n", + "**Answer the following questions (2-5 minute responses) technical answers not required, more interested in hearing about your reasoning**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "* Give me some quick background about you (go over your resume)\n", + "* Why do you want to work here?\n", + "* What's your favorite programming language and why?\n", + "* Where do you see yourself in 5 years?\n", + "* Do you have any questions about the company for me?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___\n", + "## Technical Questions\n", + "\n", + "**Answer the following question in the *Markdown* cell below. It's important to note that the cell below does NOT have syntax highlighting, its common in a phone screen interview to be given a text editor hich doesn't have anything more than basic text support**\n", + "\n", + "1. Write a function that computes the Nth fibonacci number" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..a471b4b1 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers, find the largest product you could make from 3 integers in the list **\n", + "\n", + "## Requirements\n", + "\n", + "** You can assume that the list will always have at least 3 integers **\n", + "\n", + "** Paper/pencil only, don't code this out until you've solved it as far as you can by hand. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "We can solve this problem in O(n) time with O(1) space, we should also be able to take into account negative numbers, so that a list like: [-5,-5,1,3] returns (-5)(-5)(3) = 75 as its answer.\n", + "\n", + "Hopefully you've begun to realize the similarity between this problem and the Amazon stock problem from the E-Commerce Company mock interview questions! You could brute force this problem by just simply trying every single combination of three digits, but this would require O(n^3) time!\n", + "\n", + "How about we use a greedy approach and keep track of some numbers. In the stock problem we kept track of max profit so far, in this problem we are actually going to keep track of several numbers:\n", + "\n", + "* The highest product of 3 numbers so far\n", + "* The highest product of 2 numbers so far\n", + "* The highest number so far\n", + "\n", + "Since we want to keep negative numbers in account, we will also keep track of the lowest product of two and the lowest number:\n", + "\n", + "* The lowest product of 2\n", + "* The lowest number\n", + "\n", + "Once we iterate through the list and reach the end we will have the highest posiible product with 3 numbers. At each iteration we will take the current highest product of 3 and compare it to the current integer multiplied by the highest and lowest products of 2.\n", + "\n", + "Let's see this coded out:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(lst):\n", + " \n", + " # Start at index 2 (3rd element) and assign highest and lowest \n", + " # based off of first two elements\n", + " \n", + " # Highest Number so far\n", + " high = max(lst[0],lst[1])\n", + " \n", + " # Lowest number so far\n", + " low = min(lst[0],lst[1])\n", + " \n", + " # Initiate Highest and lowest products of two numbers\n", + " high_prod2 = lst[0]*lst[1]\n", + " low_prod2 = lst[0]*lst[1]\n", + " \n", + " # Initiate highest product of 3 numbers\n", + " high_prod3 = lst[0]*lst[1]*lst[2]\n", + " \n", + " # Iterate through list\n", + " for num in lst[2:]:\n", + " \n", + " # Compare possible highest product of 3 numbers\n", + " high_prod3 = max(high_prod3,num*high_prod2,num*low_prod2)\n", + " \n", + " \n", + " # Check for possible new highest products of 2 numbers\n", + " high_prod2 = max(high_prod2,num*high,num*low)\n", + " \n", + " # Check for possible new lowest products of 2 numbers\n", + " low_prod2 = min(low_prod2,num*high,num*low)\n", + " \n", + " # Check for new possible high\n", + " high = max(high,num)\n", + " \n", + " # Check for new possible low\n", + " low = min(low,num)\n", + " \n", + " return high_prod3" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "763092" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "l = [99,-82,82,40,75,-24,39, -82, 5, 30, -25, -94, 93, -23, 48, 50, 49,-81,41,63]\n", + "\n", + "solution(l)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great! Through the use of a greedy approach we have been able to complete the problem in O(n) time. Keep this sort of approach in mind when you have to iterate through a list and a brute force solution is on the order of an exponential!\n", + "\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..0c613795 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Write a function that given a target amount of money and a list of possible coin denominations, returns the number of ways to make change for the target amount using the coin denominations**\n", + "\n", + "## Requirements\n", + "\n", + "** Write out your work on paper/pencil, then see if you can code up your solution **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "This is a classic interview problem, so classic that you've already seen a very similar problem in the recursion section! Make sure to review that problem first before reading our solution here!\n", + "\n", + "In this solution we will use a [bottom-up](https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design) algorithm.\n", + "\n", + "* As we iterate through each coin, we are adding the ways of making arr[i - coin] to arr[i]\n", + "* If we have 2 ways of making 4, and are now iterating on a coin of value 3, there should be 2 ways of making 7.\n", + "* We are essentially adding the coin we are iterating on to the number of ways of making arr[i]." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(n, coins):\n", + " \n", + " # Set up our array for trakcing results\n", + " arr = [1] + [0] * n\n", + " \n", + " for coin in coins:\n", + " for i in range(coin, n + 1):\n", + " arr[i] += arr[i - coin]\n", + " \n", + " if n == 0:\n", + " return 0\n", + " else:\n", + " return arr[n]\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "884" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution(100, [1, 2, 3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This solution results in O((m)(n)) with m being the number of coins, where we iterate about n operations. This is O(n) space." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..238cc667 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a binary tree, check whether it’s a binary search tree or not. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Requirements\n", + "\n", + "** Use paper/pencil, do not code this in an IDE until you've done it manually**\n", + "\n", + "** Do not use built-in Python libraries to do this, but do mention them if you know about them **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "The first solution that comes to mind is, at every node check whether its value is larger than or equal to its left child and smaller than or equal to its right child (assuming equals can appear at either left or right). However, this approach is erroneous because it doesn’t check whether a node violates any condition with its grandparent or any of its ancestors. \n", + "\n", + "So, we should keep track of the minimum and maximum values a node can take. And at each node we will check whether its value is between the min and max values it’s allowed to take. The root can take any value between negative infinity and positive infinity. At any node, its left child should be smaller than or equal than its own value, and similarly the right child should be larger than or equal to. So during recursion, we send the current value as the new max to our left child and send the min as it is without changing. And to the right child, we send the current value as the new min and send the max without changing. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class Node: \n", + " def __init__(self, val=None): \n", + " self.left, self.right, self.val = None, None, val \n", + " \n", + "INFINITY = float(\"infinity\") \n", + "NEG_INFINITY = float(\"-infinity\") \n", + "\n", + "def isBST(tree, minVal=NEG_INFINITY, maxVal=INFINITY): \n", + " if tree is None:\n", + " return True \n", + " if not minVal <= tree.val <= maxVal: \n", + " return False \n", + " \n", + " return isBST(tree.left, minVal, tree.val) and isBST(tree.right, tree.val, maxVal) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There’s an equally good alternative solution. If a tree is a binary search tree, then traversing the tree inorder should lead to sorted order of the values in the tree. So, we can perform an inorder traversal and check whether the node values are sorted or not." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def isBST2(tree, lastNode=[NEG_INFINITY]): \n", + " \n", + " if tree is None: \n", + " return True \n", + " \n", + " if not isBST2(tree.left, lastNode):\n", + " return False \n", + " \n", + " if tree.val < lastNode[0]: \n", + " return False \n", + " \n", + " lastNode[0]=tree.val \n", + " \n", + " return isBST2(tree.right, lastNode) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a common interview problem, its relatively simple, but not trivial and shows that someone has a knowledge of binary search trees and tree traversals.\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..662e8373 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb @@ -0,0 +1,53 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** If you were given a list of n integers and knew that they were sorted, how quickly could you check if a given integer was in the list? Elaborate on your reasoning and search methods in general**\n", + "\n", + "## Requirements\n", + "\n", + "** Try explaining your solution to someone and see if it makes sense ot them. Don't code anything for this problem **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Hopefully this problem sounds familiar! We can use a binary search to search for an intger since the list is already sorted! This means we can find the item in [O(logn) time and O(1) space](http://bigocheatsheet.com/)!\n", + "\n", + "Revisit the lectures on Binary Search and its implementation to fully get the reasoning behind this solution and problem!\n", + "\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb new file mode 100644 index 00000000..a471b4b1 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers, find the largest product you could make from 3 integers in the list **\n", + "\n", + "## Requirements\n", + "\n", + "** You can assume that the list will always have at least 3 integers **\n", + "\n", + "** Paper/pencil only, don't code this out until you've solved it as far as you can by hand. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "We can solve this problem in O(n) time with O(1) space, we should also be able to take into account negative numbers, so that a list like: [-5,-5,1,3] returns (-5)(-5)(3) = 75 as its answer.\n", + "\n", + "Hopefully you've begun to realize the similarity between this problem and the Amazon stock problem from the E-Commerce Company mock interview questions! You could brute force this problem by just simply trying every single combination of three digits, but this would require O(n^3) time!\n", + "\n", + "How about we use a greedy approach and keep track of some numbers. In the stock problem we kept track of max profit so far, in this problem we are actually going to keep track of several numbers:\n", + "\n", + "* The highest product of 3 numbers so far\n", + "* The highest product of 2 numbers so far\n", + "* The highest number so far\n", + "\n", + "Since we want to keep negative numbers in account, we will also keep track of the lowest product of two and the lowest number:\n", + "\n", + "* The lowest product of 2\n", + "* The lowest number\n", + "\n", + "Once we iterate through the list and reach the end we will have the highest posiible product with 3 numbers. At each iteration we will take the current highest product of 3 and compare it to the current integer multiplied by the highest and lowest products of 2.\n", + "\n", + "Let's see this coded out:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(lst):\n", + " \n", + " # Start at index 2 (3rd element) and assign highest and lowest \n", + " # based off of first two elements\n", + " \n", + " # Highest Number so far\n", + " high = max(lst[0],lst[1])\n", + " \n", + " # Lowest number so far\n", + " low = min(lst[0],lst[1])\n", + " \n", + " # Initiate Highest and lowest products of two numbers\n", + " high_prod2 = lst[0]*lst[1]\n", + " low_prod2 = lst[0]*lst[1]\n", + " \n", + " # Initiate highest product of 3 numbers\n", + " high_prod3 = lst[0]*lst[1]*lst[2]\n", + " \n", + " # Iterate through list\n", + " for num in lst[2:]:\n", + " \n", + " # Compare possible highest product of 3 numbers\n", + " high_prod3 = max(high_prod3,num*high_prod2,num*low_prod2)\n", + " \n", + " \n", + " # Check for possible new highest products of 2 numbers\n", + " high_prod2 = max(high_prod2,num*high,num*low)\n", + " \n", + " # Check for possible new lowest products of 2 numbers\n", + " low_prod2 = min(low_prod2,num*high,num*low)\n", + " \n", + " # Check for new possible high\n", + " high = max(high,num)\n", + " \n", + " # Check for new possible low\n", + " low = min(low,num)\n", + " \n", + " return high_prod3" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "763092" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "l = [99,-82,82,40,75,-24,39, -82, 5, 30, -25, -94, 93, -23, 48, 50, 49,-81,41,63]\n", + "\n", + "solution(l)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great! Through the use of a greedy approach we have been able to complete the problem in O(n) time. Keep this sort of approach in mind when you have to iterate through a list and a brute force solution is on the order of an exponential!\n", + "\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb new file mode 100644 index 00000000..0c613795 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Write a function that given a target amount of money and a list of possible coin denominations, returns the number of ways to make change for the target amount using the coin denominations**\n", + "\n", + "## Requirements\n", + "\n", + "** Write out your work on paper/pencil, then see if you can code up your solution **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "This is a classic interview problem, so classic that you've already seen a very similar problem in the recursion section! Make sure to review that problem first before reading our solution here!\n", + "\n", + "In this solution we will use a [bottom-up](https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design) algorithm.\n", + "\n", + "* As we iterate through each coin, we are adding the ways of making arr[i - coin] to arr[i]\n", + "* If we have 2 ways of making 4, and are now iterating on a coin of value 3, there should be 2 ways of making 7.\n", + "* We are essentially adding the coin we are iterating on to the number of ways of making arr[i]." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(n, coins):\n", + " \n", + " # Set up our array for trakcing results\n", + " arr = [1] + [0] * n\n", + " \n", + " for coin in coins:\n", + " for i in range(coin, n + 1):\n", + " arr[i] += arr[i - coin]\n", + " \n", + " if n == 0:\n", + " return 0\n", + " else:\n", + " return arr[n]\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "884" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution(100, [1, 2, 3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This solution results in O((m)(n)) with m being the number of coins, where we iterate about n operations. This is O(n) space." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb new file mode 100644 index 00000000..238cc667 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a binary tree, check whether it’s a binary search tree or not. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Requirements\n", + "\n", + "** Use paper/pencil, do not code this in an IDE until you've done it manually**\n", + "\n", + "** Do not use built-in Python libraries to do this, but do mention them if you know about them **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "The first solution that comes to mind is, at every node check whether its value is larger than or equal to its left child and smaller than or equal to its right child (assuming equals can appear at either left or right). However, this approach is erroneous because it doesn’t check whether a node violates any condition with its grandparent or any of its ancestors. \n", + "\n", + "So, we should keep track of the minimum and maximum values a node can take. And at each node we will check whether its value is between the min and max values it’s allowed to take. The root can take any value between negative infinity and positive infinity. At any node, its left child should be smaller than or equal than its own value, and similarly the right child should be larger than or equal to. So during recursion, we send the current value as the new max to our left child and send the min as it is without changing. And to the right child, we send the current value as the new min and send the max without changing. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class Node: \n", + " def __init__(self, val=None): \n", + " self.left, self.right, self.val = None, None, val \n", + " \n", + "INFINITY = float(\"infinity\") \n", + "NEG_INFINITY = float(\"-infinity\") \n", + "\n", + "def isBST(tree, minVal=NEG_INFINITY, maxVal=INFINITY): \n", + " if tree is None:\n", + " return True \n", + " if not minVal <= tree.val <= maxVal: \n", + " return False \n", + " \n", + " return isBST(tree.left, minVal, tree.val) and isBST(tree.right, tree.val, maxVal) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There’s an equally good alternative solution. If a tree is a binary search tree, then traversing the tree inorder should lead to sorted order of the values in the tree. So, we can perform an inorder traversal and check whether the node values are sorted or not." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def isBST2(tree, lastNode=[NEG_INFINITY]): \n", + " \n", + " if tree is None: \n", + " return True \n", + " \n", + " if not isBST2(tree.left, lastNode):\n", + " return False \n", + " \n", + " if tree.val < lastNode[0]: \n", + " return False \n", + " \n", + " lastNode[0]=tree.val \n", + " \n", + " return isBST2(tree.right, lastNode) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a common interview problem, its relatively simple, but not trivial and shows that someone has a knowledge of binary search trees and tree traversals.\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/Phone Screen - SOLUTION.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/Phone Screen - SOLUTION.ipynb new file mode 100644 index 00000000..662e8373 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions - SOLUTIONS/Phone Screen - SOLUTION.ipynb @@ -0,0 +1,53 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** If you were given a list of n integers and knew that they were sorted, how quickly could you check if a given integer was in the list? Elaborate on your reasoning and search methods in general**\n", + "\n", + "## Requirements\n", + "\n", + "** Try explaining your solution to someone and see if it makes sense ot them. Don't code anything for this problem **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Hopefully this problem sounds familiar! We can use a binary search to search for an intger since the list is already sorted! This means we can find the item in [O(logn) time and O(1) space](http://bigocheatsheet.com/)!\n", + "\n", + "Revisit the lectures on Binary Search and its implementation to fully get the reasoning behind this solution and problem!\n", + "\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 1 -checkpoint.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 1 -checkpoint.ipynb new file mode 100644 index 00000000..ccfa72f7 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 1 -checkpoint.ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 \n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers, find the largest product you could make from 3 integers in the list **\n", + "\n", + "## Requirements\n", + "\n", + "** You can assume that the list will always have at least 3 integers **\n", + "\n", + "** Paper/pencil only, don't code this out until you've solved it as far as you can by hand. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb new file mode 100644 index 00000000..cd47095c --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 2 -checkpoint.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 \n", + "\n", + "## Problem\n", + "\n", + "** Write a function that given a target amount of money and a list of possible coin denominations, returns the number of ways to make change for the target amount using the coin denominations**\n", + "\n", + "## Requirements\n", + "\n", + "** Write out your work on paper/pencil, then see if you can code up your solution **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 3 -checkpoint.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 3 -checkpoint.ipynb new file mode 100644 index 00000000..380ec415 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 3 -checkpoint.ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 \n", + "\n", + "## Problem\n", + "\n", + "** Given a binary tree, check whether it’s a binary search tree or not. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Requirements\n", + "\n", + "** Use paper/pencil, do not code this in an IDE until you've done it manually**\n", + "\n", + "** Do not use built-in Python libraries to do this, but do mention them if you know about them **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb new file mode 100644 index 00000000..062944af --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen \n", + "\n", + "## Problem\n", + "\n", + "** If you were given a list of n integers and knew that they were sorted, how quickly could you check if a given integer was in the list? Elaborate on your reasoning and search methods in general**\n", + "\n", + "## Requirements\n", + "\n", + "** Try explaining your solution to someone and see if it makes sense ot them. Don't code anything for this problem **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 1 .ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 1 .ipynb new file mode 100644 index 00000000..ccfa72f7 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 1 .ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 \n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers, find the largest product you could make from 3 integers in the list **\n", + "\n", + "## Requirements\n", + "\n", + "** You can assume that the list will always have at least 3 integers **\n", + "\n", + "** Paper/pencil only, don't code this out until you've solved it as far as you can by hand. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 2 .ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 2 .ipynb new file mode 100644 index 00000000..cd47095c --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 2 .ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 \n", + "\n", + "## Problem\n", + "\n", + "** Write a function that given a target amount of money and a list of possible coin denominations, returns the number of ways to make change for the target amount using the coin denominations**\n", + "\n", + "## Requirements\n", + "\n", + "** Write out your work on paper/pencil, then see if you can code up your solution **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 3 .ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 3 .ipynb new file mode 100644 index 00000000..380ec415 --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/On-Site Question 3 .ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 \n", + "\n", + "## Problem\n", + "\n", + "** Given a binary tree, check whether it’s a binary search tree or not. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Requirements\n", + "\n", + "** Use paper/pencil, do not code this in an IDE until you've done it manually**\n", + "\n", + "** Do not use built-in Python libraries to do this, but do mention them if you know about them **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/Phone Screen .ipynb b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/Phone Screen .ipynb new file mode 100644 index 00000000..062944af --- /dev/null +++ b/Mock Interviews/Ride Share Start-Up Company/Ride Share Company - Interview Questions_/Phone Screen .ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen \n", + "\n", + "## Problem\n", + "\n", + "** If you were given a list of n integers and knew that they were sorted, how quickly could you check if a given integer was in the list? Elaborate on your reasoning and search methods in general**\n", + "\n", + "## Requirements\n", + "\n", + "** Try explaining your solution to someone and see if it makes sense ot them. Don't code anything for this problem **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..f00525dd --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 1 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,138 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers and a target number, write a function that returns a boolean indicating if its possible to sum two integers from the list to reach the target number **\n", + "\n", + "## Requirements\n", + "\n", + "** Try pen/paper before coding out your solution **\n", + "\n", + "** You can not use an integer element twice. Optimize for time over space **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "For this problem we will take advantage of a **set** data structure. We will make a single pass through the list of integers, treating each element as the first integer of our possible sum.\n", + "\n", + "At each iteration we will check to see if there is a second integer which will allow us hit the target number, adn we will use a set to check if we've already seen it in our list.\n", + "\n", + "We will then update our seen set by adding the current number in the iteration to it.\n", + "\n", + "Let's see this coded out:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(lst,target):\n", + " \n", + " # Create set to keep track of duplicates\n", + " seen = set()\n", + " \n", + " # We want to find if there is a num2 that sums with num to reach the target\n", + " \n", + " for num in lst:\n", + " \n", + " num2 = target - num\n", + " \n", + " if num2 in seen:\n", + " return True\n", + " \n", + " seen.add(num)\n", + " \n", + " # If we never find a pair match which creates the sum\n", + " return False" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution([1,3,5,1,7],4)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution([1,3,5,1,7],14)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..7d049b8a --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 2 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a list of account ID numbers (integers) which contains duplicates , find the one unique integer. (the list is guaranteed to only have one unique (non-duplicated) integer **\n", + "\n", + "## Requirements\n", + "\n", + "** Do not use built-in Python functions or methods **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "This should feel very familiar to one of the problems we did in the array section of the course! We can use an [XOR](https://en.wikipedia.org/wiki/Exclusive_or) operation. The **exclusive or** operations will take two sets of bits and for each pair it will return a 1 value if **one but not both** of the bits is 1.\n", + "\n", + "In Python we can use the ^ symbol to perform an XOR.\n", + "\n", + "Now for our solution we can simply XOR all the integers in the list. We start with a unique id set to 0, then every time we XOR a new id from the list, it will change the bits. When we XOR with the same ID again, it will cancel out the earlier change.\n", + "\n", + "By the end, we wil be left with the ID that was unique and only appeared once!" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(id_list):\n", + " \n", + " # Initiate unique Id\n", + " unique_id = 0\n", + " \n", + " # XOR fo revery id in id list\n", + " for i in id_list:\n", + " \n", + " # XOR operation\n", + " unique_id ^= i\n", + " \n", + " return unique_id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..62cbf2b9 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/On-Site Question 3 - SOLUTION-checkpoint.ipynb @@ -0,0 +1,116 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Create a function that takes in a list of unsorted prices (integers) and a maximum possible price value, and return a sorted list of prices**\n", + "\n", + "## Requirements\n", + "\n", + "** Your function should be able to perform this in less than O(nlogn) time. **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "We can actually solve this problem by using a [*counting sort*](https://en.wikipedia.org/wiki/Counting_sort). Basically a counting sort works well when you know the range of integer values you will have ahead of time.\n", + "\n", + "Read the wikipedia article linked above for a full break down, and an implementation is here below (using the prices situation described in the problem above)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(unsorted_prices,max_price):\n", + " \n", + " # list of 0s at indices 0 to max_price\n", + " prices_to_counts = [0]* (max_price+1)\n", + " \n", + " # populate prices\n", + " for price in unsorted_prices:\n", + " prices_to_counts[price] +=1\n", + " \n", + " # populate final sorted prices\n", + " sorted_prices = []\n", + " \n", + " # For each price in prices_to_counts\n", + " for price,count in enumerate(prices_to_counts):\n", + " \n", + " # for the number of times the element occurs\n", + " for time in range(count):\n", + " \n", + " # add it to the sorted price list\n", + " sorted_prices.append(price)\n", + " \n", + " return sorted_prices" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 3, 4, 6, 7, 8, 9]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution([4,6,2,7,3,8,9],9)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This was a great exercise in learning about a new sorting algorithm, make sure to read up on it and practice this problem again!\n", + "\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..fe61bd16 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/.ipynb_checkpoints/Phone Screen - SOLUTION-checkpoint.ipynb @@ -0,0 +1,87 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen - SOLUTION\n", + "\n", + "## Problem \n", + "\n", + "** Remove duplicate characters in a given string keeping only the first occurrences. For example, if the input is ‘tree traversal’ the output will be ‘tre avsl’. **\n", + "\n", + "## Requirements\n", + "\n", + "**Complete this problem on a text editor that does not have syntax highlighting, such as a goolge doc!**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "We need a data structure to keep track of the characters we have seen so far, which can perform efficient find operation. If the input is guaranteed to be in standard ASCII form, we can just create a boolean array of size 128 and perform lookups by accessing the index of the character’s ASCII value in constant time. But if the string is Unicode then we would need a much larger array of size more than 100K, which will be a waste since most of it would generally be unused.\n", + "\n", + "Set data structure perfectly suits our purpose. It stores keys and provides constant time search for key existence. So, we’ll loop over the characters of the string, and at each iteration we’ll check whether we have seen the current character before by searching the set. If it’s in the set then it means we’ve seen it before, so we ignore it. Otherwise, we include it in the result and add it to the set to keep track for future reference. The code is easier to understand:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def removeDuplicates(string): \n", + " result=[] \n", + " seen=set() \n", + " \n", + " for char in string: \n", + " if char not in seen: \n", + " seen.add(char) \n", + " result.append(char)\n", + " \n", + " return ''.join(result) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The time complexity of the algorithm is O(N) where N is the number of characters in the input string, because set supports O(1) insert and find. This is an optimal solution to one of the most common string interview questions. \n", + "\n", + "This problem should have felt very similar to some other array questions you've been asked! Remember that many basic interview question ideas overlap, just their presentation is different!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb new file mode 100644 index 00000000..f00525dd --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 1 - SOLUTION.ipynb @@ -0,0 +1,138 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers and a target number, write a function that returns a boolean indicating if its possible to sum two integers from the list to reach the target number **\n", + "\n", + "## Requirements\n", + "\n", + "** Try pen/paper before coding out your solution **\n", + "\n", + "** You can not use an integer element twice. Optimize for time over space **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "For this problem we will take advantage of a **set** data structure. We will make a single pass through the list of integers, treating each element as the first integer of our possible sum.\n", + "\n", + "At each iteration we will check to see if there is a second integer which will allow us hit the target number, adn we will use a set to check if we've already seen it in our list.\n", + "\n", + "We will then update our seen set by adding the current number in the iteration to it.\n", + "\n", + "Let's see this coded out:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(lst,target):\n", + " \n", + " # Create set to keep track of duplicates\n", + " seen = set()\n", + " \n", + " # We want to find if there is a num2 that sums with num to reach the target\n", + " \n", + " for num in lst:\n", + " \n", + " num2 = target - num\n", + " \n", + " if num2 in seen:\n", + " return True\n", + " \n", + " seen.add(num)\n", + " \n", + " # If we never find a pair match which creates the sum\n", + " return False" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution([1,3,5,1,7],4)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution([1,3,5,1,7],14)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb new file mode 100644 index 00000000..7d049b8a --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 2 - SOLUTION.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Given a list of account ID numbers (integers) which contains duplicates , find the one unique integer. (the list is guaranteed to only have one unique (non-duplicated) integer **\n", + "\n", + "## Requirements\n", + "\n", + "** Do not use built-in Python functions or methods **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "This should feel very familiar to one of the problems we did in the array section of the course! We can use an [XOR](https://en.wikipedia.org/wiki/Exclusive_or) operation. The **exclusive or** operations will take two sets of bits and for each pair it will return a 1 value if **one but not both** of the bits is 1.\n", + "\n", + "In Python we can use the ^ symbol to perform an XOR.\n", + "\n", + "Now for our solution we can simply XOR all the integers in the list. We start with a unique id set to 0, then every time we XOR a new id from the list, it will change the bits. When we XOR with the same ID again, it will cancel out the earlier change.\n", + "\n", + "By the end, we wil be left with the ID that was unique and only appeared once!" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(id_list):\n", + " \n", + " # Initiate unique Id\n", + " unique_id = 0\n", + " \n", + " # XOR fo revery id in id list\n", + " for i in id_list:\n", + " \n", + " # XOR operation\n", + " unique_id ^= i\n", + " \n", + " return unique_id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb new file mode 100644 index 00000000..62cbf2b9 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/On-Site Question 3 - SOLUTION.ipynb @@ -0,0 +1,116 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 - SOLUTION\n", + "\n", + "## Problem\n", + "\n", + "** Create a function that takes in a list of unsorted prices (integers) and a maximum possible price value, and return a sorted list of prices**\n", + "\n", + "## Requirements\n", + "\n", + "** Your function should be able to perform this in less than O(nlogn) time. **" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Solution\n", + "\n", + "We can actually solve this problem by using a [*counting sort*](https://en.wikipedia.org/wiki/Counting_sort). Basically a counting sort works well when you know the range of integer values you will have ahead of time.\n", + "\n", + "Read the wikipedia article linked above for a full break down, and an implementation is here below (using the prices situation described in the problem above)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def solution(unsorted_prices,max_price):\n", + " \n", + " # list of 0s at indices 0 to max_price\n", + " prices_to_counts = [0]* (max_price+1)\n", + " \n", + " # populate prices\n", + " for price in unsorted_prices:\n", + " prices_to_counts[price] +=1\n", + " \n", + " # populate final sorted prices\n", + " sorted_prices = []\n", + " \n", + " # For each price in prices_to_counts\n", + " for price,count in enumerate(prices_to_counts):\n", + " \n", + " # for the number of times the element occurs\n", + " for time in range(count):\n", + " \n", + " # add it to the sorted price list\n", + " sorted_prices.append(price)\n", + " \n", + " return sorted_prices" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 3, 4, 6, 7, 8, 9]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution([4,6,2,7,3,8,9],9)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This was a great exercise in learning about a new sorting algorithm, make sure to read up on it and practice this problem again!\n", + "\n", + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/Phone Screen - SOLUTION.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/Phone Screen - SOLUTION.ipynb new file mode 100644 index 00000000..fe61bd16 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions - SOLUTIONS/Phone Screen - SOLUTION.ipynb @@ -0,0 +1,87 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen - SOLUTION\n", + "\n", + "## Problem \n", + "\n", + "** Remove duplicate characters in a given string keeping only the first occurrences. For example, if the input is ‘tree traversal’ the output will be ‘tre avsl’. **\n", + "\n", + "## Requirements\n", + "\n", + "**Complete this problem on a text editor that does not have syntax highlighting, such as a goolge doc!**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "We need a data structure to keep track of the characters we have seen so far, which can perform efficient find operation. If the input is guaranteed to be in standard ASCII form, we can just create a boolean array of size 128 and perform lookups by accessing the index of the character’s ASCII value in constant time. But if the string is Unicode then we would need a much larger array of size more than 100K, which will be a waste since most of it would generally be unused.\n", + "\n", + "Set data structure perfectly suits our purpose. It stores keys and provides constant time search for key existence. So, we’ll loop over the characters of the string, and at each iteration we’ll check whether we have seen the current character before by searching the set. If it’s in the set then it means we’ve seen it before, so we ignore it. Otherwise, we include it in the result and add it to the set to keep track for future reference. The code is easier to understand:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def removeDuplicates(string): \n", + " result=[] \n", + " seen=set() \n", + " \n", + " for char in string: \n", + " if char not in seen: \n", + " seen.add(char) \n", + " result.append(char)\n", + " \n", + " return ''.join(result) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The time complexity of the algorithm is O(N) where N is the number of characters in the input string, because set supports O(1) insert and find. This is an optimal solution to one of the most common string interview questions. \n", + "\n", + "This problem should have felt very similar to some other array questions you've been asked! Remember that many basic interview question ideas overlap, just their presentation is different!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 1-checkpoint.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 1-checkpoint.ipynb new file mode 100644 index 00000000..a72a4672 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 1-checkpoint.ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 \n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers and a target number, write a function that returns a boolean indicating if its possible to sum two integers from the list to reach the target number **\n", + "\n", + "## Requirements\n", + "\n", + "** Try pen/paper before coding out your solution **\n", + "\n", + "** You can not use an integer element twice. Optimize for time over space **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 2-checkpoint.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 2-checkpoint.ipynb new file mode 100644 index 00000000..e65f70c4 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 2-checkpoint.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 \n", + "\n", + "## Problem\n", + "\n", + "** Given a list of account ID numbers (integers) which contains duplicates , find the one unique integer. (the list is guaranteed to only have one unique (non-duplicated) integer **\n", + "\n", + "## Requirements\n", + "\n", + "** Do not use built-in Python functions or methods **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 3-checkpoint.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 3-checkpoint.ipynb new file mode 100644 index 00000000..139bd6c5 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/On-Site Question 3-checkpoint.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 \n", + "\n", + "## Problem\n", + "\n", + "** Create a function that takes in a list of unsorted prices (integers) and a maximum possible price value, and return a sorted list of prices**\n", + "\n", + "## Requirements\n", + "\n", + "** Your function should be able to perform this in less than O(nlogn) time. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb new file mode 100644 index 00000000..d082e4e5 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/.ipynb_checkpoints/Phone Screen -checkpoint.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen \n", + "\n", + "## Problem \n", + "\n", + "** Remove duplicate characters in a given string keeping only the first occurrences. For example, if the input is ‘tree traversal’ the output will be ‘tre avsl’. **\n", + "\n", + "## Requirements\n", + "\n", + "**Complete this problem on a text editor that does not have syntax highlighting, such as a goolge doc!**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 1.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 1.ipynb new file mode 100644 index 00000000..a72a4672 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 1.ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 1 \n", + "\n", + "## Problem\n", + "\n", + "** Given a list of integers and a target number, write a function that returns a boolean indicating if its possible to sum two integers from the list to reach the target number **\n", + "\n", + "## Requirements\n", + "\n", + "** Try pen/paper before coding out your solution **\n", + "\n", + "** You can not use an integer element twice. Optimize for time over space **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 2.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 2.ipynb new file mode 100644 index 00000000..e65f70c4 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 2.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 2 \n", + "\n", + "## Problem\n", + "\n", + "** Given a list of account ID numbers (integers) which contains duplicates , find the one unique integer. (the list is guaranteed to only have one unique (non-duplicated) integer **\n", + "\n", + "## Requirements\n", + "\n", + "** Do not use built-in Python functions or methods **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 3.ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 3.ipynb new file mode 100644 index 00000000..139bd6c5 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/On-Site Question 3.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# On-Site Question 3 \n", + "\n", + "## Problem\n", + "\n", + "** Create a function that takes in a list of unsorted prices (integers) and a maximum possible price value, and return a sorted list of prices**\n", + "\n", + "## Requirements\n", + "\n", + "** Your function should be able to perform this in less than O(nlogn) time. **" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/Phone Screen .ipynb b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/Phone Screen .ipynb new file mode 100644 index 00000000..d082e4e5 --- /dev/null +++ b/Mock Interviews/Social Network Company/Social Network Company - Interview Questions_/Phone Screen .ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Phone Screen \n", + "\n", + "## Problem \n", + "\n", + "** Remove duplicate characters in a given string keeping only the first occurrences. For example, if the input is ‘tree traversal’ the output will be ‘tre avsl’. **\n", + "\n", + "## Requirements\n", + "\n", + "**Complete this problem on a text editor that does not have syntax highlighting, such as a goolge doc!**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Practice.ipynb b/Practice.ipynb new file mode 100644 index 00000000..b2ecf2ed --- /dev/null +++ b/Practice.ipynb @@ -0,0 +1,1407 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'HELLO'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s = 'hello'\n", + "s.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hi\n" + ] + } + ], + "source": [ + "set1 = set()\n", + "print('hi')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('hello',)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import timeit\n", + "timeit\n", + "singleton = 'hello',\n", + "singleton" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "{'banana', 'apple', 'orange', 'pear'}\n" + ] + } + ], + "source": [ + "basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}\n", + "print(type(basket))\n", + "print(basket)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{' ', 't', 's', 'i', 'h', 'o', 'e', 'n', 'm', 'g'}\n" + ] + } + ], + "source": [ + "chars = {c for c in 'this is something'}\n", + "print(chars)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s = 'A man, a plan, a canal: Panama'\n" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "'return' outside function (, line 7)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m7\u001b[0m\n\u001b[0;31m return False\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m 'return' outside function\n" + ] + } + ], + "source": [ + "s='ab'\n", + "s=s.casefold()\n", + "chars = list(filter(lambda c:c.isalpha(), s))\n", + "low, high=0, len(chars)-1\n", + "while(low>> a_string = 'amanaplanacanalpanama' * 10\n", + ">>> min(timeit.repeat(lambda: reverse_string_readable_answer(a_string)))\n", + "10.38789987564087\n", + ">>> min(timeit.repeat(lambda: reversed_string(a_string)))\n", + "0.6622700691223145\n", + ">>> min(timeit.repeat(lambda: reverse_a_string_slowly(a_string)))\n", + "25.756799936294556\n", + ">>> min(timeit.repeat(lambda: reverse_a_string_more_slowly(a_string)))\n", + "38.73570013046265" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "s = 'amanaplanacanalpanama'" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def reverse_simple(s):\n", + " return s[::-1]\n", + "def reverse_readable(s):\n", + " return ''.join(reversed(s))" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.00010040099732577801" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import timeit\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.9958420610055327" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1.6800561340060085" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "timeit.timeit('\"amanaplanacanalpanama\"[::-1]', number=10000000)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9.636620013043284" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "timeit.timeit('\"\".join(reversed(\"amanaplanacanalpanama\"))', number=10000000)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/Users/bin/Documents/Workspace/GitHub/Python-for-Algorithm-and-Interviews\r\n" + ] + } + ], + "source": [ + "!pwd" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "!say 'hi'" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "stmt is neither a string nor callable", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtimeit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtimeit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1000\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mnumber\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1000\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/timeit.py\u001b[0m in \u001b[0;36mtimeit\u001b[0;34m(stmt, setup, timer, number, globals)\u001b[0m\n\u001b[1;32m 231\u001b[0m number=default_number, globals=None):\n\u001b[1;32m 232\u001b[0m \u001b[0;34m\"\"\"Convenience function to create Timer object and call timeit method.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 233\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mTimer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstmt\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msetup\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimer\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mglobals\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtimeit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnumber\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 234\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 235\u001b[0m def repeat(stmt=\"pass\", setup=\"pass\", timer=default_timer,\n", + "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/timeit.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, stmt, setup, timer, globals)\u001b[0m\n\u001b[1;32m 128\u001b[0m \u001b[0mstmt\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'_stmt()'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 129\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 130\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"stmt is neither a string nor callable\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 131\u001b[0m \u001b[0msrc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtemplate\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstmt\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstmt\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msetup\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msetup\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minit\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0minit\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 132\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msrc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msrc\u001b[0m \u001b[0;31m# Save for traceback display\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: stmt is neither a string nor callable" + ] + } + ], + "source": [ + "timeit.timeit(,number=1000)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0,\n", + " 2,\n", + " 4,\n", + " 6,\n", + " 8,\n", + " 10,\n", + " 12,\n", + " 14,\n", + " 16,\n", + " 18,\n", + " 20,\n", + " 22,\n", + " 24,\n", + " 26,\n", + " 28,\n", + " 30,\n", + " 32,\n", + " 34,\n", + " 36,\n", + " 38,\n", + " 40,\n", + " 42,\n", + " 44,\n", + " 46,\n", + " 48,\n", + " 50,\n", + " 52,\n", + " 54,\n", + " 56,\n", + " 58,\n", + " 60,\n", + " 62,\n", + " 64,\n", + " 66,\n", + " 68,\n", + " 70,\n", + " 72,\n", + " 74,\n", + " 76,\n", + " 78,\n", + " 80,\n", + " 82,\n", + " 84,\n", + " 86,\n", + " 88,\n", + " 90,\n", + " 92,\n", + " 94,\n", + " 96,\n", + " 98,\n", + " 100,\n", + " 102,\n", + " 104,\n", + " 106,\n", + " 108,\n", + " 110,\n", + " 112,\n", + " 114,\n", + " 116,\n", + " 118,\n", + " 120,\n", + " 122,\n", + " 124,\n", + " 126,\n", + " 128,\n", + " 130,\n", + " 132,\n", + " 134,\n", + " 136,\n", + " 138,\n", + " 140,\n", + " 142,\n", + " 144,\n", + " 146,\n", + " 148,\n", + " 150,\n", + " 152,\n", + " 154,\n", + " 156,\n", + " 158,\n", + " 160,\n", + " 162,\n", + " 164,\n", + " 166,\n", + " 168,\n", + " 170,\n", + " 172,\n", + " 174,\n", + " 176,\n", + " 178,\n", + " 180,\n", + " 182,\n", + " 184,\n", + " 186,\n", + " 188,\n", + " 190,\n", + " 192,\n", + " 194,\n", + " 196,\n", + " 198,\n", + " 200,\n", + " 202,\n", + " 204,\n", + " 206,\n", + " 208,\n", + " 210,\n", + " 212,\n", + " 214,\n", + " 216,\n", + " 218,\n", + " 220,\n", + " 222,\n", + " 224,\n", + " 226,\n", + " 228,\n", + " 230,\n", + " 232,\n", + " 234,\n", + " 236,\n", + " 238,\n", + " 240,\n", + " 242,\n", + " 244,\n", + " 246,\n", + " 248,\n", + " 250,\n", + " 252,\n", + " 254,\n", + " 256,\n", + " 258,\n", + " 260,\n", + " 262,\n", + " 264,\n", + " 266,\n", + " 268,\n", + " 270,\n", + " 272,\n", + " 274,\n", + " 276,\n", + " 278,\n", + " 280,\n", + " 282,\n", + " 284,\n", + " 286,\n", + " 288,\n", + " 290,\n", + " 292,\n", + " 294,\n", + " 296,\n", + " 298,\n", + " 300,\n", + " 302,\n", + " 304,\n", + " 306,\n", + " 308,\n", + " 310,\n", + " 312,\n", + " 314,\n", + " 316,\n", + " 318,\n", + " 320,\n", + " 322,\n", + " 324,\n", + " 326,\n", + " 328,\n", + " 330,\n", + " 332,\n", + " 334,\n", + " 336,\n", + " 338,\n", + " 340,\n", + " 342,\n", + " 344,\n", + " 346,\n", + " 348,\n", + " 350,\n", + " 352,\n", + " 354,\n", + " 356,\n", + " 358,\n", + " 360,\n", + " 362,\n", + " 364,\n", + " 366,\n", + " 368,\n", + " 370,\n", + " 372,\n", + " 374,\n", + " 376,\n", + " 378,\n", + " 380,\n", + " 382,\n", + " 384,\n", + " 386,\n", + " 388,\n", + " 390,\n", + " 392,\n", + " 394,\n", + " 396,\n", + " 398,\n", + " 400,\n", + " 402,\n", + " 404,\n", + " 406,\n", + " 408,\n", + " 410,\n", + " 412,\n", + " 414,\n", + " 416,\n", + " 418,\n", + " 420,\n", + " 422,\n", + " 424,\n", + " 426,\n", + " 428,\n", + " 430,\n", + " 432,\n", + " 434,\n", + " 436,\n", + " 438,\n", + " 440,\n", + " 442,\n", + " 444,\n", + " 446,\n", + " 448,\n", + " 450,\n", + " 452,\n", + " 454,\n", + " 456,\n", + " 458,\n", + " 460,\n", + " 462,\n", + " 464,\n", + " 466,\n", + " 468,\n", + " 470,\n", + " 472,\n", + " 474,\n", + " 476,\n", + " 478,\n", + " 480,\n", + " 482,\n", + " 484,\n", + " 486,\n", + " 488,\n", + " 490,\n", + " 492,\n", + " 494,\n", + " 496,\n", + " 498,\n", + " 500,\n", + " 502,\n", + " 504,\n", + " 506,\n", + " 508,\n", + " 510,\n", + " 512,\n", + " 514,\n", + " 516,\n", + " 518,\n", + " 520,\n", + " 522,\n", + " 524,\n", + " 526,\n", + " 528,\n", + " 530,\n", + " 532,\n", + " 534,\n", + " 536,\n", + " 538,\n", + " 540,\n", + " 542,\n", + " 544,\n", + " 546,\n", + " 548,\n", + " 550,\n", + " 552,\n", + " 554,\n", + " 556,\n", + " 558,\n", + " 560,\n", + " 562,\n", + " 564,\n", + " 566,\n", + " 568,\n", + " 570,\n", + " 572,\n", + " 574,\n", + " 576,\n", + " 578,\n", + " 580,\n", + " 582,\n", + " 584,\n", + " 586,\n", + " 588,\n", + " 590,\n", + " 592,\n", + " 594,\n", + " 596,\n", + " 598,\n", + " 600,\n", + " 602,\n", + " 604,\n", + " 606,\n", + " 608,\n", + " 610,\n", + " 612,\n", + " 614,\n", + " 616,\n", + " 618,\n", + " 620,\n", + " 622,\n", + " 624,\n", + " 626,\n", + " 628,\n", + " 630,\n", + " 632,\n", + " 634,\n", + " 636,\n", + " 638,\n", + " 640,\n", + " 642,\n", + " 644,\n", + " 646,\n", + " 648,\n", + " 650,\n", + " 652,\n", + " 654,\n", + " 656,\n", + " 658,\n", + " 660,\n", + " 662,\n", + " 664,\n", + " 666,\n", + " 668,\n", + " 670,\n", + " 672,\n", + " 674,\n", + " 676,\n", + " 678,\n", + " 680,\n", + " 682,\n", + " 684,\n", + " 686,\n", + " 688,\n", + " 690,\n", + " 692,\n", + " 694,\n", + " 696,\n", + " 698,\n", + " 700,\n", + " 702,\n", + " 704,\n", + " 706,\n", + " 708,\n", + " 710,\n", + " 712,\n", + " 714,\n", + " 716,\n", + " 718,\n", + " 720,\n", + " 722,\n", + " 724,\n", + " 726,\n", + " 728,\n", + " 730,\n", + " 732,\n", + " 734,\n", + " 736,\n", + " 738,\n", + " 740,\n", + " 742,\n", + " 744,\n", + " 746,\n", + " 748,\n", + " 750,\n", + " 752,\n", + " 754,\n", + " 756,\n", + " 758,\n", + " 760,\n", + " 762,\n", + " 764,\n", + " 766,\n", + " 768,\n", + " 770,\n", + " 772,\n", + " 774,\n", + " 776,\n", + " 778,\n", + " 780,\n", + " 782,\n", + " 784,\n", + " 786,\n", + " 788,\n", + " 790,\n", + " 792,\n", + " 794,\n", + " 796,\n", + " 798,\n", + " 800,\n", + " 802,\n", + " 804,\n", + " 806,\n", + " 808,\n", + " 810,\n", + " 812,\n", + " 814,\n", + " 816,\n", + " 818,\n", + " 820,\n", + " 822,\n", + " 824,\n", + " 826,\n", + " 828,\n", + " 830,\n", + " 832,\n", + " 834,\n", + " 836,\n", + " 838,\n", + " 840,\n", + " 842,\n", + " 844,\n", + " 846,\n", + " 848,\n", + " 850,\n", + " 852,\n", + " 854,\n", + " 856,\n", + " 858,\n", + " 860,\n", + " 862,\n", + " 864,\n", + " 866,\n", + " 868,\n", + " 870,\n", + " 872,\n", + " 874,\n", + " 876,\n", + " 878,\n", + " 880,\n", + " 882,\n", + " 884,\n", + " 886,\n", + " 888,\n", + " 890,\n", + " 892,\n", + " 894,\n", + " 896,\n", + " 898,\n", + " 900,\n", + " 902,\n", + " 904,\n", + " 906,\n", + " 908,\n", + " 910,\n", + " 912,\n", + " 914,\n", + " 916,\n", + " 918,\n", + " 920,\n", + " 922,\n", + " 924,\n", + " 926,\n", + " 928,\n", + " 930,\n", + " 932,\n", + " 934,\n", + " 936,\n", + " 938,\n", + " 940,\n", + " 942,\n", + " 944,\n", + " 946,\n", + " 948,\n", + " 950,\n", + " 952,\n", + " 954,\n", + " 956,\n", + " 958,\n", + " 960,\n", + " 962,\n", + " 964,\n", + " 966,\n", + " 968,\n", + " 970,\n", + " 972,\n", + " 974,\n", + " 976,\n", + " 978,\n", + " 980,\n", + " 982,\n", + " 984,\n", + " 986,\n", + " 988,\n", + " 990,\n", + " 992,\n", + " 994,\n", + " 996,\n", + " 998,\n", + " 1000,\n", + " 1002,\n", + " 1004,\n", + " 1006,\n", + " 1008,\n", + " 1010,\n", + " 1012,\n", + " 1014,\n", + " 1016,\n", + " 1018,\n", + " 1020,\n", + " 1022,\n", + " 1024,\n", + " 1026,\n", + " 1028,\n", + " 1030,\n", + " 1032,\n", + " 1034,\n", + " 1036,\n", + " 1038,\n", + " 1040,\n", + " 1042,\n", + " 1044,\n", + " 1046,\n", + " 1048,\n", + " 1050,\n", + " 1052,\n", + " 1054,\n", + " 1056,\n", + " 1058,\n", + " 1060,\n", + " 1062,\n", + " 1064,\n", + " 1066,\n", + " 1068,\n", + " 1070,\n", + " 1072,\n", + " 1074,\n", + " 1076,\n", + " 1078,\n", + " 1080,\n", + " 1082,\n", + " 1084,\n", + " 1086,\n", + " 1088,\n", + " 1090,\n", + " 1092,\n", + " 1094,\n", + " 1096,\n", + " 1098,\n", + " 1100,\n", + " 1102,\n", + " 1104,\n", + " 1106,\n", + " 1108,\n", + " 1110,\n", + " 1112,\n", + " 1114,\n", + " 1116,\n", + " 1118,\n", + " 1120,\n", + " 1122,\n", + " 1124,\n", + " 1126,\n", + " 1128,\n", + " 1130,\n", + " 1132,\n", + " 1134,\n", + " 1136,\n", + " 1138,\n", + " 1140,\n", + " 1142,\n", + " 1144,\n", + " 1146,\n", + " 1148,\n", + " 1150,\n", + " 1152,\n", + " 1154,\n", + " 1156,\n", + " 1158,\n", + " 1160,\n", + " 1162,\n", + " 1164,\n", + " 1166,\n", + " 1168,\n", + " 1170,\n", + " 1172,\n", + " 1174,\n", + " 1176,\n", + " 1178,\n", + " 1180,\n", + " 1182,\n", + " 1184,\n", + " 1186,\n", + " 1188,\n", + " 1190,\n", + " 1192,\n", + " 1194,\n", + " 1196,\n", + " 1198,\n", + " 1200,\n", + " 1202,\n", + " 1204,\n", + " 1206,\n", + " 1208,\n", + " 1210,\n", + " 1212,\n", + " 1214,\n", + " 1216,\n", + " 1218,\n", + " 1220,\n", + " 1222,\n", + " 1224,\n", + " 1226,\n", + " 1228,\n", + " 1230,\n", + " 1232,\n", + " 1234,\n", + " 1236,\n", + " 1238,\n", + " 1240,\n", + " 1242,\n", + " 1244,\n", + " 1246,\n", + " 1248,\n", + " 1250,\n", + " 1252,\n", + " 1254,\n", + " 1256,\n", + " 1258,\n", + " 1260,\n", + " 1262,\n", + " 1264,\n", + " 1266,\n", + " 1268,\n", + " 1270,\n", + " 1272,\n", + " 1274,\n", + " 1276,\n", + " 1278,\n", + " 1280,\n", + " 1282,\n", + " 1284,\n", + " 1286,\n", + " 1288,\n", + " 1290,\n", + " 1292,\n", + " 1294,\n", + " 1296,\n", + " 1298,\n", + " 1300,\n", + " 1302,\n", + " 1304,\n", + " 1306,\n", + " 1308,\n", + " 1310,\n", + " 1312,\n", + " 1314,\n", + " 1316,\n", + " 1318,\n", + " 1320,\n", + " 1322,\n", + " 1324,\n", + " 1326,\n", + " 1328,\n", + " 1330,\n", + " 1332,\n", + " 1334,\n", + " 1336,\n", + " 1338,\n", + " 1340,\n", + " 1342,\n", + " 1344,\n", + " 1346,\n", + " 1348,\n", + " 1350,\n", + " 1352,\n", + " 1354,\n", + " 1356,\n", + " 1358,\n", + " 1360,\n", + " 1362,\n", + " 1364,\n", + " 1366,\n", + " 1368,\n", + " 1370,\n", + " 1372,\n", + " 1374,\n", + " 1376,\n", + " 1378,\n", + " 1380,\n", + " 1382,\n", + " 1384,\n", + " 1386,\n", + " 1388,\n", + " 1390,\n", + " 1392,\n", + " 1394,\n", + " 1396,\n", + " 1398,\n", + " 1400,\n", + " 1402,\n", + " 1404,\n", + " 1406,\n", + " 1408,\n", + " 1410,\n", + " 1412,\n", + " 1414,\n", + " 1416,\n", + " 1418,\n", + " 1420,\n", + " 1422,\n", + " 1424,\n", + " 1426,\n", + " 1428,\n", + " 1430,\n", + " 1432,\n", + " 1434,\n", + " 1436,\n", + " 1438,\n", + " 1440,\n", + " 1442,\n", + " 1444,\n", + " 1446,\n", + " 1448,\n", + " 1450,\n", + " 1452,\n", + " 1454,\n", + " 1456,\n", + " 1458,\n", + " 1460,\n", + " 1462,\n", + " 1464,\n", + " 1466,\n", + " 1468,\n", + " 1470,\n", + " 1472,\n", + " 1474,\n", + " 1476,\n", + " 1478,\n", + " 1480,\n", + " 1482,\n", + " 1484,\n", + " 1486,\n", + " 1488,\n", + " 1490,\n", + " 1492,\n", + " 1494,\n", + " 1496,\n", + " 1498,\n", + " 1500,\n", + " 1502,\n", + " 1504,\n", + " 1506,\n", + " 1508,\n", + " 1510,\n", + " 1512,\n", + " 1514,\n", + " 1516,\n", + " 1518,\n", + " 1520,\n", + " 1522,\n", + " 1524,\n", + " 1526,\n", + " 1528,\n", + " 1530,\n", + " 1532,\n", + " 1534,\n", + " 1536,\n", + " 1538,\n", + " 1540,\n", + " 1542,\n", + " 1544,\n", + " 1546,\n", + " 1548,\n", + " 1550,\n", + " 1552,\n", + " 1554,\n", + " 1556,\n", + " 1558,\n", + " 1560,\n", + " 1562,\n", + " 1564,\n", + " 1566,\n", + " 1568,\n", + " 1570,\n", + " 1572,\n", + " 1574,\n", + " 1576,\n", + " 1578,\n", + " 1580,\n", + " 1582,\n", + " 1584,\n", + " 1586,\n", + " 1588,\n", + " 1590,\n", + " 1592,\n", + " 1594,\n", + " 1596,\n", + " 1598,\n", + " 1600,\n", + " 1602,\n", + " 1604,\n", + " 1606,\n", + " 1608,\n", + " 1610,\n", + " 1612,\n", + " 1614,\n", + " 1616,\n", + " 1618,\n", + " 1620,\n", + " 1622,\n", + " 1624,\n", + " 1626,\n", + " 1628,\n", + " 1630,\n", + " 1632,\n", + " 1634,\n", + " 1636,\n", + " 1638,\n", + " 1640,\n", + " 1642,\n", + " 1644,\n", + " 1646,\n", + " 1648,\n", + " 1650,\n", + " 1652,\n", + " 1654,\n", + " 1656,\n", + " 1658,\n", + " 1660,\n", + " 1662,\n", + " 1664,\n", + " 1666,\n", + " 1668,\n", + " 1670,\n", + " 1672,\n", + " 1674,\n", + " 1676,\n", + " 1678,\n", + " 1680,\n", + " 1682,\n", + " 1684,\n", + " 1686,\n", + " 1688,\n", + " 1690,\n", + " 1692,\n", + " 1694,\n", + " 1696,\n", + " 1698,\n", + " 1700,\n", + " 1702,\n", + " 1704,\n", + " 1706,\n", + " 1708,\n", + " 1710,\n", + " 1712,\n", + " 1714,\n", + " 1716,\n", + " 1718,\n", + " 1720,\n", + " 1722,\n", + " 1724,\n", + " 1726,\n", + " 1728,\n", + " 1730,\n", + " 1732,\n", + " 1734,\n", + " 1736,\n", + " 1738,\n", + " 1740,\n", + " 1742,\n", + " 1744,\n", + " 1746,\n", + " 1748,\n", + " 1750,\n", + " 1752,\n", + " 1754,\n", + " 1756,\n", + " 1758,\n", + " 1760,\n", + " 1762,\n", + " 1764,\n", + " 1766,\n", + " 1768,\n", + " 1770,\n", + " 1772,\n", + " 1774,\n", + " 1776,\n", + " 1778,\n", + " 1780,\n", + " 1782,\n", + " 1784,\n", + " 1786,\n", + " 1788,\n", + " 1790,\n", + " 1792,\n", + " 1794,\n", + " 1796,\n", + " 1798,\n", + " 1800,\n", + " 1802,\n", + " 1804,\n", + " 1806,\n", + " 1808,\n", + " 1810,\n", + " 1812,\n", + " 1814,\n", + " 1816,\n", + " 1818,\n", + " 1820,\n", + " 1822,\n", + " 1824,\n", + " 1826,\n", + " 1828,\n", + " 1830,\n", + " 1832,\n", + " 1834,\n", + " 1836,\n", + " 1838,\n", + " 1840,\n", + " 1842,\n", + " 1844,\n", + " 1846,\n", + " 1848,\n", + " 1850,\n", + " 1852,\n", + " 1854,\n", + " 1856,\n", + " 1858,\n", + " 1860,\n", + " 1862,\n", + " 1864,\n", + " 1866,\n", + " 1868,\n", + " 1870,\n", + " 1872,\n", + " 1874,\n", + " 1876,\n", + " 1878,\n", + " 1880,\n", + " 1882,\n", + " 1884,\n", + " 1886,\n", + " 1888,\n", + " 1890,\n", + " 1892,\n", + " 1894,\n", + " 1896,\n", + " 1898,\n", + " 1900,\n", + " 1902,\n", + " 1904,\n", + " 1906,\n", + " 1908,\n", + " 1910,\n", + " 1912,\n", + " 1914,\n", + " 1916,\n", + " 1918,\n", + " 1920,\n", + " 1922,\n", + " 1924,\n", + " 1926,\n", + " 1928,\n", + " 1930,\n", + " 1932,\n", + " 1934,\n", + " 1936,\n", + " 1938,\n", + " 1940,\n", + " 1942,\n", + " 1944,\n", + " 1946,\n", + " 1948,\n", + " 1950,\n", + " 1952,\n", + " 1954,\n", + " 1956,\n", + " 1958,\n", + " 1960,\n", + " 1962,\n", + " 1964,\n", + " 1966,\n", + " 1968,\n", + " 1970,\n", + " 1972,\n", + " 1974,\n", + " 1976,\n", + " 1978,\n", + " 1980,\n", + " 1982,\n", + " 1984,\n", + " 1986,\n", + " 1988,\n", + " 1990,\n", + " 1992,\n", + " 1994,\n", + " 1996,\n", + " 1998]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import timeit\n", + "[2 * n for n in range(1000)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/README.md b/README.md new file mode 100644 index 00000000..71dea9b5 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Python for Algorithms, Data-Structures, and Interviews! +#### Welcome to the repository for the Udemy Course: Python for Algorithms, Data Structures, and Interviews! + +This is the ultimate course in preparing you for your technical interviews and landing the job of your dreams! + +Get the entire course, including full video content, solution walkthroughs, discussion forums, instructor support, +and much more for only $20 by using the [discount link](https://www.udemy.com/python-for-data-structures-algorithms-and-interviews/?couponCode=github_discount)! + + diff --git a/Recursion/.ipynb_checkpoints/Introduction to Recursion-checkpoint.ipynb b/Recursion/.ipynb_checkpoints/Introduction to Recursion-checkpoint.ipynb new file mode 100644 index 00000000..0a165bd9 --- /dev/null +++ b/Recursion/.ipynb_checkpoints/Introduction to Recursion-checkpoint.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction to Recursion\n", + "\n", + "In this lecture we will go over the basics of Recursion.\n", + "\n", + "## What is Recursion?\n", + "\n", + "There are two main instances of recursion. The first is when recursion is used as a technique in which a function makes one or more calls to itself. The second is when a data structure uses smaller instances of the exact same type of data structure when it represents itself. Both of these instances are use cases of recursion.\n", + "\n", + "Recursion actually occurs in the real world, such as fractal patterns seen in plants!\n", + "\n", + "## Why use Recursion?\n", + "\n", + "Recursion provides a powerful alternative for performing repetitions of tasks in which a loop is not ideal. Most modern programming languages support recursion and recursion serves as a great tool for building out particular data structures.\n", + "\n", + "We'll start this introduction with an example of recursion- a factorial function.\n", + "\n", + "_______\n", + "# Factorial Example\n", + "\n", + "In this part of the lecture we will explain recursion through an example excercise of creating the factorial function.\n", + "The factorial function is denoted with an exclamation point and is defined as the product of the integers from 1 to *n*. Formally, we can state this as:\n", + "\n", + "$$ n! = n·(n-1)·(n-2)... 3·2·1 $$\n", + "\n", + "Note, **if n = 0, then n! = 1**. This is important to take into account, because it will serve as our *base case*. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Take this example:\n", + "$$4! = 4 · 3 · 2 · 1 = 24. $$\n", + "So how can we state this in a recursive manner? This is where the concept of **base case** comes in.\n", + "\n", + "**Base case** is a key part of understanding recursion, especially when it comes to having to solve interview problems dealing with recursion. Let's rewrite the above equation of 4! so it looks like this:\n", + "\n", + "$$ 4! = 4 · (3 · 2 · 1) = 24 $$\n", + "\n", + "Notice that this is the same as:\n", + "\n", + "$$ 4! = 4 · 3! = 24 $$\n", + "\n", + "Meaning we can rewrite the formal recursion definition in terms of recursion like so:\n", + "\n", + "$$ n! = n·(n−1)!$$\n", + "\n", + "Note, **if n = 0, then n! = 1**. This means the **base case** occurs once n=0, the *recursive cases* are defined in the equation above. Whenever you are trying to develop a recursive solution it is very important to think about the base case, as your solution will need to return the base case once all the recursive cases have been worked through. Let's look at how we can create the factorial function in Python:\n", + "___" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def fact(n):\n", + " '''\n", + " Returns factorial of n (n!).\n", + " Note use of recursion\n", + " '''\n", + " # BASE CASE!\n", + " if n == 0:\n", + " return 1\n", + " \n", + " # Recursion!\n", + " else:\n", + " return n * fact(n-1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see it in action!" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "120" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fact(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "Note how we had an if statement to check if a base case occured. Without it this function would not have successfully completed running. We can visualize the recursion with the following figure:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "from IPython.core.display import HTML \n", + "Image(url= 'http://faculty.cs.niu.edu/~freedman/241/241notes/recur.gif')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We can follow this flow chart from the top, reaching the base case, and then working our way back up.\n", + "\n", + "# Conclusion\n", + "\n", + "Recursion is a powerful tool, but it can be a tricky concept to implement. In the next lectures we will go over a few more example problems for recursion. Then afterwards you'll be faced with some real interview questions involving recursion!" + ] + } + ], + "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 +} diff --git a/Recursion/.ipynb_checkpoints/Memoization-checkpoint.ipynb b/Recursion/.ipynb_checkpoints/Memoization-checkpoint.ipynb new file mode 100644 index 00000000..7de1aee7 --- /dev/null +++ b/Recursion/.ipynb_checkpoints/Memoization-checkpoint.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Memoization\n", + "\n", + "In this lecture we will discuss memoization and dynamic programming. For your homework assignment, read the [Wikipedia article on Memoization](https://en.wikipedia.org/wiki/Memoization), before continuing on with this lecture!\n", + "\n", + "____\n", + "\n", + "Memoization effectively refers to remembering (\"memoization\" -> \"memorandum\" -> to be remembered) results of method calls based on the method inputs and then returning the remembered result rather than computing the result again. You can think of it as a cache for method results. We'll use this in some of the interview problems as improved versions of a purely recursive solution.\n", + "\n", + "A simple example for computing factorials using memoization in Python would be something like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create cache for known results\n", + "factorial_memo = {}\n", + "\n", + "def factorial(k):\n", + " \n", + " if k < 2: \n", + " return 1\n", + " \n", + " if not k in factorial_memo:\n", + " factorial_memo[k] = k * factorial(k-1)\n", + " \n", + " return factorial_memo[k]" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "24" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we are now using a dictionary to store previous results of the factorial function! We are now able to increase the efficiency of this function by remembering old results!\n", + "\n", + "Keep this in mind when working on the Coin Change Problem and the Fibonacci Sequence Problem.\n", + "\n", + "___\n", + "\n", + "We can also encapsulate the memoization process into a class:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Memoize:\n", + " def __init__(self, f):\n", + " self.f = f\n", + " self.memo = {}\n", + " def __call__(self, *args):\n", + " if not args in self.memo:\n", + " self.memo[args] = self.f(*args)\n", + " return self.memo[args]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then all we would have to do is:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def factorial(k):\n", + " \n", + " if k < 2: \n", + " return 1\n", + " \n", + " return k * factorial(k - 1)\n", + "\n", + "factorial = Memoize(factorial)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Try comparing the run times of the memoization versions of functions versus the normal recursive 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 +} diff --git a/Recursion/.ipynb_checkpoints/Recursion Homework Example Problems - PRACTICE-checkpoint.ipynb b/Recursion/.ipynb_checkpoints/Recursion Homework Example Problems - PRACTICE-checkpoint.ipynb new file mode 100644 index 00000000..b6c7d5bb --- /dev/null +++ b/Recursion/.ipynb_checkpoints/Recursion Homework Example Problems - PRACTICE-checkpoint.ipynb @@ -0,0 +1,293 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Recursion Homework Problems \n", + "\n", + "This assignment is a variety of small problems to begin you getting used to the idea of recursion. They are not full-blown interview questions, but do serve as a great start for getting your mind \"in the zone\" for recursion problems.\n", + "\n", + "\n", + "______\n", + "### Problem 1\n", + "\n", + "**Write a recursive function which takes an integer and computes the cumulative sum of 0 to that integer**\n", + "\n", + "**For example, if n=4 , return 4+3+2+1+0, which is 10.**\n", + "\n", + "This problem is very similar to the factorial problem presented during the introduction to recursion. Remember, always think of what the base case will look like. In this case, we have a base case of n =0 (Note, you could have also designed the cut off to be 1).\n", + "\n", + "In this case, we have:\n", + " n + (n-1) + (n-2) + .... + 0\n", + "\n", + "Fill out a sample solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "def rec_sum(n):\n", + " if n == 0:\n", + " return 0\n", + " else:\n", + " return n + rec_sum(n-1)\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_sum(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "______\n", + "### Problem 2\n", + "\n", + "**Given an integer, create a function which returns the sum of all the individual digits in that integer. For example:\n", + "if n = 4321, return 4+3+2+1**" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def sum_func(n):\n", + " if(n<10):\n", + " return n\n", + " else:\n", + " return n%10 + sum_func(int(n/10))\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum_func(4321)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Hints:*" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# You'll neeed to use modulo\n", + "4321%10" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "432" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4321 / 10" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We'll need to think of this function recursively by knowing that:\n", + "4502 % 10 + sum_func(4502/10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "________\n", + "### Problem 3\n", + "*Note, this is a more advanced problem than the previous two! It aso has a lot of variation possibilities and we're ignoring strict requirements here.*\n", + "\n", + "Create a function called word_split() which takes in a string **phrase** and a set **list_of_words**. The function will then determine if it is possible to split the string in a way in which words can be made from the list of words. You can assume the phrase will only contain words found in the dictionary if it is completely splittable.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['the', 'man', 'ran']" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['the','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['i', 'love', 'dogs', 'John']" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('ilovedogsJohn',['i','am','a','dogs','lover','love','John'])" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['clown','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def word_split(phrase,list_of_words, output = None):\n", + " if output is None:\n", + " output = []\n", + " \n", + " for word in list_of_words:\n", + " if phrase.startswith(word):\n", + " output.append(word)\n", + " word_split(phrase[len(word):], list_of_words, output)\n", + " return output\n", + " pass " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Luck!\n", + "\n", + "Check out the Solutions Notebook once you're done!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/.ipynb_checkpoints/Recursion Homework Example Problems - SOLUTIONS-checkpoint.ipynb b/Recursion/.ipynb_checkpoints/Recursion Homework Example Problems - SOLUTIONS-checkpoint.ipynb new file mode 100644 index 00000000..f7bafd8e --- /dev/null +++ b/Recursion/.ipynb_checkpoints/Recursion Homework Example Problems - SOLUTIONS-checkpoint.ipynb @@ -0,0 +1,327 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Recursion Homework Problems - Solutions\n", + "\n", + "This assignment is a variety of small problems to begin you getting used to the idea of recursion. They are not full-blown interview questions, but do serve as a great start for getting your mind \"in the zone\" for recursion problems.\n", + "\n", + "Here are the solutions with some simple explanations to the problems.\n", + "\n", + "______\n", + "### Problem 1\n", + "\n", + "**Write a recursive function which takes an integer and computes the cumulative sum of 0 to that integer**\n", + "\n", + "**For example, if n=4 , return 4+3+2+1+0, which is 10.**\n", + "\n", + "This problem is very similar to the factorial problem presented during the introduction to recursion. Remember, always think of what the base case will look like. In this case, we have a base case of n =0 (Note, you could have also designed the cut off to be 1).\n", + "\n", + "In this case, we have:\n", + " n + (n-1) + (n-2) + .... + 0\n", + "\n", + "Check out a sample solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rec_sum(n):\n", + " \n", + " # Base Case\n", + " if n == 0:\n", + " return 0\n", + " \n", + " # Recursion\n", + " else:\n", + " return n + rec_sum(n-1)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_sum(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "______\n", + "### Problem 2\n", + "\n", + "**Given an integer, create a function which returns the sum of all the individual digits in that integer. For example:\n", + "if n = 4321, return 4+3+2+1**" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def sum_func(n):\n", + " # Base case\n", + " if len(str(n)) == 1:\n", + " return n\n", + " \n", + " # Recursion\n", + " else:\n", + " return n%10 + sum_func(n/10)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum_func(4321)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Hints:*" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# You'll neeed to use modulo\n", + "4321%10" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "432" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4321 / 10" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We'll need to think of this function recursively by knowing that:\n", + "4502 % 10 + sum_func(4502/10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "________\n", + "### Problem 3\n", + "*Note, this is a more advanced problem than the previous two! It aso has a lot of variation possibilities and we're ignoring strict requirements here.*\n", + "\n", + "Create a function called word_split() which takes in a string **phrase** and a set **list_of_words**. The function will then determine if it is possible to split the string in a way in which words can be made from the list of words. You can assume the phrase will only contain words found in the dictionary if it is completely splittable.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['the', 'man', 'ran']" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['the','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['i', 'love', 'dogs', 'John']" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('ilovedogsJohn',['i','am','a','dogs','lover','love','John'])" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['clown','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def word_split(phrase,list_of_words, output = None):\n", + " '''\n", + " Note: This is a very \"python-y\" solution.\n", + " ''' \n", + " \n", + " # Checks to see if any output has been initiated.\n", + " # If you default output=[], it would be overwritten for every recursion!\n", + " if output is None:\n", + " output = []\n", + " \n", + " # For every word in list\n", + " for word in list_of_words:\n", + " \n", + " # If the current phrase begins with the word, we have a split point!\n", + " if phrase.startswith(word):\n", + " \n", + " # Add the word to the output\n", + " output.append(word)\n", + " \n", + " # Recursively call the split function on the remaining portion of the phrase--- phrase[len(word):]\n", + " # Remember to pass along the output and list of words\n", + " return word_split(phrase[len(word):],list_of_words,output)\n", + " \n", + " # Finally return output if no phrase.startswith(word) returns True\n", + " return output " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "Alright, so now that we've seen a few examples, let's dive in to the interview practice problems!" + ] + } + ], + "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 +} diff --git a/Recursion/.ipynb_checkpoints/Recursion Homework Example Problems-checkpoint.ipynb b/Recursion/.ipynb_checkpoints/Recursion Homework Example Problems-checkpoint.ipynb new file mode 100644 index 00000000..ebe52213 --- /dev/null +++ b/Recursion/.ipynb_checkpoints/Recursion Homework Example Problems-checkpoint.ipynb @@ -0,0 +1,291 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Recursion Homework Problems \n", + "\n", + "This assignment is a variety of small problems to begin you getting used to the idea of recursion. They are not full-blown interview questions, but do serve as a great start for getting your mind \"in the zone\" for recursion problems.\n", + "\n", + "\n", + "______\n", + "### Problem 1\n", + "\n", + "**Write a recursive function which takes an integer and computes the cumulative sum of 0 to that integer**\n", + "\n", + "**For example, if n=4 , return 4+3+2+1+0, which is 10.**\n", + "\n", + "This problem is very similar to the factorial problem presented during the introduction to recursion. Remember, always think of what the base case will look like. In this case, we have a base case of n =0 (Note, you could have also designed the cut off to be 1).\n", + "\n", + "In this case, we have:\n", + " n + (n-1) + (n-2) + .... + 0\n", + "\n", + "Fill out a sample solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rec_sum(n):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_sum(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "______\n", + "### Problem 2\n", + "\n", + "**Given an integer, create a function which returns the sum of all the individual digits in that integer. For example:\n", + "if n = 4321, return 4+3+2+1**" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def sum_func(n):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum_func(4321)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Hints:*" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# You'll neeed to use modulo\n", + "4321%10" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "432" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4321 / 10" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We'll need to think of this function recursively by knowing that:\n", + "4502 % 10 + sum_func(4502/10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "________\n", + "### Problem 3\n", + "*Note, this is a more advanced problem than the previous two! It aso has a lot of variation possibilities and we're ignoring strict requirements here.*\n", + "\n", + "Create a function called word_split() which takes in a string **phrase** and a set **list_of_words**. The function will then determine if it is possible to split the string in a way in which words can be made from the list of words. You can assume the phrase will only contain words found in the dictionary if it is completely splittable.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['the', 'man', 'ran']" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['the','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['i', 'love', 'dogs', 'John']" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('ilovedogsJohn',['i','am','a','dogs','lover','love','John'])" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['clown','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def word_split(phrase,list_of_words, output = None):\n", + " pass " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Luck!\n", + "\n", + "Check out the Solutions Notebook once you're done!" + ] + } + ], + "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 +} diff --git a/Recursion/Introduction to Recursion.ipynb b/Recursion/Introduction to Recursion.ipynb new file mode 100644 index 00000000..0a165bd9 --- /dev/null +++ b/Recursion/Introduction to Recursion.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction to Recursion\n", + "\n", + "In this lecture we will go over the basics of Recursion.\n", + "\n", + "## What is Recursion?\n", + "\n", + "There are two main instances of recursion. The first is when recursion is used as a technique in which a function makes one or more calls to itself. The second is when a data structure uses smaller instances of the exact same type of data structure when it represents itself. Both of these instances are use cases of recursion.\n", + "\n", + "Recursion actually occurs in the real world, such as fractal patterns seen in plants!\n", + "\n", + "## Why use Recursion?\n", + "\n", + "Recursion provides a powerful alternative for performing repetitions of tasks in which a loop is not ideal. Most modern programming languages support recursion and recursion serves as a great tool for building out particular data structures.\n", + "\n", + "We'll start this introduction with an example of recursion- a factorial function.\n", + "\n", + "_______\n", + "# Factorial Example\n", + "\n", + "In this part of the lecture we will explain recursion through an example excercise of creating the factorial function.\n", + "The factorial function is denoted with an exclamation point and is defined as the product of the integers from 1 to *n*. Formally, we can state this as:\n", + "\n", + "$$ n! = n·(n-1)·(n-2)... 3·2·1 $$\n", + "\n", + "Note, **if n = 0, then n! = 1**. This is important to take into account, because it will serve as our *base case*. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Take this example:\n", + "$$4! = 4 · 3 · 2 · 1 = 24. $$\n", + "So how can we state this in a recursive manner? This is where the concept of **base case** comes in.\n", + "\n", + "**Base case** is a key part of understanding recursion, especially when it comes to having to solve interview problems dealing with recursion. Let's rewrite the above equation of 4! so it looks like this:\n", + "\n", + "$$ 4! = 4 · (3 · 2 · 1) = 24 $$\n", + "\n", + "Notice that this is the same as:\n", + "\n", + "$$ 4! = 4 · 3! = 24 $$\n", + "\n", + "Meaning we can rewrite the formal recursion definition in terms of recursion like so:\n", + "\n", + "$$ n! = n·(n−1)!$$\n", + "\n", + "Note, **if n = 0, then n! = 1**. This means the **base case** occurs once n=0, the *recursive cases* are defined in the equation above. Whenever you are trying to develop a recursive solution it is very important to think about the base case, as your solution will need to return the base case once all the recursive cases have been worked through. Let's look at how we can create the factorial function in Python:\n", + "___" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def fact(n):\n", + " '''\n", + " Returns factorial of n (n!).\n", + " Note use of recursion\n", + " '''\n", + " # BASE CASE!\n", + " if n == 0:\n", + " return 1\n", + " \n", + " # Recursion!\n", + " else:\n", + " return n * fact(n-1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see it in action!" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "120" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fact(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "Note how we had an if statement to check if a base case occured. Without it this function would not have successfully completed running. We can visualize the recursion with the following figure:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "from IPython.core.display import HTML \n", + "Image(url= 'http://faculty.cs.niu.edu/~freedman/241/241notes/recur.gif')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We can follow this flow chart from the top, reaching the base case, and then working our way back up.\n", + "\n", + "# Conclusion\n", + "\n", + "Recursion is a powerful tool, but it can be a tricky concept to implement. In the next lectures we will go over a few more example problems for recursion. Then afterwards you'll be faced with some real interview questions involving recursion!" + ] + } + ], + "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 +} diff --git a/Recursion/Memoization.ipynb b/Recursion/Memoization.ipynb new file mode 100644 index 00000000..8921ed05 --- /dev/null +++ b/Recursion/Memoization.ipynb @@ -0,0 +1,145 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Memoization\n", + "\n", + "In this lecture we will discuss memoization and dynamic programming. For your homework assignment, read the [Wikipedia article on Memoization](https://en.wikipedia.org/wiki/Memoization), before continuing on with this lecture!\n", + "\n", + "____\n", + "\n", + "Memoization effectively refers to remembering (\"memoization\" -> \"memorandum\" -> to be remembered) results of method calls based on the method inputs and then returning the remembered result rather than computing the result again. You can think of it as a cache for method results. We'll use this in some of the interview problems as improved versions of a purely recursive solution.\n", + "\n", + "A simple example for computing factorials using memoization in Python would be something like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Create cache for known results\n", + "factorial_memo = {}\n", + "\n", + "def factorial(k):\n", + " \n", + " if k < 2: \n", + " return 1\n", + " \n", + " if not k in factorial_memo:\n", + " factorial_memo[k] = k * factorial(k-1)\n", + " \n", + " return factorial_memo[k]" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "24" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "factorial(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we are now using a dictionary to store previous results of the factorial function! We are now able to increase the efficiency of this function by remembering old results!\n", + "\n", + "Keep this in mind when working on the Coin Change Problem and the Fibonacci Sequence Problem.\n", + "\n", + "___\n", + "\n", + "We can also encapsulate the memoization process into a class:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Memoize:\n", + " def __init__(self, f):\n", + " self.f = f\n", + " self.memo = {}\n", + " def __call__(self, *args):\n", + " if not args in self.memo:\n", + " self.memo[args] = self.f(*args)\n", + " return self.memo[args]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then all we would have to do is:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def factorial(k):\n", + " \n", + " if k < 2: \n", + " return 1\n", + " \n", + " return k * factorial(k - 1)\n", + "\n", + "factorial = Memoize(factorial)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Try comparing the run times of the memoization versions of functions versus the normal recursive 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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Homework Example Problems - PRACTICE.ipynb b/Recursion/Recursion Homework Example Problems - PRACTICE.ipynb new file mode 100644 index 00000000..b6c7d5bb --- /dev/null +++ b/Recursion/Recursion Homework Example Problems - PRACTICE.ipynb @@ -0,0 +1,293 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Recursion Homework Problems \n", + "\n", + "This assignment is a variety of small problems to begin you getting used to the idea of recursion. They are not full-blown interview questions, but do serve as a great start for getting your mind \"in the zone\" for recursion problems.\n", + "\n", + "\n", + "______\n", + "### Problem 1\n", + "\n", + "**Write a recursive function which takes an integer and computes the cumulative sum of 0 to that integer**\n", + "\n", + "**For example, if n=4 , return 4+3+2+1+0, which is 10.**\n", + "\n", + "This problem is very similar to the factorial problem presented during the introduction to recursion. Remember, always think of what the base case will look like. In this case, we have a base case of n =0 (Note, you could have also designed the cut off to be 1).\n", + "\n", + "In this case, we have:\n", + " n + (n-1) + (n-2) + .... + 0\n", + "\n", + "Fill out a sample solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "def rec_sum(n):\n", + " if n == 0:\n", + " return 0\n", + " else:\n", + " return n + rec_sum(n-1)\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_sum(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "______\n", + "### Problem 2\n", + "\n", + "**Given an integer, create a function which returns the sum of all the individual digits in that integer. For example:\n", + "if n = 4321, return 4+3+2+1**" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def sum_func(n):\n", + " if(n<10):\n", + " return n\n", + " else:\n", + " return n%10 + sum_func(int(n/10))\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum_func(4321)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Hints:*" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# You'll neeed to use modulo\n", + "4321%10" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "432" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4321 / 10" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We'll need to think of this function recursively by knowing that:\n", + "4502 % 10 + sum_func(4502/10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "________\n", + "### Problem 3\n", + "*Note, this is a more advanced problem than the previous two! It aso has a lot of variation possibilities and we're ignoring strict requirements here.*\n", + "\n", + "Create a function called word_split() which takes in a string **phrase** and a set **list_of_words**. The function will then determine if it is possible to split the string in a way in which words can be made from the list of words. You can assume the phrase will only contain words found in the dictionary if it is completely splittable.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['the', 'man', 'ran']" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['the','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['i', 'love', 'dogs', 'John']" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('ilovedogsJohn',['i','am','a','dogs','lover','love','John'])" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['clown','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def word_split(phrase,list_of_words, output = None):\n", + " if output is None:\n", + " output = []\n", + " \n", + " for word in list_of_words:\n", + " if phrase.startswith(word):\n", + " output.append(word)\n", + " word_split(phrase[len(word):], list_of_words, output)\n", + " return output\n", + " pass " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Luck!\n", + "\n", + "Check out the Solutions Notebook once you're done!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Homework Example Problems - SOLUTIONS.ipynb b/Recursion/Recursion Homework Example Problems - SOLUTIONS.ipynb new file mode 100644 index 00000000..f7bafd8e --- /dev/null +++ b/Recursion/Recursion Homework Example Problems - SOLUTIONS.ipynb @@ -0,0 +1,327 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Recursion Homework Problems - Solutions\n", + "\n", + "This assignment is a variety of small problems to begin you getting used to the idea of recursion. They are not full-blown interview questions, but do serve as a great start for getting your mind \"in the zone\" for recursion problems.\n", + "\n", + "Here are the solutions with some simple explanations to the problems.\n", + "\n", + "______\n", + "### Problem 1\n", + "\n", + "**Write a recursive function which takes an integer and computes the cumulative sum of 0 to that integer**\n", + "\n", + "**For example, if n=4 , return 4+3+2+1+0, which is 10.**\n", + "\n", + "This problem is very similar to the factorial problem presented during the introduction to recursion. Remember, always think of what the base case will look like. In this case, we have a base case of n =0 (Note, you could have also designed the cut off to be 1).\n", + "\n", + "In this case, we have:\n", + " n + (n-1) + (n-2) + .... + 0\n", + "\n", + "Check out a sample solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rec_sum(n):\n", + " \n", + " # Base Case\n", + " if n == 0:\n", + " return 0\n", + " \n", + " # Recursion\n", + " else:\n", + " return n + rec_sum(n-1)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_sum(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "______\n", + "### Problem 2\n", + "\n", + "**Given an integer, create a function which returns the sum of all the individual digits in that integer. For example:\n", + "if n = 4321, return 4+3+2+1**" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def sum_func(n):\n", + " # Base case\n", + " if len(str(n)) == 1:\n", + " return n\n", + " \n", + " # Recursion\n", + " else:\n", + " return n%10 + sum_func(n/10)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum_func(4321)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Hints:*" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# You'll neeed to use modulo\n", + "4321%10" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "432" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4321 / 10" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We'll need to think of this function recursively by knowing that:\n", + "4502 % 10 + sum_func(4502/10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "________\n", + "### Problem 3\n", + "*Note, this is a more advanced problem than the previous two! It aso has a lot of variation possibilities and we're ignoring strict requirements here.*\n", + "\n", + "Create a function called word_split() which takes in a string **phrase** and a set **list_of_words**. The function will then determine if it is possible to split the string in a way in which words can be made from the list of words. You can assume the phrase will only contain words found in the dictionary if it is completely splittable.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['the', 'man', 'ran']" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['the','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['i', 'love', 'dogs', 'John']" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('ilovedogsJohn',['i','am','a','dogs','lover','love','John'])" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['clown','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def word_split(phrase,list_of_words, output = None):\n", + " '''\n", + " Note: This is a very \"python-y\" solution.\n", + " ''' \n", + " \n", + " # Checks to see if any output has been initiated.\n", + " # If you default output=[], it would be overwritten for every recursion!\n", + " if output is None:\n", + " output = []\n", + " \n", + " # For every word in list\n", + " for word in list_of_words:\n", + " \n", + " # If the current phrase begins with the word, we have a split point!\n", + " if phrase.startswith(word):\n", + " \n", + " # Add the word to the output\n", + " output.append(word)\n", + " \n", + " # Recursively call the split function on the remaining portion of the phrase--- phrase[len(word):]\n", + " # Remember to pass along the output and list of words\n", + " return word_split(phrase[len(word):],list_of_words,output)\n", + " \n", + " # Finally return output if no phrase.startswith(word) returns True\n", + " return output " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "Alright, so now that we've seen a few examples, let's dive in to the interview practice problems!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Homework Example Problems.ipynb b/Recursion/Recursion Homework Example Problems.ipynb new file mode 100644 index 00000000..ebe52213 --- /dev/null +++ b/Recursion/Recursion Homework Example Problems.ipynb @@ -0,0 +1,291 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Recursion Homework Problems \n", + "\n", + "This assignment is a variety of small problems to begin you getting used to the idea of recursion. They are not full-blown interview questions, but do serve as a great start for getting your mind \"in the zone\" for recursion problems.\n", + "\n", + "\n", + "______\n", + "### Problem 1\n", + "\n", + "**Write a recursive function which takes an integer and computes the cumulative sum of 0 to that integer**\n", + "\n", + "**For example, if n=4 , return 4+3+2+1+0, which is 10.**\n", + "\n", + "This problem is very similar to the factorial problem presented during the introduction to recursion. Remember, always think of what the base case will look like. In this case, we have a base case of n =0 (Note, you could have also designed the cut off to be 1).\n", + "\n", + "In this case, we have:\n", + " n + (n-1) + (n-2) + .... + 0\n", + "\n", + "Fill out a sample solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rec_sum(n):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_sum(4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "______\n", + "### Problem 2\n", + "\n", + "**Given an integer, create a function which returns the sum of all the individual digits in that integer. For example:\n", + "if n = 4321, return 4+3+2+1**" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def sum_func(n):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "10" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum_func(4321)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Hints:*" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# You'll neeed to use modulo\n", + "4321%10" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "432" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "4321 / 10" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We'll need to think of this function recursively by knowing that:\n", + "4502 % 10 + sum_func(4502/10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "________\n", + "### Problem 3\n", + "*Note, this is a more advanced problem than the previous two! It aso has a lot of variation possibilities and we're ignoring strict requirements here.*\n", + "\n", + "Create a function called word_split() which takes in a string **phrase** and a set **list_of_words**. The function will then determine if it is possible to split the string in a way in which words can be made from the list of words. You can assume the phrase will only contain words found in the dictionary if it is completely splittable.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['the', 'man', 'ran']" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['the','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['i', 'love', 'dogs', 'John']" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('ilovedogsJohn',['i','am','a','dogs','lover','love','John'])" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "word_split('themanran',['clown','ran','man'])" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def word_split(phrase,list_of_words, output = None):\n", + " pass " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Luck!\n", + "\n", + "Check out the Solutions Notebook once you're done!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 1 - Reverse String - SOLUTION-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 1 - Reverse String - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..3f683cab --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 1 - Reverse String - SOLUTION-checkpoint.ipynb @@ -0,0 +1,146 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reverse a String\n", + "\n", + "This interview question requires you to reverse a string using recursion. Make sure to think of the base case here.\n", + "\n", + "Again, make sure you use *recursion* to accomplish this. **Do not slice (e.g. string[::-1]) or use iteration, there muse be a recursive call for the function.**\n", + "\n", + "____\n", + "\n", + "## Solution\n", + "\n", + "In order to reverse a string using recursion we need to consider what a base and recursive case would look like. Here we've set a base case to be when the length of the string we are passing through the function is length less than or equal to 1.\n", + "\n", + "During the recursive case we grab the first letter and add it on to the recursive call." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def reverse(s):\n", + " \n", + " # Base Case\n", + " if len(s) <= 1:\n", + " return s\n", + "\n", + " # Recursion\n", + " return reverse(s[1:]) + s[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'dlrow olleh'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse('hello world')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solution against the following cases:\n", + "\n", + " string = 'hello'\n", + " string = 'hello world'\n", + " string = '123456789'" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASSED ALL TEST CASES!\n" + ] + } + ], + "source": [ + "'''\n", + "RUN THIS CELL TO TEST YOUR FUNCTION AGAINST SOME TEST CASES\n", + "'''\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestReverse(object):\n", + " \n", + " def test_rev(self,solution):\n", + " assert_equal(solution('hello'),'olleh')\n", + " assert_equal(solution('hello world'),'dlrow olleh')\n", + " assert_equal(solution('123456789'),'987654321')\n", + " \n", + " print 'PASSED ALL TEST CASES!'\n", + " \n", + "# Run Tests\n", + "test = TestReverse()\n", + "test.test_rev(reverse)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extra Notes\n", + "\n", + "The \"trick\" to this question was thinking about what a base case would look like when reversing a string recursively. It takes a lot of practice to be able to begin thinking like this, so don't worry if you're struggling! However it is important to fully understand the solution!\n", + "\n", + "**Good Job!**" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 2 - String Permutation- SOLUTION-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 2 - String Permutation- SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..31274b2b --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 2 - String Permutation- SOLUTION-checkpoint.ipynb @@ -0,0 +1,175 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# String Permutation\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string, write a function that uses recursion to output a list of all the possible permutations of that string.\n", + "\n", + "For example, given s='abc' the function should return ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']\n", + "\n", + "*Note: If a character is repeated, treat each occurence as distinct, for example an input of 'xxx' would return a list with 6 \"versions\" of 'xxx'*\n", + "\n", + "\n", + "## Fill Out Your Solution Below\n", + "\n", + "Let's think about what the steps we need to take here are:\n", + "\n", + "1. Iterate through the initial string – e.g., ‘abc’.\n", + "\n", + "* For each character in the initial string, set aside that character and get a list of all permutations of the string that’s left. So, for example, if the current iteration is on 'b', we’d want to find all the permutations of the string 'ac'.\n", + "\n", + "* Once you have the list from step 2, add each element from that list to the character from the initial string, and append the result to our list of final results. So if we’re on 'b' and we’ve gotten the list ['ac', 'ca'], we’d add 'b' to those, resulting in 'bac' and 'bca', each of which we’d add to our final results.\n", + "\n", + "* Return the list of final results.\n", + "\n", + "Let's go ahead and see this implemented:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def permute(s):\n", + " out = []\n", + " \n", + " # Base Case\n", + " if len(s) == 1:\n", + " out = [s]\n", + " \n", + " else:\n", + " # For every letter in string\n", + " for i, let in enumerate(s):\n", + " \n", + " # For every permutation resulting from Step 2 and 3 described above\n", + " for perm in permute(s[:i] + s[i+1:]):\n", + " \n", + " # Add it to output\n", + " out += [let + perm]\n", + "\n", + " return out" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['abc', 'acb', 'bac', 'bca', 'cab', 'cba']" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "permute('abc')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All test cases passed.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPerm(object):\n", + " \n", + " def test(self,solution):\n", + " \n", + " assert_equal(sorted(solution('abc')),sorted(['abc', 'acb', 'bac', 'bca', 'cab', 'cba']))\n", + " assert_equal(sorted(solution('dog')),sorted(['dog', 'dgo', 'odg', 'ogd', 'gdo', 'god']) )\n", + " \n", + " print 'All test cases passed.'\n", + " \n", + "\n", + "\n", + "# Run Tests\n", + "t = TestPerm()\n", + "t.test(permute)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___\n", + "# Conclusion\n", + "\n", + "There were two main takeaways from tackling this problem:\n", + "\n", + "* Every time we put a new letter in position i, we then had to find all the possible combinations at position i+1 – this was the recursive call that we made. How do we know when to save a string? When we are at a position i that is greater than the number of letters in the input string, then we know that we have found one valid permutation of the string and then we can add it to the list and return to changing letters at positions less than i. This was our base case – remember that we always must have a recursive case and a base case when using recursion!\n", + "\n", + "\n", + "* Another big part of this problem was figuring out which letters we can put in a given position. Using our sample string “abc”, lets say that we are going through all the permutations where the first letter is \"c”. Then, it should be clear that the letter in the 2nd and 3rd position can only be either “a” or “b”, because “a” is already used. As part of our algorithm, we have to know which letters can be used in a given position – because we can’t reuse the letters that were used in the earlier positions. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Good Job!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence - SOLUTION-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..30914e73 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence - SOLUTION-checkpoint.ipynb @@ -0,0 +1,265 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Fibonnaci Sequence\n", + "\n", + "## Problem Statement\n", + "\n", + "Implement a [Fibonnaci Sequence](https://en.wikipedia.org/wiki/Fibonacci_number) in three different ways:\n", + "\n", + "* Recursively\n", + "* Dynamically (Using Memoization to store results)\n", + "* Iteratively\n", + "\n", + "Remember that a fibonacci sequence: 0,1,1,2,3,5,8,13,21,... starts off with a base case checking to see if n = 0 or 1, then it returns 1. \n", + "\n", + "Else it returns fib(n-1)+fib(n+2)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Recursively\n", + "\n", + "The recursive solution is exponential time Big-O , with O(2^n). However, its a very simple and basic implementation to consider:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def fib_rec(n):\n", + " \n", + " # Base Case\n", + " if n == 0 or n == 1:\n", + " return n\n", + " \n", + " # Recursion\n", + " else:\n", + " return fib_rec(n-1) + fib_rec(n-2)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_rec(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dynamically\n", + "\n", + "In the form it is implemented here, the cache is set beforehand and is based on the desired **n** number of the Fibonacci Sequence. Note how we check it the cache[n] != None, meaning we have a check to know wether or not to keep setting the cache (and more importantly keep cache of old results!)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Instantiate Cache information\n", + "n = 10\n", + "cache = [None] * (n + 1)\n", + "\n", + "\n", + "def fib_dyn(n):\n", + " \n", + " # Base Case\n", + " if n == 0 or n == 1:\n", + " return n\n", + " \n", + " # Check cache\n", + " if cache[n] != None:\n", + " return cache[n]\n", + " \n", + " # Keep setting cache\n", + " cache[n] = fib_dyn(n-1) + fib_dyn(n-2)\n", + " \n", + " return cache[n]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_dyn(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Iteratively\n", + "\n", + "In this solution we can take advantage of Python's tuple unpacking!" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def fib_iter(n):\n", + " \n", + " # Set starting point\n", + " a = 0\n", + " b = 1\n", + " \n", + " # Follow algorithm\n", + " for i in range(n):\n", + " \n", + " a, b = b, a + b\n", + " \n", + " return a" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "28657" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_iter(23)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solutions, simply uncomment the solution functions you wish to test!" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Passed all tests.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "UNCOMMENT THE CODE AT THE BOTTOM OF THIS CELL TO SELECT WHICH SOLUTIONS TO TEST.\n", + "THEN RUN THE CELL.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFib(object):\n", + " \n", + " def test(self,solution):\n", + " assert_equal(solution(10),55)\n", + " assert_equal(solution(1),1)\n", + " assert_equal(solution(23),28657)\n", + " print 'Passed all tests.'\n", + "# UNCOMMENT FOR CORRESPONDING FUNCTION\n", + "t = TestFib()\n", + "\n", + "t.test(fib_rec)\n", + "#t.test(fib_dyn) # Note, will need to reset cache size for each test!\n", + "#t.test(fib_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "Hopefully this interview question served as a good excercise in exploring recursion, dynamic programming, and iterative solutions for a single problem! Its good to work through all three because in an interview a common question may just begin with requesting a recursive solution and then checking to se if you can implement the other forms!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 4 - Coin Change - SOLUTION-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 4 - Coin Change - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..a3ace666 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/.ipynb_checkpoints/Recursion Problem 4 - Coin Change - SOLUTION-checkpoint.ipynb @@ -0,0 +1,308 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Coin Change Problem\n", + "\n", + "**Note: This problem has multiple solutions and is a classic problem in showing issues with basic recursion. There are better solutions involving memoization and simple iterative solutions.If you are having trouble with this problem (or it seems to be taking a long time to run in some cases) check out the Solution Notebook and fully read the conclusion link for a detailed description of the various ways to solve this problem!**\n", + "\n", + "\n", + "This problem is common enough that is actually has its own [Wikipedia Entry](https://en.wikipedia.org/wiki/Change-making_problem)! Let's check the problem statement again:\n", + "\n", + "This is a classic recursion problem: Given a target amount **n** and a list (array) of distinct coin values, what's the fewest coins needed to make the change amount. \n", + "\n", + "For example:\n", + "\n", + "If n = 10 and coins = [1,5,10]. Then there are 4 possible ways to make change:\n", + "\n", + "* 1+1+1+1+1+1+1+1+1+1\n", + "\n", + "* 5 + 1+1+1+1+1\n", + "\n", + "* 5+5\n", + "\n", + "* 10\n", + "\n", + "With 1 coin being the minimum amount.\n", + "\n", + " \n", + "## Solution\n", + "\n", + "This is a classic problem to show the value of dynamic programming. We'll show a basic recursive example and show why it's actually not the best way to solve this problem.\n", + "\n", + "Make sure to read the comments in the code below to fully understand the basic logic!" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rec_coin(target,coins):\n", + " '''\n", + " INPUT: Target change amount and list of coin values\n", + " OUTPUT: Minimum coins needed to make change\n", + " \n", + " Note, this solution is not optimized.\n", + " '''\n", + " \n", + " # Default to target value\n", + " min_coins = target\n", + " \n", + " # Check to see if we have a single coin match (BASE CASE)\n", + " if target in coins:\n", + " return 1\n", + " \n", + " else:\n", + " \n", + " # for every coin value that is <= than target\n", + " for i in [c for c in coins if c <= target]:\n", + " \n", + " # Recursive Call (add a count coin and subtract from the target) \n", + " num_coins = 1 + rec_coin(target-i,coins)\n", + " \n", + " # Reset Minimum if we have a new minimum\n", + " if num_coins < min_coins:\n", + " \n", + " min_coins = num_coins\n", + " \n", + " return min_coins" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see it in action." + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n" + ] + } + ], + "source": [ + "rec_coin(63,[1,5,10,25])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The problem with this approach is that it is very inefficient! It can take many, many recursive calls to finish this problem and its also inaccurate for non standard coin values (coin values that are not 1,5,10, etc.)\n", + "\n", + "We can see the problem with this approach in the figure below:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "Image(url='http://interactivepython.org/runestone/static/pythonds/_images/callTree.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each node here corresponds to a call to the **rec_coin** function. The label on the node indicated the amount of change for which we are now computng the number of coins for. Note how we are recalculating values we've already solved! For instance 15 is called 3 times. It would be much better if we could keep track of function calls we've already made.\n", + "_____\n", + "## Dynamic Programming Solution\n", + "\n", + "This is the key to reducing the work time for the function. The better solution is to remember past results, that way before computing a new minimum we can check to see if we already know a result.\n", + "\n", + "Let's implement this:" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def rec_coin_dynam(target,coins,known_results):\n", + " '''\n", + " INPUT: This funciton takes in a target amount and a list of possible coins to use.\n", + " It also takes a third parameter, known_results, indicating previously calculated results.\n", + " The known_results parameter shoud be started with [0] * (target+1)\n", + " \n", + " OUTPUT: Minimum number of coins needed to make the target.\n", + " '''\n", + " \n", + " # Default output to target\n", + " min_coins = target\n", + " \n", + " # Base Case\n", + " if target in coins:\n", + " known_results[target] = 1\n", + " return 1\n", + " \n", + " # Return a known result if it happens to be greater than 1\n", + " elif known_results[target] > 0:\n", + " return known_results[target]\n", + " \n", + " else:\n", + " # for every coin value that is <= than target\n", + " for i in [c for c in coins if c <= target]:\n", + " \n", + " # Recursive call, note how we include the known results!\n", + " num_coins = 1 + rec_coin_dynam(target-i,coins,known_results)\n", + " \n", + " # Reset Minimum if we have a new minimum\n", + " if num_coins < min_coins:\n", + " min_coins = num_coins\n", + " \n", + " # Reset the known result\n", + " known_results[target] = min_coins\n", + " \n", + " return min_coins" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's test it!" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target = 74\n", + "coins = [1,5,10,25]\n", + "known_results = [0]*(target+1)\n", + "\n", + "rec_coin_dynam(target,coins,known_results)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your function against some test cases. \n", + "\n", + "**Note that the TestCoins class only test functions with two parameter inputs, the list of coins and the target**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR FUNCTION.\n", + "NOTE: NON-DYNAMIC FUNCTIONS WILL TAKE A LONG TIME TO TEST. IF YOU BELIEVE YOU HAVE A SOLUTION\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCoins(object):\n", + " \n", + " def check(self,solution):\n", + " coins = [1,5,10,25]\n", + " assert_equal(solution(45,coins),3)\n", + " assert_equal(solution(23,coins),5)\n", + " assert_equal(solution(74,coins),8)\n", + "\n", + " print 'Passed all tests.'\n", + " \n", + "# Run Test\n", + "\n", + "test = TestCoins()\n", + "test.check(rec_coin)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion and Extra Resources\n", + "\n", + "For homework, read the link below and also implement the non-recursive solution described in the link!\n", + "\n", + "For another great resource on a variation of this problem, check out this link:\n", + "[Dynamic Programming Coin Change Problem](http://interactivepython.org/runestone/static/pythonds/Recursion/DynamicProgramming.html)" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 1 - Reverse String - SOLUTION.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 1 - Reverse String - SOLUTION.ipynb new file mode 100644 index 00000000..fa3aca61 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 1 - Reverse String - SOLUTION.ipynb @@ -0,0 +1,140 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reverse a String\n", + "\n", + "This interview question requires you to reverse a string using recursion. Make sure to think of the base case here.\n", + "\n", + "Again, make sure you use *recursion* to accomplish this. **Do not slice (e.g. string[::-1]) or use iteration, there muse be a recursive call for the function.**\n", + "\n", + "____\n", + "\n", + "## Solution\n", + "\n", + "In order to reverse a string using recursion we need to consider what a base and recursive case would look like. Here we've set a base case to be when the length of the string we are passing through the function is length less than or equal to 1.\n", + "\n", + "During the recursive case we grab the first letter and add it on to the recursive call." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def reverse(s):\n", + " \n", + " # Base Case\n", + " if len(s) <= 1:\n", + " return s\n", + "\n", + " # Recursion\n", + " return reverse(s[1:]) + s[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'dlrow olleh'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse('hello world')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solution against the following cases:\n", + "\n", + " string = 'hello'\n", + " string = 'hello world'\n", + " string = '123456789'" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASSED ALL TEST CASES!\n" + ] + } + ], + "source": [ + "'''\n", + "RUN THIS CELL TO TEST YOUR FUNCTION AGAINST SOME TEST CASES\n", + "'''\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestReverse(object):\n", + " \n", + " def test_rev(self,solution):\n", + " assert_equal(solution('hello'),'olleh')\n", + " assert_equal(solution('hello world'),'dlrow olleh')\n", + " assert_equal(solution('123456789'),'987654321')\n", + " \n", + " print 'PASSED ALL TEST CASES!'\n", + " \n", + "# Run Tests\n", + "test = TestReverse()\n", + "test.test_rev(reverse)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extra Notes\n", + "\n", + "The \"trick\" to this question was thinking about what a base case would look like when reversing a string recursively. It takes a lot of practice to be able to begin thinking like this, so don't worry if you're struggling! However it is important to fully understand the solution!\n", + "\n", + "**Good Job!**" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 2 - String Permutation- SOLUTION.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 2 - String Permutation- SOLUTION.ipynb new file mode 100644 index 00000000..a45943a5 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 2 - String Permutation- SOLUTION.ipynb @@ -0,0 +1,171 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# String Permutation\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string, write a function that uses recursion to output a list of all the possible permutations of that string.\n", + "\n", + "For example, given s='abc' the function should return ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']\n", + "\n", + "*Note: If a character is repeated, treat each occurence as distinct, for example an input of 'xxx' would return a list with 6 \"versions\" of 'xxx'*\n", + "\n", + "\n", + "## Fill Out Your Solution Below\n", + "\n", + "Let's think about what the steps we need to take here are:\n", + "\n", + "1. Iterate through the initial string – e.g., ‘abc’.\n", + "\n", + "* For each character in the initial string, set aside that character and get a list of all permutations of the string that’s left. So, for example, if the current iteration is on 'b', we’d want to find all the permutations of the string 'ac'.\n", + "\n", + "* Once you have the list from step 2, add each element from that list to the character from the initial string, and append the result to our list of final results. So if we’re on 'b' and we’ve gotten the list ['ac', 'ca'], we’d add 'b' to those, resulting in 'bac' and 'bca', each of which we’d add to our final results.\n", + "\n", + "* Return the list of final results.\n", + "\n", + "Let's go ahead and see this implemented:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def permute(s):\n", + " out = []\n", + " \n", + " # Base Case\n", + " if len(s) == 1:\n", + " out = [s]\n", + " \n", + " else:\n", + " # For every letter in string\n", + " for i, let in enumerate(s):\n", + " \n", + " # For every permutation resulting from Step 2 and 3 described above\n", + " for perm in permute(s[:i] + s[i+1:]):\n", + " \n", + " # Add it to output\n", + " out += [let + perm]\n", + "\n", + " return out" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['abc', 'acb', 'bac', 'bca', 'cab', 'cba']" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "permute('abc')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All test cases passed.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPerm(object):\n", + " \n", + " def test(self,solution):\n", + " \n", + " assert_equal(sorted(solution('abc')),sorted(['abc', 'acb', 'bac', 'bca', 'cab', 'cba']))\n", + " assert_equal(sorted(solution('dog')),sorted(['dog', 'dgo', 'odg', 'ogd', 'gdo', 'god']) )\n", + " \n", + " print 'All test cases passed.'\n", + " \n", + "\n", + "\n", + "# Run Tests\n", + "t = TestPerm()\n", + "t.test(permute)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___\n", + "# Conclusion\n", + "\n", + "There were two main takeaways from tackling this problem:\n", + "\n", + "* Every time we put a new letter in position i, we then had to find all the possible combinations at position i+1 – this was the recursive call that we made. How do we know when to save a string? When we are at a position i that is greater than the number of letters in the input string, then we know that we have found one valid permutation of the string and then we can add it to the list and return to changing letters at positions less than i. This was our base case – remember that we always must have a recursive case and a base case when using recursion!\n", + "\n", + "\n", + "* Another big part of this problem was figuring out which letters we can put in a given position. Using our sample string “abc”, lets say that we are going through all the permutations where the first letter is \"c”. Then, it should be clear that the letter in the 2nd and 3rd position can only be either “a” or “b”, because “a” is already used. As part of our algorithm, we have to know which letters can be used in a given position – because we can’t reuse the letters that were used in the earlier positions. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 3 - Fibonacci Sequence - SOLUTION.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 3 - Fibonacci Sequence - SOLUTION.ipynb new file mode 100644 index 00000000..a774e188 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 3 - Fibonacci Sequence - SOLUTION.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Fibonnaci Sequence\n", + "\n", + "## Problem Statement\n", + "\n", + "Implement a [Fibonnaci Sequence](https://en.wikipedia.org/wiki/Fibonacci_number) in three different ways:\n", + "\n", + "* Recursively\n", + "* Dynamically (Using Memoization to store results)\n", + "* Iteratively\n", + "\n", + "Remember that a fibonacci sequence: 0,1,1,2,3,5,8,13,21,... starts off with a base case checking to see if n = 0 or 1, then it returns 1. \n", + "\n", + "Else it returns fib(n-1)+fib(n+2)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Recursively\n", + "\n", + "The recursive solution is exponential time Big-O , with O(2^n). However, its a very simple and basic implementation to consider:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def fib_rec(n):\n", + " \n", + " # Base Case\n", + " if n == 0 or n == 1:\n", + " return n\n", + " \n", + " # Recursion\n", + " else:\n", + " return fib_rec(n-1) + fib_rec(n-2)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_rec(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dynamically\n", + "\n", + "In the form it is implemented here, the cache is set beforehand and is based on the desired **n** number of the Fibonacci Sequence. Note how we check it the cache[n] != None, meaning we have a check to know wether or not to keep setting the cache (and more importantly keep cache of old results!)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# Instantiate Cache information\n", + "n = 10\n", + "cache = [None] * (n + 1)\n", + "\n", + "\n", + "def fib_dyn(n):\n", + " \n", + " # Base Case\n", + " if n == 0 or n == 1:\n", + " return n\n", + " \n", + " # Check cache\n", + " if cache[n] != None:\n", + " return cache[n]\n", + " \n", + " # Keep setting cache\n", + " cache[n] = fib_dyn(n-1) + fib_dyn(n-2)\n", + " \n", + " return cache[n]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_dyn(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Iteratively\n", + "\n", + "In this solution we can take advantage of Python's tuple unpacking!" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def fib_iter(n):\n", + " \n", + " # Set starting point\n", + " a = 0\n", + " b = 1\n", + " \n", + " # Follow algorithm\n", + " for i in range(n):\n", + " \n", + " a, b = b, a + b\n", + " \n", + " return a" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "28657" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_iter(23)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solutions, simply uncomment the solution functions you wish to test!" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Passed all tests.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "UNCOMMENT THE CODE AT THE BOTTOM OF THIS CELL TO SELECT WHICH SOLUTIONS TO TEST.\n", + "THEN RUN THE CELL.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFib(object):\n", + " \n", + " def test(self,solution):\n", + " assert_equal(solution(10),55)\n", + " assert_equal(solution(1),1)\n", + " assert_equal(solution(23),28657)\n", + " print 'Passed all tests.'\n", + "# UNCOMMENT FOR CORRESPONDING FUNCTION\n", + "t = TestFib()\n", + "\n", + "t.test(fib_rec)\n", + "#t.test(fib_dyn) # Note, will need to reset cache size for each test!\n", + "#t.test(fib_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "Hopefully this interview question served as a good excercise in exploring recursion, dynamic programming, and iterative solutions for a single problem! Its good to work through all three because in an interview a common question may just begin with requesting a recursive solution and then checking to se if you can implement the other forms!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 4 - Coin Change - SOLUTION.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 4 - Coin Change - SOLUTION.ipynb new file mode 100644 index 00000000..2368b86b --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - SOLUTIONS/Recursion Problem 4 - Coin Change - SOLUTION.ipynb @@ -0,0 +1,299 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Coin Change Problem\n", + "\n", + "**Note: This problem has multiple solutions and is a classic problem in showing issues with basic recursion. There are better solutions involving memoization and simple iterative solutions.If you are having trouble with this problem (or it seems to be taking a long time to run in some cases) check out the Solution Notebook and fully read the conclusion link for a detailed description of the various ways to solve this problem!**\n", + "\n", + "\n", + "This problem is common enough that is actually has its own [Wikipedia Entry](https://en.wikipedia.org/wiki/Change-making_problem)! Let's check the problem statement again:\n", + "\n", + "This is a classic recursion problem: Given a target amount **n** and a list (array) of distinct coin values, what's the fewest coins needed to make the change amount. \n", + "\n", + "For example:\n", + "\n", + "If n = 10 and coins = [1,5,10]. Then there are 4 possible ways to make change:\n", + "\n", + "* 1+1+1+1+1+1+1+1+1+1\n", + "\n", + "* 5 + 1+1+1+1+1\n", + "\n", + "* 5+5\n", + "\n", + "* 10\n", + "\n", + "With 1 coin being the minimum amount.\n", + "\n", + " \n", + "## Solution\n", + "\n", + "This is a classic problem to show the value of dynamic programming. We'll show a basic recursive example and show why it's actually not the best way to solve this problem.\n", + "\n", + "Make sure to read the comments in the code below to fully understand the basic logic!" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "def rec_coin(target,coins):\n", + " '''\n", + " INPUT: Target change amount and list of coin values\n", + " OUTPUT: Minimum coins needed to make change\n", + " \n", + " Note, this solution is not optimized.\n", + " '''\n", + " \n", + " # Default to target value\n", + " min_coins = target\n", + " \n", + " # Check to see if we have a single coin match (BASE CASE)\n", + " if target in coins:\n", + " return 1\n", + " \n", + " else:\n", + " \n", + " # for every coin value that is <= than target\n", + " for i in [c for c in coins if c <= target]:\n", + " \n", + " # Recursive Call (add a count coin and subtract from the target) \n", + " num_coins = 1 + rec_coin(target-i,coins)\n", + " \n", + " # Reset Minimum if we have a new minimum\n", + " if num_coins < min_coins:\n", + " \n", + " min_coins = num_coins\n", + " \n", + " return min_coins" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see it in action." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_coin(63,[1,5,10,25])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The problem with this approach is that it is very inefficient! It can take many, many recursive calls to finish this problem and its also inaccurate for non standard coin values (coin values that are not 1,5,10, etc.)\n", + "\n", + "We can see the problem with this approach in the figure below:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "Image(url='http://interactivepython.org/runestone/static/pythonds/_images/callTree.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each node here corresponds to a call to the **rec_coin** function. The label on the node indicated the amount of change for which we are now computng the number of coins for. Note how we are recalculating values we've already solved! For instance 15 is called 3 times. It would be much better if we could keep track of function calls we've already made.\n", + "_____\n", + "## Dynamic Programming Solution\n", + "\n", + "This is the key to reducing the work time for the function. The better solution is to remember past results, that way before computing a new minimum we can check to see if we already know a result.\n", + "\n", + "Let's implement this:" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "def rec_coin_dynam(target,coins,known_results):\n", + " '''\n", + " INPUT: This funciton takes in a target amount and a list of possible coins to use.\n", + " It also takes a third parameter, known_results, indicating previously calculated results.\n", + " The known_results parameter shoud be started with [0] * (target+1)\n", + " \n", + " OUTPUT: Minimum number of coins needed to make the target.\n", + " '''\n", + " \n", + " # Default output to target\n", + " min_coins = target\n", + " \n", + " # Base Case\n", + " if target in coins:\n", + " known_results[target] = 1\n", + " return 1\n", + " \n", + " # Return a known result if it happens to be greater than 1\n", + " elif known_results[target] > 0:\n", + " return known_results[target]\n", + " \n", + " else:\n", + " # for every coin value that is <= than target\n", + " for i in [c for c in coins if c <= target]:\n", + " \n", + " # Recursive call, note how we include the known results!\n", + " num_coins = 1 + rec_coin_dynam(target-i,coins,known_results)\n", + " \n", + " # Reset Minimum if we have a new minimum\n", + " if num_coins < min_coins:\n", + " min_coins = num_coins\n", + " \n", + " # Reset the known result\n", + " known_results[target] = min_coins\n", + " \n", + " return min_coins" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's test it!" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target = 74\n", + "coins = [1,5,10,25]\n", + "known_results = [0]*(target+1)\n", + "\n", + "rec_coin_dynam(target,coins,known_results)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your function against some test cases. \n", + "\n", + "**Note that the TestCoins class only test functions with two parameter inputs, the list of coins and the target**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR FUNCTION.\n", + "NOTE: NON-DYNAMIC FUNCTIONS WILL TAKE A LONG TIME TO TEST. IF YOU BELIEVE YOU HAVE A SOLUTION\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCoins(object):\n", + " \n", + " def check(self,solution):\n", + " coins = [1,5,10,25]\n", + " assert_equal(solution(45,coins),3)\n", + " assert_equal(solution(23,coins),5)\n", + " assert_equal(solution(74,coins),8)\n", + "\n", + " print 'Passed all tests.'\n", + " \n", + "# Run Test\n", + "\n", + "test = TestCoins()\n", + "test.check(rec_coin)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion and Extra Resources\n", + "\n", + "For homework, read the link below and also implement the non-recursive solution described in the link!\n", + "\n", + "For another great resource on a variation of this problem, check out this link:\n", + "[Dynamic Programming Coin Change Problem](http://interactivepython.org/runestone/static/pythonds/Recursion/DynamicProgramming.html)" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 1 - Reverse String -checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 1 - Reverse String -checkpoint.ipynb new file mode 100644 index 00000000..b645222c --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 1 - Reverse String -checkpoint.ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reverse a String\n", + "\n", + "This interview question requires you to reverse a string using recursion. Make sure to think of the base case here.\n", + "\n", + "Again, make sure you use *recursion* to accomplish this. **Do not slice (e.g. string[::-1]) or use iteration, there must be a recursive call for the function.**\n", + "\n", + "____\n", + "\n", + "### Fill out your solution below" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def reverse(s):\n", + " if(len(s)<=1):\n", + " return s\n", + " else:\n", + " m = int(len(s)/2)\n", + " return reverse(s[m:]) + (reverse((s[:m])))\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'dlrow olleh'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse('hello world')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solution against the following cases:\n", + "\n", + " string = 'hello'\n", + " string = 'hello world'\n", + " string = '123456789'" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASSED ALL TEST CASES!\n" + ] + } + ], + "source": [ + "'''\n", + "RUN THIS CELL TO TEST YOUR FUNCTION AGAINST SOME TEST CASES\n", + "'''\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestReverse(object):\n", + " \n", + " def test_rev(self,solution):\n", + " assert_equal(solution('hello'),'olleh')\n", + " assert_equal(solution('hello world'),'dlrow olleh')\n", + " assert_equal(solution('123456789'),'987654321')\n", + " \n", + " print ('PASSED ALL TEST CASES!')\n", + " \n", + "# Run Tests\n", + "test = TestReverse()\n", + "test.test_rev(reverse)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Good Luck!**" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 2 - String Permutation-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 2 - String Permutation-checkpoint.ipynb new file mode 100644 index 00000000..e2585c12 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 2 - String Permutation-checkpoint.ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# String Permutation\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string, write a function that uses recursion to output a list of all the possible permutations of that string.\n", + "\n", + "For example, given s='abc' the function should return ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']\n", + "\n", + "*Note: If a character is repeated, treat each occurence as distinct, for example an input of 'xxx' would return a list with 6 \"versions\" of 'xxx'*\n", + "\n", + "\n", + "## Fill Out Your Solution Below\n", + "\n", + "Let's think about what the steps we need to take here are:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def permute(s):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['abc', 'acb', 'bac', 'bca', 'cab', 'cba']" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "permute('abc')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All test cases passed.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPerm(object):\n", + " \n", + " def test(self,solution):\n", + " \n", + " assert_equal(sorted(solution('abc')),sorted(['abc', 'acb', 'bac', 'bca', 'cab', 'cba']))\n", + " assert_equal(sorted(solution('dog')),sorted(['dog', 'dgo', 'odg', 'ogd', 'gdo', 'god']) )\n", + " \n", + " print 'All test cases passed.'\n", + " \n", + "\n", + "\n", + "# Run Tests\n", + "t = TestPerm()\n", + "t.test(permute)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Luck!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 2 - String Permutations-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 2 - String Permutations-checkpoint.ipynb new file mode 100644 index 00000000..d4218415 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 2 - String Permutations-checkpoint.ipynb @@ -0,0 +1,34 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence-checkpoint.ipynb new file mode 100644 index 00000000..514061b4 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence-checkpoint.ipynb @@ -0,0 +1,256 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Fibonnaci Sequence\n", + "\n", + "In this interview excercise we will begin to get a feel of having to solve a single problem multiple ways!\n", + "\n", + "## Problem Statement\n", + "\n", + "Implement a [Fibonnaci Sequence](https://en.wikipedia.org/wiki/Fibonacci_number) in three different ways:\n", + "\n", + "* Recursively\n", + "* Dynamically (Using Memoization to store results)\n", + "* Iteratively\n", + "___\n", + "#### Function Output\n", + "Your function will accept a number **n** and return the **nth** number of the fibonacci sequence\n", + "___\n", + "Remember that a fibonacci sequence: 0,1,1,2,3,5,8,13,21,... starts off with a base case checking to see if n = 0 or 1, then it returns 1. \n", + "\n", + "Else it returns fib(n-1)+fib(n+2).\n", + "\n", + "____\n", + "\n", + "## Fill Out Your Solutions Below" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Recursively\n", + "\n", + "Solve the problem using simple recursion." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def fib_rec(n):\n", + " if n <=2:\n", + " return int((n+1)/2)\n", + " else:\n", + " return fib_rec(n-1) + fib_rec(n-2)\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_rec(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dynamically\n", + "\n", + "Implement the function using dynamic programming by using a cache to store results (memoization)." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[None, None, None, None, None, None, None, None, None, None, None]\n" + ] + } + ], + "source": [ + "# Instantiate Cache information\n", + "n = 10\n", + "cache = [None] * (n + 1)\n", + "print(cache)\n", + "\n", + "def fib_dyn(n):\n", + " if cache[n] is not None:\n", + " return cache[n]\n", + " if n <=2:\n", + " cache[n] = int((n+1)/2)\n", + " else:\n", + " cache[n] = fib_dyn(n-1) + fib_dyn(n-2)\n", + " return cache[n]\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_dyn(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Iteratively\n", + "\n", + "Implement the solution with simple iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "def fib_iter(n):\n", + " fib_2=fib_1=1\n", + " for i in range(n-2):\n", + " fib = fib_2+fib_1\n", + " fib_2 = fib_1\n", + " fib_1 = fib\n", + " return fib_1\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "28657" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_iter(23)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solutions, simply uncomment the solution functions you wish to test!" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Passed all tests.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "UNCOMMENT THE CODE AT THE BOTTOM OF THIS CELL TO SELECT WHICH SOLUTIONS TO TEST.\n", + "THEN RUN THE CELL.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFib(object):\n", + " \n", + " def test(self,solution):\n", + " assert_equal(solution(10),55)\n", + " assert_equal(solution(1),1)\n", + " assert_equal(solution(23),28657)\n", + " print ('Passed all tests.')\n", + "# UNCOMMENT FOR CORRESPONDING FUNCTION\n", + "t = TestFib()\n", + "\n", + "t.test(fib_rec)\n", + "#t.test(fib_dyn) # Note, will need to reset cache size for each test!\n", + "#t.test(fib_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "Hopefully this interview question served as a good excercise in exploring recursion, dynamic programming, and iterative solutions for a single problem! Its good to work through all three because in an interview a common question may just begin with requesting a recursive solution and then checking to se if you can implement the other forms!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 4 - Coin Change-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 4 - Coin Change-checkpoint.ipynb new file mode 100644 index 00000000..f8785dfb --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/.ipynb_checkpoints/Recursion Problem 4 - Coin Change-checkpoint.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Coin Change Problem\n", + "\n", + "##### Note: This problem has multiple solutions and is a classic problem in showing issues with basic recursion. If you are having trouble with this problem (or it seems to be taking a long time to run in some cases) check out the Solution Notebook and fully read the conclusion link for a detailed description of the various ways to solve this problem!\n", + "\n", + "\n", + "This problem is common enough that is actually has its own [Wikipedia Entry](https://en.wikipedia.org/wiki/Change-making_problem)! \n", + "\n", + "____\n", + "## Problem Statement\n", + "Given a target amount **n** and a list (array) of distinct coin values, what's the fewest coins needed to make the change amount. \n", + "\n", + "For example:\n", + "\n", + "If n = 10 and coins = [1,5,10]. Then there are 4 possible ways to make change:\n", + "\n", + "* 1+1+1+1+1+1+1+1+1+1\n", + "\n", + "* 5 + 1+1+1+1+1\n", + "\n", + "* 5+5\n", + "\n", + "* 10\n", + "\n", + "With 1 coin being the minimum amount.\n", + "\n", + " \n", + "## Solution\n", + "\n", + "Implement your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rec_coin(target,coins):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_coin(10,[1,5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your function against some test cases. \n", + "\n", + "**Note that the TestCoins class only test functions with two parameter inputs, the list of coins and the target**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR FUNCTION.\n", + "NOTE: NON-DYNAMIC FUNCTIONS WILL TAKE A LONG TIME TO TEST. IF YOU BELIEVE YOU HAVE A SOLUTION \n", + " GO CHECK THE SOLUTION NOTEBOOK INSTEAD OF RUNNING THIS!\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCoins(object):\n", + " \n", + " def check(self,solution):\n", + " coins = [1,5,10,25]\n", + " assert_equal(solution(45,coins),3)\n", + " assert_equal(solution(23,coins),5)\n", + " assert_equal(solution(74,coins),8)\n", + " print 'Passed all tests.'\n", + "# Run Test\n", + "\n", + "test = TestCoins()\n", + "test.check(rec_coin)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## EXTRA\n", + "\n", + "Good luck and remember to read the solution notebook for this once you've think you have a solution!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 1 - Reverse String .ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 1 - Reverse String .ipynb new file mode 100644 index 00000000..b645222c --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 1 - Reverse String .ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reverse a String\n", + "\n", + "This interview question requires you to reverse a string using recursion. Make sure to think of the base case here.\n", + "\n", + "Again, make sure you use *recursion* to accomplish this. **Do not slice (e.g. string[::-1]) or use iteration, there must be a recursive call for the function.**\n", + "\n", + "____\n", + "\n", + "### Fill out your solution below" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def reverse(s):\n", + " if(len(s)<=1):\n", + " return s\n", + " else:\n", + " m = int(len(s)/2)\n", + " return reverse(s[m:]) + (reverse((s[:m])))\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'dlrow olleh'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse('hello world')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solution against the following cases:\n", + "\n", + " string = 'hello'\n", + " string = 'hello world'\n", + " string = '123456789'" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASSED ALL TEST CASES!\n" + ] + } + ], + "source": [ + "'''\n", + "RUN THIS CELL TO TEST YOUR FUNCTION AGAINST SOME TEST CASES\n", + "'''\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestReverse(object):\n", + " \n", + " def test_rev(self,solution):\n", + " assert_equal(solution('hello'),'olleh')\n", + " assert_equal(solution('hello world'),'dlrow olleh')\n", + " assert_equal(solution('123456789'),'987654321')\n", + " \n", + " print ('PASSED ALL TEST CASES!')\n", + " \n", + "# Run Tests\n", + "test = TestReverse()\n", + "test.test_rev(reverse)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Good Luck!**" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 2 - String Permutation.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 2 - String Permutation.ipynb new file mode 100644 index 00000000..a69fc179 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 2 - String Permutation.ipynb @@ -0,0 +1,136 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# String Permutation\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string, write a function that uses recursion to output a list of all the possible permutations of that string.\n", + "\n", + "For example, given s='abc' the function should return ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']\n", + "\n", + "*Note: If a character is repeated, treat each occurence as distinct, for example an input of 'xxx' would return a list with 6 \"versions\" of 'xxx'*\n", + "\n", + "\n", + "## Fill Out Your Solution Below\n", + "\n", + "Let's think about what the steps we need to take here are:" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [], + "source": [ + "def permute(s):\n", + " output = []\n", + " \n", + " if len(s) <= 1:\n", + " output=[s]\n", + " else:\n", + " for i, let in enumerate(s):\n", + " for perm in permute(s[:i]+s[i+1:]):\n", + " output+=[let+perm]\n", + " return output" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['abc', 'acb', 'bac', 'bca', 'cab', 'cba']" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "permute('abc')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All test cases passed.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPerm(object):\n", + " \n", + " def test(self,solution):\n", + " \n", + " assert_equal(sorted(solution('abc')),sorted(['abc', 'acb', 'bac', 'bca', 'cab', 'cba']))\n", + " assert_equal(sorted(solution('dog')),sorted(['dog', 'dgo', 'odg', 'ogd', 'gdo', 'god']) )\n", + " \n", + " print ('All test cases passed.')\n", + " \n", + "\n", + "\n", + "# Run Tests\n", + "t = TestPerm()\n", + "t.test(permute)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Luck!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 3 - Fibonacci Sequence.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 3 - Fibonacci Sequence.ipynb new file mode 100644 index 00000000..81c56493 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 3 - Fibonacci Sequence.ipynb @@ -0,0 +1,258 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Fibonnaci Sequence\n", + "\n", + "In this interview excercise we will begin to get a feel of having to solve a single problem multiple ways!\n", + "\n", + "## Problem Statement\n", + "\n", + "Implement a [Fibonnaci Sequence](https://en.wikipedia.org/wiki/Fibonacci_number) in three different ways:\n", + "\n", + "* Recursively\n", + "* Dynamically (Using Memoization to store results)\n", + "* Iteratively\n", + "___\n", + "#### Function Output\n", + "Your function will accept a number **n** and return the **nth** number of the fibonacci sequence\n", + "___\n", + "Remember that a fibonacci sequence: 0,1,1,2,3,5,8,13,21,... starts off with a base case checking to see if n = 0 or 1, then it returns 1. \n", + "\n", + "Else it returns fib(n-1)+fib(n+2).\n", + "\n", + "____\n", + "\n", + "## Fill Out Your Solutions Below" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Recursively\n", + "\n", + "Solve the problem using simple recursion." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def fib_rec(n):\n", + " if n <=2:\n", + " return int((n+1)/2)\n", + " else:\n", + " return fib_rec(n-1) + fib_rec(n-2)\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_rec(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dynamically\n", + "\n", + "Implement the function using dynamic programming by using a cache to store results (memoization)." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[None, None, None, None, None, None, None, None, None, None, None]\n" + ] + } + ], + "source": [ + "# Instantiate Cache information\n", + "n = 10\n", + "cache = [None] * (n + 1)\n", + "print(cache)\n", + "\n", + "def fib_dyn(n):\n", + " if cache[n] is not None:\n", + " return cache[n]\n", + " if n <=2:\n", + " cache[n] = int((n+1)/2)\n", + " else:\n", + " cache[n] = fib_dyn(n-1) + fib_dyn(n-2)\n", + " return cache[n]\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_dyn(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Iteratively\n", + "\n", + "Implement the solution with simple iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "def fib_iter(n):\n", + " \n", + " # Set starting point\n", + " a = 0\n", + " b = 1\n", + " \n", + " # Follow algorithm\n", + " for i in range(n):\n", + " a, b = b, a + b\n", + " return a" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "28657" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_iter(23)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solutions, simply uncomment the solution functions you wish to test!" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Passed all tests.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "UNCOMMENT THE CODE AT THE BOTTOM OF THIS CELL TO SELECT WHICH SOLUTIONS TO TEST.\n", + "THEN RUN THE CELL.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFib(object):\n", + " \n", + " def test(self,solution):\n", + " assert_equal(solution(10),55)\n", + " assert_equal(solution(1),1)\n", + " assert_equal(solution(23),28657)\n", + " print ('Passed all tests.')\n", + "# UNCOMMENT FOR CORRESPONDING FUNCTION\n", + "t = TestFib()\n", + "\n", + "t.test(fib_rec)\n", + "#t.test(fib_dyn) # Note, will need to reset cache size for each test!\n", + "#t.test(fib_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "Hopefully this interview question served as a good excercise in exploring recursion, dynamic programming, and iterative solutions for a single problem! Its good to work through all three because in an interview a common question may just begin with requesting a recursive solution and then checking to se if you can implement the other forms!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 4 - Coin Change.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 4 - Coin Change.ipynb new file mode 100644 index 00000000..68a6dcae --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems - PRACTICE/Recursion Problem 4 - Coin Change.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Coin Change Problem\n", + "\n", + "##### Note: This problem has multiple solutions and is a classic problem in showing issues with basic recursion. If you are having trouble with this problem (or it seems to be taking a long time to run in some cases) check out the Solution Notebook and fully read the conclusion link for a detailed description of the various ways to solve this problem!\n", + "\n", + "\n", + "This problem is common enough that is actually has its own [Wikipedia Entry](https://en.wikipedia.org/wiki/Change-making_problem)! \n", + "\n", + "____\n", + "## Problem Statement\n", + "Given a target amount **n** and a list (array) of distinct coin values, what's the fewest coins needed to make the change amount. \n", + "\n", + "For example:\n", + "\n", + "If n = 10 and coins = [1,5,10]. Then there are 4 possible ways to make change:\n", + "\n", + "* 1+1+1+1+1+1+1+1+1+1\n", + "\n", + "* 5 + 1+1+1+1+1\n", + "\n", + "* 5+5\n", + "\n", + "* 10\n", + "\n", + "With 1 coin being the minimum amount.\n", + "\n", + " \n", + "## Solution\n", + "\n", + "Implement your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "def rec_coin(target,coins):\n", + " min_coins = target\n", + " \n", + " if target in coins:\n", + " return 1\n", + " else:\n", + " for value in [ c for c in coins if c<= target]:\n", + " num_coins = rec_coin(target-value, coins) + 1\n", + " min_coins = min(num_coins, min_coins)\n", + " return min_coins\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_coin(10,[1,5]) #2" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_coin(63,[1,5,10,25])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your function against some test cases. \n", + "\n", + "**Note that the TestCoins class only test functions with two parameter inputs, the list of coins and the target**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR FUNCTION.\n", + "NOTE: NON-DYNAMIC FUNCTIONS WILL TAKE A LONG TIME TO TEST. IF YOU BELIEVE YOU HAVE A SOLUTION \n", + " GO CHECK THE SOLUTION NOTEBOOK INSTEAD OF RUNNING THIS!\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCoins(object):\n", + " \n", + " def check(self,solution):\n", + " coins = [1,5,10,25]\n", + " assert_equal(solution(45,coins),3)\n", + " assert_equal(solution(23,coins),5)\n", + " assert_equal(solution(74,coins),8)\n", + " print ('Passed all tests.')\n", + "# Run Test\n", + "\n", + "test = TestCoins()\n", + "test.check(rec_coin)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## EXTRA\n", + "\n", + "Good luck and remember to read the solution notebook for this once you've think you have a solution!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 1 - Reverse String -checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 1 - Reverse String -checkpoint.ipynb new file mode 100644 index 00000000..4d4308f6 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 1 - Reverse String -checkpoint.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reverse a String\n", + "\n", + "This interview question requires you to reverse a string using recursion. Make sure to think of the base case here.\n", + "\n", + "Again, make sure you use *recursion* to accomplish this. **Do not slice (e.g. string[::-1]) or use iteration, there must be a recursive call for the function.**\n", + "\n", + "____\n", + "\n", + "### Fill out your solution below" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def reverse(s):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'dlrow olleh'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse('hello world')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solution against the following cases:\n", + "\n", + " string = 'hello'\n", + " string = 'hello world'\n", + " string = '123456789'" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASSED ALL TEST CASES!\n" + ] + } + ], + "source": [ + "'''\n", + "RUN THIS CELL TO TEST YOUR FUNCTION AGAINST SOME TEST CASES\n", + "'''\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestReverse(object):\n", + " \n", + " def test_rev(self,solution):\n", + " assert_equal(solution('hello'),'olleh')\n", + " assert_equal(solution('hello world'),'dlrow olleh')\n", + " assert_equal(solution('123456789'),'987654321')\n", + " \n", + " print 'PASSED ALL TEST CASES!'\n", + " \n", + "# Run Tests\n", + "test = TestReverse()\n", + "test.test_rev(reverse)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Good Luck!**" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 2 - String Permutation-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 2 - String Permutation-checkpoint.ipynb new file mode 100644 index 00000000..e2585c12 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 2 - String Permutation-checkpoint.ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# String Permutation\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string, write a function that uses recursion to output a list of all the possible permutations of that string.\n", + "\n", + "For example, given s='abc' the function should return ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']\n", + "\n", + "*Note: If a character is repeated, treat each occurence as distinct, for example an input of 'xxx' would return a list with 6 \"versions\" of 'xxx'*\n", + "\n", + "\n", + "## Fill Out Your Solution Below\n", + "\n", + "Let's think about what the steps we need to take here are:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def permute(s):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['abc', 'acb', 'bac', 'bca', 'cab', 'cba']" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "permute('abc')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All test cases passed.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPerm(object):\n", + " \n", + " def test(self,solution):\n", + " \n", + " assert_equal(sorted(solution('abc')),sorted(['abc', 'acb', 'bac', 'bca', 'cab', 'cba']))\n", + " assert_equal(sorted(solution('dog')),sorted(['dog', 'dgo', 'odg', 'ogd', 'gdo', 'god']) )\n", + " \n", + " print 'All test cases passed.'\n", + " \n", + "\n", + "\n", + "# Run Tests\n", + "t = TestPerm()\n", + "t.test(permute)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Luck!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 2 - String Permutations-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 2 - String Permutations-checkpoint.ipynb new file mode 100644 index 00000000..d4218415 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 2 - String Permutations-checkpoint.ipynb @@ -0,0 +1,34 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence-checkpoint.ipynb new file mode 100644 index 00000000..e85c24d0 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 3 - Fibonacci Sequence-checkpoint.ipynb @@ -0,0 +1,248 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Fibonnaci Sequence\n", + "\n", + "In this interview excercise we will begin to get a feel of having to solve a single problem multiple ways!\n", + "\n", + "## Problem Statement\n", + "\n", + "Implement a [Fibonnaci Sequence](https://en.wikipedia.org/wiki/Fibonacci_number) in three different ways:\n", + "\n", + "* Recursively\n", + "* Dynamically (Using Memoization to store results)\n", + "* Iteratively\n", + "___\n", + "#### Function Output\n", + "Your function will accept a number **n** and return the **nth** number of the fibonacci sequence\n", + "___\n", + "Remember that a fibonacci sequence: 0,1,1,2,3,5,8,13,21,... starts off with a base case checking to see if n = 0 or 1, then it returns 1. \n", + "\n", + "Else it returns fib(n-1)+fib(n+2).\n", + "\n", + "____\n", + "\n", + "## Fill Out Your Solutions Below" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Recursively\n", + "\n", + "Solve the problem using simple recursion." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def fib_rec(n):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_rec(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dynamically\n", + "\n", + "Implement the function using dynamic programming by using a cache to store results (memoization)." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Instantiate Cache information\n", + "n = 10\n", + "cache = [None] * (n + 1)\n", + "\n", + "\n", + "def fib_dyn(n):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_dyn(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Iteratively\n", + "\n", + "Implement the solution with simple iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def fib_iter(n):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "28657" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_iter(23)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solutions, simply uncomment the solution functions you wish to test!" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Passed all tests.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "UNCOMMENT THE CODE AT THE BOTTOM OF THIS CELL TO SELECT WHICH SOLUTIONS TO TEST.\n", + "THEN RUN THE CELL.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFib(object):\n", + " \n", + " def test(self,solution):\n", + " assert_equal(solution(10),55)\n", + " assert_equal(solution(1),1)\n", + " assert_equal(solution(23),28657)\n", + " print 'Passed all tests.'\n", + "# UNCOMMENT FOR CORRESPONDING FUNCTION\n", + "t = TestFib()\n", + "\n", + "t.test(fib_rec)\n", + "#t.test(fib_dyn) # Note, will need to reset cache size for each test!\n", + "#t.test(fib_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "Hopefully this interview question served as a good excercise in exploring recursion, dynamic programming, and iterative solutions for a single problem! Its good to work through all three because in an interview a common question may just begin with requesting a recursive solution and then checking to se if you can implement the other forms!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 4 - Coin Change-checkpoint.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 4 - Coin Change-checkpoint.ipynb new file mode 100644 index 00000000..f8785dfb --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems/.ipynb_checkpoints/Recursion Problem 4 - Coin Change-checkpoint.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Coin Change Problem\n", + "\n", + "##### Note: This problem has multiple solutions and is a classic problem in showing issues with basic recursion. If you are having trouble with this problem (or it seems to be taking a long time to run in some cases) check out the Solution Notebook and fully read the conclusion link for a detailed description of the various ways to solve this problem!\n", + "\n", + "\n", + "This problem is common enough that is actually has its own [Wikipedia Entry](https://en.wikipedia.org/wiki/Change-making_problem)! \n", + "\n", + "____\n", + "## Problem Statement\n", + "Given a target amount **n** and a list (array) of distinct coin values, what's the fewest coins needed to make the change amount. \n", + "\n", + "For example:\n", + "\n", + "If n = 10 and coins = [1,5,10]. Then there are 4 possible ways to make change:\n", + "\n", + "* 1+1+1+1+1+1+1+1+1+1\n", + "\n", + "* 5 + 1+1+1+1+1\n", + "\n", + "* 5+5\n", + "\n", + "* 10\n", + "\n", + "With 1 coin being the minimum amount.\n", + "\n", + " \n", + "## Solution\n", + "\n", + "Implement your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rec_coin(target,coins):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_coin(10,[1,5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your function against some test cases. \n", + "\n", + "**Note that the TestCoins class only test functions with two parameter inputs, the list of coins and the target**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR FUNCTION.\n", + "NOTE: NON-DYNAMIC FUNCTIONS WILL TAKE A LONG TIME TO TEST. IF YOU BELIEVE YOU HAVE A SOLUTION \n", + " GO CHECK THE SOLUTION NOTEBOOK INSTEAD OF RUNNING THIS!\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCoins(object):\n", + " \n", + " def check(self,solution):\n", + " coins = [1,5,10,25]\n", + " assert_equal(solution(45,coins),3)\n", + " assert_equal(solution(23,coins),5)\n", + " assert_equal(solution(74,coins),8)\n", + " print 'Passed all tests.'\n", + "# Run Test\n", + "\n", + "test = TestCoins()\n", + "test.check(rec_coin)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## EXTRA\n", + "\n", + "Good luck and remember to read the solution notebook for this once you've think you have a solution!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 1 - Reverse String .ipynb b/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 1 - Reverse String .ipynb new file mode 100644 index 00000000..4d4308f6 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 1 - Reverse String .ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reverse a String\n", + "\n", + "This interview question requires you to reverse a string using recursion. Make sure to think of the base case here.\n", + "\n", + "Again, make sure you use *recursion* to accomplish this. **Do not slice (e.g. string[::-1]) or use iteration, there must be a recursive call for the function.**\n", + "\n", + "____\n", + "\n", + "### Fill out your solution below" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def reverse(s):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'dlrow olleh'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reverse('hello world')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solution against the following cases:\n", + "\n", + " string = 'hello'\n", + " string = 'hello world'\n", + " string = '123456789'" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PASSED ALL TEST CASES!\n" + ] + } + ], + "source": [ + "'''\n", + "RUN THIS CELL TO TEST YOUR FUNCTION AGAINST SOME TEST CASES\n", + "'''\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestReverse(object):\n", + " \n", + " def test_rev(self,solution):\n", + " assert_equal(solution('hello'),'olleh')\n", + " assert_equal(solution('hello world'),'dlrow olleh')\n", + " assert_equal(solution('123456789'),'987654321')\n", + " \n", + " print 'PASSED ALL TEST CASES!'\n", + " \n", + "# Run Tests\n", + "test = TestReverse()\n", + "test.test_rev(reverse)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Good Luck!**" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 2 - String Permutation.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 2 - String Permutation.ipynb new file mode 100644 index 00000000..e2585c12 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 2 - String Permutation.ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# String Permutation\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string, write a function that uses recursion to output a list of all the possible permutations of that string.\n", + "\n", + "For example, given s='abc' the function should return ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']\n", + "\n", + "*Note: If a character is repeated, treat each occurence as distinct, for example an input of 'xxx' would return a list with 6 \"versions\" of 'xxx'*\n", + "\n", + "\n", + "## Fill Out Your Solution Below\n", + "\n", + "Let's think about what the steps we need to take here are:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def permute(s):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['abc', 'acb', 'bac', 'bca', 'cab', 'cba']" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "permute('abc')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All test cases passed.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestPerm(object):\n", + " \n", + " def test(self,solution):\n", + " \n", + " assert_equal(sorted(solution('abc')),sorted(['abc', 'acb', 'bac', 'bca', 'cab', 'cba']))\n", + " assert_equal(sorted(solution('dog')),sorted(['dog', 'dgo', 'odg', 'ogd', 'gdo', 'god']) )\n", + " \n", + " print 'All test cases passed.'\n", + " \n", + "\n", + "\n", + "# Run Tests\n", + "t = TestPerm()\n", + "t.test(permute)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Luck!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 3 - Fibonacci Sequence.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 3 - Fibonacci Sequence.ipynb new file mode 100644 index 00000000..e85c24d0 --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 3 - Fibonacci Sequence.ipynb @@ -0,0 +1,248 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Fibonnaci Sequence\n", + "\n", + "In this interview excercise we will begin to get a feel of having to solve a single problem multiple ways!\n", + "\n", + "## Problem Statement\n", + "\n", + "Implement a [Fibonnaci Sequence](https://en.wikipedia.org/wiki/Fibonacci_number) in three different ways:\n", + "\n", + "* Recursively\n", + "* Dynamically (Using Memoization to store results)\n", + "* Iteratively\n", + "___\n", + "#### Function Output\n", + "Your function will accept a number **n** and return the **nth** number of the fibonacci sequence\n", + "___\n", + "Remember that a fibonacci sequence: 0,1,1,2,3,5,8,13,21,... starts off with a base case checking to see if n = 0 or 1, then it returns 1. \n", + "\n", + "Else it returns fib(n-1)+fib(n+2).\n", + "\n", + "____\n", + "\n", + "## Fill Out Your Solutions Below" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Recursively\n", + "\n", + "Solve the problem using simple recursion." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def fib_rec(n):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_rec(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dynamically\n", + "\n", + "Implement the function using dynamic programming by using a cache to store results (memoization)." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Instantiate Cache information\n", + "n = 10\n", + "cache = [None] * (n + 1)\n", + "\n", + "\n", + "def fib_dyn(n):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "55" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_dyn(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Iteratively\n", + "\n", + "Implement the solution with simple iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def fib_iter(n):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "28657" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fib_iter(23)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your solutions, simply uncomment the solution functions you wish to test!" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Passed all tests.\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "UNCOMMENT THE CODE AT THE BOTTOM OF THIS CELL TO SELECT WHICH SOLUTIONS TO TEST.\n", + "THEN RUN THE CELL.\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestFib(object):\n", + " \n", + " def test(self,solution):\n", + " assert_equal(solution(10),55)\n", + " assert_equal(solution(1),1)\n", + " assert_equal(solution(23),28657)\n", + " print 'Passed all tests.'\n", + "# UNCOMMENT FOR CORRESPONDING FUNCTION\n", + "t = TestFib()\n", + "\n", + "t.test(fib_rec)\n", + "#t.test(fib_dyn) # Note, will need to reset cache size for each test!\n", + "#t.test(fib_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "Hopefully this interview question served as a good excercise in exploring recursion, dynamic programming, and iterative solutions for a single problem! Its good to work through all three because in an interview a common question may just begin with requesting a recursive solution and then checking to se if you can implement the other forms!" + ] + } + ], + "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 +} diff --git a/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 4 - Coin Change.ipynb b/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 4 - Coin Change.ipynb new file mode 100644 index 00000000..f8785dfb --- /dev/null +++ b/Recursion/Recursion Interview Problems/Recursion Problems/Recursion Problem 4 - Coin Change.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Coin Change Problem\n", + "\n", + "##### Note: This problem has multiple solutions and is a classic problem in showing issues with basic recursion. If you are having trouble with this problem (or it seems to be taking a long time to run in some cases) check out the Solution Notebook and fully read the conclusion link for a detailed description of the various ways to solve this problem!\n", + "\n", + "\n", + "This problem is common enough that is actually has its own [Wikipedia Entry](https://en.wikipedia.org/wiki/Change-making_problem)! \n", + "\n", + "____\n", + "## Problem Statement\n", + "Given a target amount **n** and a list (array) of distinct coin values, what's the fewest coins needed to make the change amount. \n", + "\n", + "For example:\n", + "\n", + "If n = 10 and coins = [1,5,10]. Then there are 4 possible ways to make change:\n", + "\n", + "* 1+1+1+1+1+1+1+1+1+1\n", + "\n", + "* 5 + 1+1+1+1+1\n", + "\n", + "* 5+5\n", + "\n", + "* 10\n", + "\n", + "With 1 coin being the minimum amount.\n", + "\n", + " \n", + "## Solution\n", + "\n", + "Implement your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rec_coin(target,coins):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rec_coin(10,[1,5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "Run the cell below to test your function against some test cases. \n", + "\n", + "**Note that the TestCoins class only test functions with two parameter inputs, the list of coins and the target**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR FUNCTION.\n", + "NOTE: NON-DYNAMIC FUNCTIONS WILL TAKE A LONG TIME TO TEST. IF YOU BELIEVE YOU HAVE A SOLUTION \n", + " GO CHECK THE SOLUTION NOTEBOOK INSTEAD OF RUNNING THIS!\n", + "\"\"\"\n", + "\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestCoins(object):\n", + " \n", + " def check(self,solution):\n", + " coins = [1,5,10,25]\n", + " assert_equal(solution(45,coins),3)\n", + " assert_equal(solution(23,coins),5)\n", + " assert_equal(solution(74,coins),8)\n", + " print 'Passed all tests.'\n", + "# Run Test\n", + "\n", + "test = TestCoins()\n", + "test.check(rec_coin)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## EXTRA\n", + "\n", + "Good luck and remember to read the solution notebook for this once you've think you have a solution!" + ] + } + ], + "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 +} diff --git a/Reflect Notes.ipynb b/Reflect Notes.ipynb new file mode 100644 index 00000000..9f226948 --- /dev/null +++ b/Reflect Notes.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Array\n", + "- Python use reference when slide or extend an array. (Because python uses immutable value for integers and strings)\n", + "## Dynamic Array Implementation\n", + "- The array has an initial size and will expand twice when extending.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\" \".join()\n", + "reversed()\n", + "s.split()\n", + "len(set(s))" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Riddles/.ipynb_checkpoints/How to Approach Riddles-checkpoint.ipynb b/Riddles/.ipynb_checkpoints/How to Approach Riddles-checkpoint.ipynb new file mode 100644 index 00000000..6d3eb2cd --- /dev/null +++ b/Riddles/.ipynb_checkpoints/How to Approach Riddles-checkpoint.ipynb @@ -0,0 +1,34 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How to Approach Riddles\n", + "\n", + "Please view the video lecture for full explanation on this topic!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/How to Approach Riddles.ipynb b/Riddles/How to Approach Riddles.ipynb new file mode 100644 index 00000000..6d3eb2cd --- /dev/null +++ b/Riddles/How to Approach Riddles.ipynb @@ -0,0 +1,34 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How to Approach Riddles\n", + "\n", + "Please view the video lecture for full explanation on this topic!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Bridge Crossing - SOLUTION-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Bridge Crossing - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..6932931a --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Bridge Crossing - SOLUTION-checkpoint.ipynb @@ -0,0 +1,66 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bridge Crossing - SOLUTION" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem Statement\n", + "\n", + "A group of four travelers comes to a bridge at night. The bridge can hold the weight of at most only two of the travelers at a time, and it can- not be crossed without using a flashlight. \n", + "\n", + "The travelers have one flashlight among them. Each traveler walks at a different speed: The first can cross the bridge in 1 minute, the second in 2 minutes, the third in 5 minutes, and the fourth takes 10 minutes to cross the bridge. If two travelers cross together, they walk at the speed of the slower traveler.\n", + "\n", + "What is the least amount of time in which all the travelers can cross from one side of the bridge to the other?\n", + "\n", + "## Solution\n", + "\n", + "This is part of a common group of [river crossing](https://en.wikipedia.org/wiki/River_crossing_puzzle) puzzles. Its know as the [Bridge and Torch problem](https://en.wikipedia.org/wiki/Bridge_and_torch_problem) (sometimes the times assigned to each person are different).\n", + "\n", + "The solution to this version is:\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
MoveTime
(1) & (2) Cross with Torch2
(1) Returns with Torch1
(5) & (10) Cross with Torch10
(2) Returns with Torch2
(1) & (2) Cross with Torch2
 17
" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Coins and a Scale - SOLUTION-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Coins and a Scale - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..dd6ce0ad --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Coins and a Scale - SOLUTION-checkpoint.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Coins and a Scale - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You have eight coins and a two-pan scale. All the coins weigh the same, **except for one** which is heavier than all the others. The coins are otherwise indistinguishable. You may make no assumptions about how much heavier the heavy coin is. What is the minimum number of weighings needed to be certain of identifying the heavy coin?\n", + "\n", + "## Solution\n", + "\n", + "Begin by dividing the coins into two groups of three, which you put on the scale, and one group of two, which you leave off. If the two sides weigh the same, the heavy coin is in the group of two, and you can find it with one more weighing, for a total of two weighings. On the other hand, if either side of the scale is heavier, the heavy coin must be in that group of three. You can eliminate all the other coins, and place one coin from this group on either side of the scale, leaving the third coin aside. If one side is heavier, it contains the heavy coin; if neither side is heavier, the heavy coin is the one you didn’t place on the scale. This is also a total of two weighings, so you can always find the heavy coin in a group of eight using two weighings." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Egg Drop - SOLUTION-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Egg Drop - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..3a39349e --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Egg Drop - SOLUTION-checkpoint.ipynb @@ -0,0 +1,73 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Egg Drop - SOLUTION\n", + "This is probably the most common brain teaser riddle out of the group, so really try to think algorithmically about this problem before looking at the solution!\n", + "\n", + "## Problem Statement\n", + "\n", + "A tower has 100 floors. You've been given two eggs. The eggs are strong enough that they can be dropped from a particular floor in the tower without breaking. You've been tasked to find the highest floor an egg can be dropped without breaking, in as few drops as possible. If an egg is dropped from above its target floor it will break. If it is dropped from that floor or below, it will be intact and you can test drop the egg again on another floor.\n", + "\n", + "Show algorithmically how you would go about doing this in as few drops as possible. (Your answer should be a number of the fewest drops needed for testing 2 eggs on 100 floors)\n", + "## Solution\n", + "\n", + "Start from the 10th floor and go up to floors in multiples of 10.\n", + "\n", + "If first egg breaks, say at 20th floor then you can check all the floors between 11th and 19th with the second egg to see which floor it will not break.\n", + "\n", + "In this case, the worst-case number of drops is 19. If the threshold was 99th floor, then you would have to drop the first egg 10 times and the second egg 9 times in linear fashion.\n", + "\n", + "**Best solution:**\n", + "We need to minimize this worst-case number of drops. For that, we need to generalize the problem to have n floors. What would be the step value, for the first egg? Would it still be 10? Suppose we have 200 floors. Would the step value be still 10? \n", + "\n", + "The point to note here is that we are trying to minimize the worst-case number of drops which happens if the threshold is at the highest floors. So, our steps should be of some value which reduces the number of drops of the first egg.\n", + "\n", + "Let's assume we take some step value m initially. If every subsequent step is m-1,\n", + "then, \n", + "$$m+m−1+m−2+.....+1=n$$\n", + "\n", + "This is \n", + "\n", + "$$\\frac{m∗(m+1)}{2}=n$$\n", + "\n", + "If n =100, then m would be 13.65 which since we can't drop from a decimal of a floor, we actually use 14.\n", + "\n", + "So, the worst case scenario is now when the threshold is in the first 14 floors with number of drops being 14.\n", + "\n", + "Note that this is simply a binary search!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___\n", + "You can find plenty of other explanations by simply googling \"2 eggs 100 floors\"" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Hallway Lockers -SOLUTION-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Hallway Lockers -SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..3e7b54f7 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Hallway Lockers -SOLUTION-checkpoint.ipynb @@ -0,0 +1,63 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Hallway Lockers - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You are in a hallway lined with 100 lockers. You start with one pass and open the lockers, so that the *opened* lockers are now with their doors opened out. You begin by closing **every second** locker. Then you go to close **every third** locker and **close it if it is open or open it if it’s closed** — we will refer to this as \"toggling\" the lockers. You continue toggling every nth locker on pass number n. After your hundredth pass of the hallway, in which you toggle only locker number 100, how many lockers are open?\n", + "\n", + "## Solution\n", + "\n", + "Obviously you can't just brute force and count out this problem, there are just too many passes, so we will need to think about this algorithmically.\n", + "\n", + "Let's begin solving this problem by choosing an arbitrary locker and see if we can detect a pattern. Let's choose locker 12, it has been toggled open on your first pass.\n", + "\n", + "To start off we know we won't have to toggle it on any pass greater than 12. So now we only have to think of the passes that occur on 2-11. We can actualy count these out:\n", + "\n", + "* On pass 2: 2,4,6,8,10,12\n", + "* On pass 3: 3,6,9,12\n", + "* On pass 4: 4,8,12\n", + "* On pass 5: 5,10 **No toggle on this pass**\n", + "* On pass 6: 6,12\n", + "* On pass 7: 7,14 **No toggle on this pass**\n", + "* ect...\n", + "\n", + "You'll notice the pattern that emerges, we only toggle the locker when the pass number is a factor of the locker number. We can begin to make the generalization that all lockers started open after the first pass and alternate between being open and closed. So lockers are closed after the second, fourth, sixth, and so on, times they are toggled — in other words, if a locker is toggled an even number of times, then it ends closed; otherwise, it ends open. You know that a locker is toggled once for every factor of the locker number, so you can say that a locker ends open only if it has an odd number of factors.\n", + "\n", + "**The task has now been reduced to finding how many numbers between 1 and 100 have an odd number of factors!**\n", + "____\n", + "\n", + "We can think about this in the following manner:\n", + "\n", + "If a number **i** is a factor of **n**, what does that mean? It means that **i** times some other number **j** is equal to n. Because multiplication is commutative (i × j = j × i), that means that j is a factor of n, too, so the number of factors is usually even because factors tend to come in pairs. If you can find the numbers that have unpaired factors, you will know which lockers will be open. Multiplication is a binary operation, so two numbers will always be involved, but what if they are both the same number (that is, i = j)? In that case, a single number would effectively form both halves of the pair, and there would be an odd number of factors. When this is the case, i × i = n. Therefore, n must be a perfect square. Try a perfect square to check this solution. For example,\n", + "for 16, the factors are 1, 2, 4, 8, 16; operations are open, close, open, close, open — as expected, it ends open.\n", + "\n", + "Based on this reasoning, you can conclude that only lockers with numbers that are perfect squares end up open. The perfect squares between 1 and 100 (inclusive) are 1, 4, 9, 16, 25, 36, 49, 64, 81, and 100. So 10 lockers would remain open." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Jugs of Water - SOLUTION-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Jugs of Water - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..6bad4853 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Jugs of Water - SOLUTION-checkpoint.ipynb @@ -0,0 +1,113 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Jugs of Water - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You have a five gallons jug and a three gallons jug, and an unlimited supply of water (but no measuring cups) How would you come up with exactly four gallons of water?\n", + "\n", + "## Solution\n", + "\n", + "This problem has a cameo in the movie Die Hard 3. The solution is below:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "Image(url='http://mindyourdecisions.com/blog/wp-content/uploads/2013/02/water-jug-riddle-1.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hopefully your interviews are not as stressful as this:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo('BVtQNK_ZUJg')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Yippee Ki Yay" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Light Switches - SOLUTION-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Light Switches - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..f06d5f7d --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Light Switches - SOLUTION-checkpoint.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Light Switches - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You are in a hallway next to three light switches, all of which are off. Each switch activates a different *incandescent* light bulb in the room at the end of the hall. You cannot see the lights from where the switches are. Your task is to determine which light corresponds to each switch. However, you may go into the room with the lights only once.\n", + "\n", + "**Note: This is a \"trick\" question, so don't spend too much time on it. Although it is more on the \"fun\" side of brain teaser type questions.**\n", + "\n", + "## Solution\n", + "\n", + "This is a bit of a trick question and hopefully you don't get asked this type of question in an interview, since its not really math or logic based. The solution is to realize that you can leave an *incandescent* light bulb on for awhile until it heats up. \n", + "\n", + "So the solution is to turn on switch 1 and wait for 15 minutes until that corrresponding bulb is hot. Then turn it off and turn on switch 2 then head to the room. Then you know that:\n", + "\n", + "* The bulb which is hot corresponds to switch 1\n", + "* The bulb which is on corresponds to switch 2\n", + "* The bulb which is off corresponds to switch 3" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Ropes Burning - SOLUTION-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Ropes Burning - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..a4473f76 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/.ipynb_checkpoints/Ropes Burning - SOLUTION-checkpoint.ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Ropes Burning - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You have two ropes. Each takes exactly 60 minutes to burn.\n", + "\n", + "They are made of different material so even though they take the same amount of time to burn, they burn at separate rates. In addition, each rope burns inconsistently.\n", + "\n", + "How do you measure out exactly 45 minutes?\n", + "\n", + "## Solution\n", + "\n", + "Take one rope and burn it at both ends.\n", + "\n", + "At the same time, burn one end of the other rope.\n", + "\n", + "When the first rope finishes burning, light the other end of the remaining rope.\n", + "\n", + "When it burns out, that's 45 minutes." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Bridge Crossing - SOLUTION.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Bridge Crossing - SOLUTION.ipynb new file mode 100644 index 00000000..1a330257 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Bridge Crossing - SOLUTION.ipynb @@ -0,0 +1,66 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bridge Crossing - SOLUTION" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem Statement\n", + "\n", + "A group of four travelers comes to a bridge at night. The bridge can hold the weight of at most only two of the travelers at a time, and it can- not be crossed without using a flashlight. \n", + "\n", + "The travelers have one flashlight among them. Each traveler walks at a different speed: The first can cross the bridge in 1 minute, the second in 2 minutes, the third in 5 minutes, and the fourth takes 10 minutes to cross the bridge. If two travelers cross together, they walk at the speed of the slower traveler.\n", + "\n", + "What is the least amount of time in which all the travelers can cross from one side of the bridge to the other?\n", + "\n", + "## Solution\n", + "\n", + "This is part of a common group of [river crossing](https://en.wikipedia.org/wiki/River_crossing_puzzle) puzzles. Its know as the [Bridge and Torch problem](https://en.wikipedia.org/wiki/Bridge_and_torch_problem) (sometimes the times assigned to each person are different).\n", + "\n", + "The solution to this version is:\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
MoveTime
(1) & (2) Cross with Torch2
(1) Returns with Torch1
(5) & (10) Cross with Torch10
(2) Returns with Torch2
(1) & (2) Cross with Torch2
 17
" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Coins and a Scale - SOLUTION.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Coins and a Scale - SOLUTION.ipynb new file mode 100644 index 00000000..dd6ce0ad --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Coins and a Scale - SOLUTION.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Coins and a Scale - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You have eight coins and a two-pan scale. All the coins weigh the same, **except for one** which is heavier than all the others. The coins are otherwise indistinguishable. You may make no assumptions about how much heavier the heavy coin is. What is the minimum number of weighings needed to be certain of identifying the heavy coin?\n", + "\n", + "## Solution\n", + "\n", + "Begin by dividing the coins into two groups of three, which you put on the scale, and one group of two, which you leave off. If the two sides weigh the same, the heavy coin is in the group of two, and you can find it with one more weighing, for a total of two weighings. On the other hand, if either side of the scale is heavier, the heavy coin must be in that group of three. You can eliminate all the other coins, and place one coin from this group on either side of the scale, leaving the third coin aside. If one side is heavier, it contains the heavy coin; if neither side is heavier, the heavy coin is the one you didn’t place on the scale. This is also a total of two weighings, so you can always find the heavy coin in a group of eight using two weighings." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Egg Drop - SOLUTION.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Egg Drop - SOLUTION.ipynb new file mode 100644 index 00000000..2546a3db --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Egg Drop - SOLUTION.ipynb @@ -0,0 +1,73 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Egg Drop - SOLUTION\n", + "This is probably the most common brain teaser riddle out of the group, so really try to think algorithmically about this problem before looking at the solution!\n", + "\n", + "## Problem Statement\n", + "\n", + "A tower has 100 floors. You've been given two eggs. The eggs are strong enough that they can be dropped from a particular floor in the tower without breaking. You've been tasked to find the highest floor an egg can be dropped without breaking, in as few drops as possible. If an egg is dropped from above its target floor it will break. If it is dropped from that floor or below, it will be intact and you can test drop the egg again on another floor.\n", + "\n", + "Show algorithmically how you would go about doing this in as few drops as possible. (Your answer should be a number of the fewest drops needed for testing 2 eggs on 100 floors)\n", + "## Solution\n", + "\n", + "Start from the 10th floor and go up to floors in multiples of 10.\n", + "\n", + "If first egg breaks, say at 20th floor then you can check all the floors between 11th and 19th with the second egg to see which floor it will not break.\n", + "\n", + "In this case, the worst-case number of drops is 19. If the threshold was 99th floor, then you would have to drop the first egg 10 times and the second egg 9 times in linear fashion.\n", + "\n", + "**Best solution:**\n", + "We need to minimize this worst-case number of drops. For that, we need to generalize the problem to have n floors. What would be the step value, for the first egg? Would it still be 10? Suppose we have 200 floors. Would the step value be still 10? \n", + "\n", + "The point to note here is that we are trying to minimize the worst-case number of drops which happens if the threshold is at the highest floors. So, our steps should be of some value which reduces the number of drops of the first egg.\n", + "\n", + "Let's assume we take some step value m initially. If every subsequent step is m-1,\n", + "then, \n", + "$$m+m−1+m−2+.....+1=n$$\n", + "\n", + "This is \n", + "\n", + "$$\\frac{m∗(m+1)}{2}=n$$\n", + "\n", + "If n =100, then m would be 13.65 which since we can't drop from a decimal of a floor, we actually use 14.\n", + "\n", + "So, the worst case scenario is now when the threshold is in the first 14 floors with number of drops being 14.\n", + "\n", + "Note that this is simply a binary search!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "___\n", + "You can find plenty of other explanations by simply googling \"2 eggs 100 floors\"" + ] + } + ], + "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.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Hallway Lockers -SOLUTION.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Hallway Lockers -SOLUTION.ipynb new file mode 100644 index 00000000..3e7b54f7 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Hallway Lockers -SOLUTION.ipynb @@ -0,0 +1,63 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Hallway Lockers - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You are in a hallway lined with 100 lockers. You start with one pass and open the lockers, so that the *opened* lockers are now with their doors opened out. You begin by closing **every second** locker. Then you go to close **every third** locker and **close it if it is open or open it if it’s closed** — we will refer to this as \"toggling\" the lockers. You continue toggling every nth locker on pass number n. After your hundredth pass of the hallway, in which you toggle only locker number 100, how many lockers are open?\n", + "\n", + "## Solution\n", + "\n", + "Obviously you can't just brute force and count out this problem, there are just too many passes, so we will need to think about this algorithmically.\n", + "\n", + "Let's begin solving this problem by choosing an arbitrary locker and see if we can detect a pattern. Let's choose locker 12, it has been toggled open on your first pass.\n", + "\n", + "To start off we know we won't have to toggle it on any pass greater than 12. So now we only have to think of the passes that occur on 2-11. We can actualy count these out:\n", + "\n", + "* On pass 2: 2,4,6,8,10,12\n", + "* On pass 3: 3,6,9,12\n", + "* On pass 4: 4,8,12\n", + "* On pass 5: 5,10 **No toggle on this pass**\n", + "* On pass 6: 6,12\n", + "* On pass 7: 7,14 **No toggle on this pass**\n", + "* ect...\n", + "\n", + "You'll notice the pattern that emerges, we only toggle the locker when the pass number is a factor of the locker number. We can begin to make the generalization that all lockers started open after the first pass and alternate between being open and closed. So lockers are closed after the second, fourth, sixth, and so on, times they are toggled — in other words, if a locker is toggled an even number of times, then it ends closed; otherwise, it ends open. You know that a locker is toggled once for every factor of the locker number, so you can say that a locker ends open only if it has an odd number of factors.\n", + "\n", + "**The task has now been reduced to finding how many numbers between 1 and 100 have an odd number of factors!**\n", + "____\n", + "\n", + "We can think about this in the following manner:\n", + "\n", + "If a number **i** is a factor of **n**, what does that mean? It means that **i** times some other number **j** is equal to n. Because multiplication is commutative (i × j = j × i), that means that j is a factor of n, too, so the number of factors is usually even because factors tend to come in pairs. If you can find the numbers that have unpaired factors, you will know which lockers will be open. Multiplication is a binary operation, so two numbers will always be involved, but what if they are both the same number (that is, i = j)? In that case, a single number would effectively form both halves of the pair, and there would be an odd number of factors. When this is the case, i × i = n. Therefore, n must be a perfect square. Try a perfect square to check this solution. For example,\n", + "for 16, the factors are 1, 2, 4, 8, 16; operations are open, close, open, close, open — as expected, it ends open.\n", + "\n", + "Based on this reasoning, you can conclude that only lockers with numbers that are perfect squares end up open. The perfect squares between 1 and 100 (inclusive) are 1, 4, 9, 16, 25, 36, 49, 64, 81, and 100. So 10 lockers would remain open." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Jugs of Water - SOLUTION.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Jugs of Water - SOLUTION.ipynb new file mode 100644 index 00000000..6bad4853 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Jugs of Water - SOLUTION.ipynb @@ -0,0 +1,113 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Jugs of Water - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You have a five gallons jug and a three gallons jug, and an unlimited supply of water (but no measuring cups) How would you come up with exactly four gallons of water?\n", + "\n", + "## Solution\n", + "\n", + "This problem has a cameo in the movie Die Hard 3. The solution is below:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "Image(url='http://mindyourdecisions.com/blog/wp-content/uploads/2013/02/water-jug-riddle-1.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hopefully your interviews are not as stressful as this:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import YouTubeVideo\n", + "YouTubeVideo('BVtQNK_ZUJg')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Yippee Ki Yay" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Light Switches - SOLUTION.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Light Switches - SOLUTION.ipynb new file mode 100644 index 00000000..f06d5f7d --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Light Switches - SOLUTION.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Light Switches - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You are in a hallway next to three light switches, all of which are off. Each switch activates a different *incandescent* light bulb in the room at the end of the hall. You cannot see the lights from where the switches are. Your task is to determine which light corresponds to each switch. However, you may go into the room with the lights only once.\n", + "\n", + "**Note: This is a \"trick\" question, so don't spend too much time on it. Although it is more on the \"fun\" side of brain teaser type questions.**\n", + "\n", + "## Solution\n", + "\n", + "This is a bit of a trick question and hopefully you don't get asked this type of question in an interview, since its not really math or logic based. The solution is to realize that you can leave an *incandescent* light bulb on for awhile until it heats up. \n", + "\n", + "So the solution is to turn on switch 1 and wait for 15 minutes until that corrresponding bulb is hot. Then turn it off and turn on switch 2 then head to the room. Then you know that:\n", + "\n", + "* The bulb which is hot corresponds to switch 1\n", + "* The bulb which is on corresponds to switch 2\n", + "* The bulb which is off corresponds to switch 3" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Ropes Burning - SOLUTION.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Ropes Burning - SOLUTION.ipynb new file mode 100644 index 00000000..a4473f76 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems - SOLUTIONS/Ropes Burning - SOLUTION.ipynb @@ -0,0 +1,49 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Ropes Burning - SOLUTION\n", + "## Problem Statement\n", + "\n", + "You have two ropes. Each takes exactly 60 minutes to burn.\n", + "\n", + "They are made of different material so even though they take the same amount of time to burn, they burn at separate rates. In addition, each rope burns inconsistently.\n", + "\n", + "How do you measure out exactly 45 minutes?\n", + "\n", + "## Solution\n", + "\n", + "Take one rope and burn it at both ends.\n", + "\n", + "At the same time, burn one end of the other rope.\n", + "\n", + "When the first rope finishes burning, light the other end of the remaining rope.\n", + "\n", + "When it burns out, that's 45 minutes." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Bridge Crossing-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Bridge Crossing-checkpoint.ipynb new file mode 100644 index 00000000..405b8032 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Bridge Crossing-checkpoint.ipynb @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bridge Crossing" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem Statement\n", + "\n", + "A group of four travelers comes to a bridge at night. The bridge can hold the weight of at most only two of the travelers at a time, and it can- not be crossed without using a flashlight. \n", + "\n", + "The travelers have one flashlight among them. Each traveler walks at a different speed: The first can cross the bridge in 1 minute, the second in 2 minutes, the third in 5 minutes, and the fourth takes 10 minutes to cross the bridge. If two travelers cross together, they walk at the speed of the slower traveler.\n", + "\n", + "What is the least amount of time in which all the travelers can cross from one side of the bridge to the other?\n", + "\n" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Coins and a Scale -checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Coins and a Scale -checkpoint.ipynb new file mode 100644 index 00000000..15461219 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Coins and a Scale -checkpoint.ipynb @@ -0,0 +1,35 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Coins and a Scale \n", + "## Problem Statement\n", + "\n", + "You have eight coins and a two-pan scale. All the coins weigh the same, **except for one** which is heavier than all the others. The coins are otherwise indistinguishable. You may make no assumptions about how much heavier the heavy coin is. What is the minimum number of weighings needed to be certain of identifying the heavy coin?" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Egg Drop -checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Egg Drop -checkpoint.ipynb new file mode 100644 index 00000000..cbe1be74 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Egg Drop -checkpoint.ipynb @@ -0,0 +1,38 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Egg Drop \n", + "This is probably the most common brain teaser riddle out of the group, so really try to think algorithmically about this problem before looking at the solution!\n", + "## Problem Statement\n", + "\n", + "A tower has 100 floors. You've been given two eggs. The eggs are strong enough that they can be dropped from a particular floor in the tower without breaking. You've been tasked to find the highest floor an egg can be dropped without breaking, in as few drops as possible. If an egg is dropped from above its target floor it will break. If it is dropped from that floor or below, it will be intact and you can test drop the egg again on another floor.\n", + "\n", + "Show algorithmically how you would go about doing this in as few drops as possible. (Your answer should be a number of the fewest drops needed for testing 2 eggs on 100 floors)" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Hallway Lockers-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Hallway Lockers-checkpoint.ipynb new file mode 100644 index 00000000..402bfffd --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Hallway Lockers-checkpoint.ipynb @@ -0,0 +1,35 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Hallway Lockers\n", + "## Problem Statement\n", + "\n", + "You are in a hallway lined with 100 lockers. You start with one pass and open the lockers, so that the *opened* lockers are now with their doors opened out. You begin by closing **every second** locker. Then you go to close **every third** locker and **close it if it is open or open it if it’s closed** — we will refer to this as \"toggling\" the lockers. You continue toggling every nth locker on pass number n. After your hundredth pass of the hallway, in which you toggle only locker number 100, how many lockers are open?\n" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Jugs of Water -checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Jugs of Water -checkpoint.ipynb new file mode 100644 index 00000000..727614de --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Jugs of Water -checkpoint.ipynb @@ -0,0 +1,35 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Jugs of Water \n", + "## Problem Statement\n", + "\n", + "You have a five gallons jug and a three gallons jug, and an unlimited supply of water (but no measuring cups) How would you come up with exactly four gallons of water?" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Light Switches -checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Light Switches -checkpoint.ipynb new file mode 100644 index 00000000..b3b8995a --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Light Switches -checkpoint.ipynb @@ -0,0 +1,37 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Light Switches\n", + "## Problem Statement\n", + "\n", + "You are in a hallway next to three light switches, all of which are off. Each switch activates a different *incandescent* light bulb in the room at the end of the hall. You cannot see the lights from where the switches are. Your task is to determine which light corresponds to each switch. However, you may go into the room with the lights only once.\n", + "\n", + "**Note: This is a bit of \"trick\" question, so don't spend too much time on it. Although it is more on the \"fun\" side of brain teaser type questions.**\n" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Ropes Burning-checkpoint.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Ropes Burning-checkpoint.ipynb new file mode 100644 index 00000000..c9f81f96 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/.ipynb_checkpoints/Ropes Burning-checkpoint.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Ropes Burning \n", + "## Problem Statement\n", + "\n", + "You have two ropes. Each takes exactly 60 minutes to burn.\n", + "\n", + "They are made of different material so even though they take the same amount of time to burn, they burn at separate rates. In addition, each rope burns inconsistently.\n", + "\n", + "How do you measure out exactly 45 minutes?" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Bridge Crossing.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Bridge Crossing.ipynb new file mode 100644 index 00000000..405b8032 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Bridge Crossing.ipynb @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bridge Crossing" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem Statement\n", + "\n", + "A group of four travelers comes to a bridge at night. The bridge can hold the weight of at most only two of the travelers at a time, and it can- not be crossed without using a flashlight. \n", + "\n", + "The travelers have one flashlight among them. Each traveler walks at a different speed: The first can cross the bridge in 1 minute, the second in 2 minutes, the third in 5 minutes, and the fourth takes 10 minutes to cross the bridge. If two travelers cross together, they walk at the speed of the slower traveler.\n", + "\n", + "What is the least amount of time in which all the travelers can cross from one side of the bridge to the other?\n", + "\n" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Coins and a Scale .ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Coins and a Scale .ipynb new file mode 100644 index 00000000..15461219 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Coins and a Scale .ipynb @@ -0,0 +1,35 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Coins and a Scale \n", + "## Problem Statement\n", + "\n", + "You have eight coins and a two-pan scale. All the coins weigh the same, **except for one** which is heavier than all the others. The coins are otherwise indistinguishable. You may make no assumptions about how much heavier the heavy coin is. What is the minimum number of weighings needed to be certain of identifying the heavy coin?" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Egg Drop .ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Egg Drop .ipynb new file mode 100644 index 00000000..cbe1be74 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Egg Drop .ipynb @@ -0,0 +1,38 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Egg Drop \n", + "This is probably the most common brain teaser riddle out of the group, so really try to think algorithmically about this problem before looking at the solution!\n", + "## Problem Statement\n", + "\n", + "A tower has 100 floors. You've been given two eggs. The eggs are strong enough that they can be dropped from a particular floor in the tower without breaking. You've been tasked to find the highest floor an egg can be dropped without breaking, in as few drops as possible. If an egg is dropped from above its target floor it will break. If it is dropped from that floor or below, it will be intact and you can test drop the egg again on another floor.\n", + "\n", + "Show algorithmically how you would go about doing this in as few drops as possible. (Your answer should be a number of the fewest drops needed for testing 2 eggs on 100 floors)" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Hallway Lockers.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Hallway Lockers.ipynb new file mode 100644 index 00000000..402bfffd --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Hallway Lockers.ipynb @@ -0,0 +1,35 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Hallway Lockers\n", + "## Problem Statement\n", + "\n", + "You are in a hallway lined with 100 lockers. You start with one pass and open the lockers, so that the *opened* lockers are now with their doors opened out. You begin by closing **every second** locker. Then you go to close **every third** locker and **close it if it is open or open it if it’s closed** — we will refer to this as \"toggling\" the lockers. You continue toggling every nth locker on pass number n. After your hundredth pass of the hallway, in which you toggle only locker number 100, how many lockers are open?\n" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Jugs of Water .ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Jugs of Water .ipynb new file mode 100644 index 00000000..727614de --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Jugs of Water .ipynb @@ -0,0 +1,35 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Jugs of Water \n", + "## Problem Statement\n", + "\n", + "You have a five gallons jug and a three gallons jug, and an unlimited supply of water (but no measuring cups) How would you come up with exactly four gallons of water?" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Light Switches .ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Light Switches .ipynb new file mode 100644 index 00000000..b3b8995a --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Light Switches .ipynb @@ -0,0 +1,37 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Light Switches\n", + "## Problem Statement\n", + "\n", + "You are in a hallway next to three light switches, all of which are off. Each switch activates a different *incandescent* light bulb in the room at the end of the hall. You cannot see the lights from where the switches are. Your task is to determine which light corresponds to each switch. However, you may go into the room with the lights only once.\n", + "\n", + "**Note: This is a bit of \"trick\" question, so don't spend too much time on it. Although it is more on the \"fun\" side of brain teaser type questions.**\n" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Ropes Burning.ipynb b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Ropes Burning.ipynb new file mode 100644 index 00000000..c9f81f96 --- /dev/null +++ b/Riddles/Riddle Interview Problems/Riddle Interview Problems_/Ropes Burning.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Ropes Burning \n", + "## Problem Statement\n", + "\n", + "You have two ropes. Each takes exactly 60 minutes to burn.\n", + "\n", + "They are made of different material so even though they take the same amount of time to burn, they burn at separate rates. In addition, each rope burns inconsistently.\n", + "\n", + "How do you measure out exactly 45 minutes?" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/.ipynb_checkpoints/Implementation of Binary Search-checkpoint.ipynb b/Sorting and Searching/.ipynb_checkpoints/Implementation of Binary Search-checkpoint.ipynb new file mode 100644 index 00000000..aa558014 --- /dev/null +++ b/Sorting and Searching/.ipynb_checkpoints/Implementation of Binary Search-checkpoint.ipynb @@ -0,0 +1,226 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Binary Search\n", + "\n", + "In this notebook we will just implement two versions of a simple binary search. View the video lecture for a full breakdown!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Binary Search" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def binary_search(arr,ele):\n", + " \n", + " # First and last index values\n", + " first = 0\n", + " last = len(arr) - 1\n", + " \n", + " found = False\n", + " \n", + " \n", + " while first <= last and not found:\n", + " \n", + " mid = (first+last)/2 # or // for Python 3\n", + " \n", + " # Match found\n", + " if arr[mid] == ele:\n", + " found = True\n", + " \n", + " # Set new midpoints up or down depending on comparison\n", + " else:\n", + " # Set down\n", + " if ele < arr[mid]:\n", + " last = mid -1\n", + " # Set up \n", + " else:\n", + " first = mid + 1\n", + " \n", + " return found" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# list must already be sorted!\n", + "arr = [1,2,3,4,5,6,7,8,9,10]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "binary_search(arr,4)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "binary_search(arr,2.2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Recursive Version of Binary Search" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def rec_bin_search(arr,ele):\n", + " \n", + " # Base Case!\n", + " if len(arr) == 0:\n", + " return False\n", + " \n", + " # Recursive Case\n", + " else:\n", + " \n", + " mid = len(arr)/2\n", + " \n", + " # If match found\n", + " if arr[mid]==ele:\n", + " return True\n", + " \n", + " else:\n", + " \n", + " # Call again on second half\n", + " if elearr[k+1]:\n", + " temp = arr[k]\n", + " arr[k] = arr[k+1]\n", + " arr[k+1] = temp" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "arr = [3,2,13,4,6,5,7,8,1,20]\n", + "bubble_sort(arr)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 13, 20]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Great Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/.ipynb_checkpoints/Implementation of Insertion Sort-checkpoint.ipynb b/Sorting and Searching/.ipynb_checkpoints/Implementation of Insertion Sort-checkpoint.ipynb new file mode 100644 index 00000000..86b90033 --- /dev/null +++ b/Sorting and Searching/.ipynb_checkpoints/Implementation of Insertion Sort-checkpoint.ipynb @@ -0,0 +1,105 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Insertion Sort\n", + "\n", + "Insertion Sort builds the final sorted array (or list) one item at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Insertion sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Animation](http://cs.armstrong.edu/liang/animation/web/InsertionSort.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/insertion-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def insertion_sort(arr):\n", + " \n", + " # For every index in array\n", + " for i in range(1,len(arr)):\n", + " \n", + " # Set current values and position\n", + " currentvalue = arr[i]\n", + " position = i\n", + " \n", + " # Sorted Sublist\n", + " while position>0 and arr[position-1]>currentvalue:\n", + " \n", + " arr[position]=arr[position-1]\n", + " position = position-1\n", + "\n", + " arr[position]=currentvalue" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 6, 8, 12, 25, 41]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr =[3,5,4,6,8,1,2,12,41,25]\n", + "insertion_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/.ipynb_checkpoints/Implementation of Merge Sort-checkpoint.ipynb b/Sorting and Searching/.ipynb_checkpoints/Implementation of Merge Sort-checkpoint.ipynb new file mode 100644 index 00000000..5a38965b --- /dev/null +++ b/Sorting and Searching/.ipynb_checkpoints/Implementation of Merge Sort-checkpoint.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Merge Sort\n", + "\n", + "Merge sort is a recursive algorithm that continually splits a list in half. If the list is empty or has one item, it is sorted by definition (the base case). If the list has more than one item, we split the list and recursively invoke a merge sort on both halves. Once the two halves are sorted, the fundamental operation, called a merge, is performed. Merging is the process of taking two smaller sorted lists and combining them together into a single, sorted, new list. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Merge sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/merge-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def merge_sort(arr):\n", + " \n", + " if len(arr)>1:\n", + " mid = len(arr)/2\n", + " lefthalf = arr[:mid]\n", + " righthalf = arr[mid:]\n", + "\n", + " merge_sort(lefthalf)\n", + " merge_sort(righthalf)\n", + "\n", + " i=0\n", + " j=0\n", + " k=0\n", + " while i < len(lefthalf) and j < len(righthalf):\n", + " if lefthalf[i] < righthalf[j]:\n", + " arr[k]=lefthalf[i]\n", + " i=i+1\n", + " else:\n", + " arr[k]=righthalf[j]\n", + " j=j+1\n", + " k=k+1\n", + "\n", + " while i < len(lefthalf):\n", + " arr[k]=lefthalf[i]\n", + " i=i+1\n", + " k=k+1\n", + "\n", + " while j < len(righthalf):\n", + " arr[k]=righthalf[j]\n", + " j=j+1\n", + " k=k+1" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 4, 5, 6, 7, 8, 11, 23]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr = [11,2,5,4,7,6,8,1,23]\n", + "merge_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/.ipynb_checkpoints/Implementation of Quick Sort-checkpoint.ipynb b/Sorting and Searching/.ipynb_checkpoints/Implementation of Quick Sort-checkpoint.ipynb new file mode 100644 index 00000000..7a00715a --- /dev/null +++ b/Sorting and Searching/.ipynb_checkpoints/Implementation of Quick Sort-checkpoint.ipynb @@ -0,0 +1,132 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Quick Sort\n", + "\n", + "A quick sort first selects a value, which is called the pivot value. Although there are many different ways to choose the pivot value, we will simply use the first item in the list. The role of the pivot value is to assist with splitting the list. The actual position where the pivot value belongs in the final sorted list, commonly called the split point, will be used to divide the list for subsequent calls to the quick sort." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Insertion sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Quicksort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/quick-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def quick_sort(arr):\n", + " \n", + " quick_sort_help(arr,0,len(arr)-1)\n", + "\n", + "def quick_sort_help(arr,first,last):\n", + " \n", + " if first= pivotvalue and rightmark >= leftmark:\n", + " rightmark = rightmark -1\n", + "\n", + " if rightmark < leftmark:\n", + " done = True\n", + " else:\n", + " temp = arr[leftmark]\n", + " arr[leftmark] = arr[rightmark]\n", + " arr[rightmark] = temp\n", + "\n", + " temp = arr[first]\n", + " arr[first] = arr[rightmark]\n", + " arr[rightmark] = temp\n", + "\n", + "\n", + " return rightmark" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 4, 5, 6, 7, 11, 12]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr = [2,5,4,6,7,3,1,4,12,11]\n", + "quick_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/.ipynb_checkpoints/Implementation of Selection Sort-checkpoint.ipynb b/Sorting and Searching/.ipynb_checkpoints/Implementation of Selection Sort-checkpoint.ipynb new file mode 100644 index 00000000..c6d82a2d --- /dev/null +++ b/Sorting and Searching/.ipynb_checkpoints/Implementation of Selection Sort-checkpoint.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Selection Sort\n", + "\n", + "The selection sort improves on the bubble sort by making only one exchange for every pass through the list. In order to do this, a selection sort looks for the largest value as it makes a pass and, after completing the pass, places it in the proper location. As with a bubble sort, after the first pass, the largest item is in the correct place. After the second pass, the next largest is in place. This process continues and requires n−1 passes to sort n items, since the final item must be in place after the (n−1) st pass." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Selection sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Selection_sort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Animation](http://cs.armstrong.edu/liang/animation/web/SelectionSort.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/selection-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def selection_sort(arr):\n", + " \n", + " # For every slot in array\n", + " for fillslot in range(len(arr)-1,0,-1):\n", + " positionOfMax=0\n", + " \n", + " # For every set of 0 to fillslot+1\n", + " for location in range(1,fillslot+1):\n", + " # Set maximum's location\n", + " if arr[location]>arr[positionOfMax]:\n", + " positionOfMax = location\n", + "\n", + " temp = arr[fillslot]\n", + " arr[fillslot] = arr[positionOfMax]\n", + " arr[positionOfMax] = temp" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 3, 5, 6, 7, 8, 12, 21, 40]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr = [3,5,2,7,6,8,12,40,21]\n", + "selection_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/.ipynb_checkpoints/Implementation of Shell Sort-checkpoint.ipynb b/Sorting and Searching/.ipynb_checkpoints/Implementation of Shell Sort-checkpoint.ipynb new file mode 100644 index 00000000..52bc30fc --- /dev/null +++ b/Sorting and Searching/.ipynb_checkpoints/Implementation of Shell Sort-checkpoint.ipynb @@ -0,0 +1,114 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Shell Sort\n", + "\n", + "The shell sort improves on the insertion sort by breaking the original list into a number of smaller sublists, each of which is sorted using an insertion sort. The unique way that these sublists are chosen is the key to the shell sort. Instead of breaking the list into sublists of contiguous items, the shell sort uses an increment i, sometimes called the gap, to create a sublist by choosing all items that are i items apart." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Shell sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/shell-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def shell_sort(arr):\n", + " sublistcount = len(arr)/2\n", + " \n", + " # While we still have sub lists\n", + " while sublistcount > 0:\n", + " for start in range(sublistcount):\n", + " # Use a gap insertion\n", + " gap_insertion_sort(arr,start,sublistcount)\n", + "\n", + " \n", + "\n", + " sublistcount = sublistcount / 2\n", + "\n", + "def gap_insertion_sort(arr,start,gap):\n", + " for i in range(start+gap,len(arr),gap):\n", + "\n", + " currentvalue = arr[i]\n", + " position = i\n", + "\n", + " # Using the Gap\n", + " while position>=gap and arr[position-gap]>currentvalue:\n", + " arr[position]=arr[position-gap]\n", + " position = position-gap\n", + " \n", + " # Set current value\n", + " arr[position]=currentvalue" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 4, 6, 7, 21, 23, 24, 45, 45, 67, 90]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr = [45,67,23,45,21,24,7,2,6,4,90]\n", + "shell_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/.ipynb_checkpoints/Implementation of a Hash Table-checkpoint.ipynb b/Sorting and Searching/.ipynb_checkpoints/Implementation of a Hash Table-checkpoint.ipynb new file mode 100644 index 00000000..aa8703ba --- /dev/null +++ b/Sorting and Searching/.ipynb_checkpoints/Implementation of a Hash Table-checkpoint.ipynb @@ -0,0 +1,277 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of a Hash Table\n", + "\n", + "In this lecture we will be implementing our own Hash Table to complete our understanding of Hash Tables and Hash Functions! Make sure to review the video lecture before this to fully understand this implementation!\n", + "\n", + "Keep in mind that Python already has a built-in dictionary object that serves as a Hash Table, you would never actually need to implement your own hash table in Python.\n", + "\n", + "___\n", + "## Map\n", + "The idea of a dictionary used as a hash table to get and retrieve items using **keys** is often referred to as a mapping. In our implementation we will have the following methods:\n", + "\n", + "\n", + "* **HashTable()** Create a new, empty map. It returns an empty map collection.\n", + "* **put(key,val)** Add a new key-value pair to the map. If the key is already in the map then replace the old value with the new value.\n", + "* **get(key)** Given a key, return the value stored in the map or None otherwise.\n", + "* **del** Delete the key-value pair from the map using a statement of the form del map[key].\n", + "* **len()** Return the number of key-value pairs stored \n", + "* **in** the map in Return True for a statement of the form **key in map**, if the given key is in the map, False otherwise." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class HashTable(object):\n", + " \n", + " def __init__(self,size):\n", + " \n", + " # Set up size and slots and data\n", + " self.size = size\n", + " self.slots = [None] * self.size\n", + " self.data = [None] * self.size\n", + " \n", + " def put(self,key,data):\n", + " #Note, we'll only use integer keys for ease of use with the Hash Function\n", + " \n", + " # Get the hash value\n", + " hashvalue = self.hashfunction(key,len(self.slots))\n", + "\n", + " # If Slot is Empty\n", + " if self.slots[hashvalue] == None:\n", + " self.slots[hashvalue] = key\n", + " self.data[hashvalue] = data\n", + " \n", + " else:\n", + " \n", + " # If key already exists, replace old value\n", + " if self.slots[hashvalue] == key:\n", + " self.data[hashvalue] = data \n", + " \n", + " # Otherwise, find the next available slot\n", + " else:\n", + " \n", + " nextslot = self.rehash(hashvalue,len(self.slots))\n", + " \n", + " # Get to the next slot\n", + " while self.slots[nextslot] != None and self.slots[nextslot] != key:\n", + " nextslot = self.rehash(nextslot,len(self.slots))\n", + " \n", + " # Set new key, if NONE\n", + " if self.slots[nextslot] == None:\n", + " self.slots[nextslot]=key\n", + " self.data[nextslot]=data\n", + " \n", + " # Otherwise replace old value\n", + " else:\n", + " self.data[nextslot] = data \n", + "\n", + " def hashfunction(self,key,size):\n", + " # Remainder Method\n", + " return key%size\n", + "\n", + " def rehash(self,oldhash,size):\n", + " # For finding next possible positions\n", + " return (oldhash+1)%size\n", + " \n", + " \n", + " def get(self,key):\n", + " \n", + " # Getting items given a key\n", + " \n", + " # Set up variables for our search\n", + " startslot = self.hashfunction(key,len(self.slots))\n", + " data = None\n", + " stop = False\n", + " found = False\n", + " position = startslot\n", + " \n", + " # Until we discern that its not empty or found (and haven't stopped yet)\n", + " while self.slots[position] != None and not found and not stop:\n", + " \n", + " if self.slots[position] == key:\n", + " found = True\n", + " data = self.data[position]\n", + " \n", + " else:\n", + " position=self.rehash(position,len(self.slots))\n", + " if position == startslot:\n", + " \n", + " stop = True\n", + " return data\n", + "\n", + " # Special Methods for use with Python indexing\n", + " def __getitem__(self,key):\n", + " return self.get(key)\n", + "\n", + " def __setitem__(self,key,data):\n", + " self.put(key,data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see it in action!" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "h = HashTable(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Put our first key in\n", + "h[1] = 'one'" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "h[2] = 'two'" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "h[3] = 'three'" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'one'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "h[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "h[1] = 'new_one'" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'new_one'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "h[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n" + ] + } + ], + "source": [ + "print h[4]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Great Job!\n", + "\n", + "That's it for this rudimentary implementation, try implementing a different hash function for practice!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/.ipynb_checkpoints/Sequential Search-checkpoint.ipynb b/Sorting and Searching/.ipynb_checkpoints/Sequential Search-checkpoint.ipynb new file mode 100644 index 00000000..f514dc75 --- /dev/null +++ b/Sorting and Searching/.ipynb_checkpoints/Sequential Search-checkpoint.ipynb @@ -0,0 +1,235 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sequential Search\n", + "\n", + "Check out the video lecture for a full breakdown, in this Notebook all we do is implement Sequential Search for an Unordered List and an Ordered List." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "## Sequential Search" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def seq_search(arr,ele):\n", + " \"\"\"\n", + " General Sequential Search. Works on Unordered lists.\n", + " \"\"\"\n", + " \n", + " # Start at position 0\n", + " pos = 0\n", + " # Target becomes true if ele is in the list\n", + " found = False\n", + " \n", + " # go until end of list\n", + " while pos < len(arr) and not found:\n", + " \n", + " # If match\n", + " if arr[pos] == ele:\n", + " found = True\n", + " \n", + " # Else move one down\n", + " else:\n", + " pos = pos+1\n", + " \n", + " return found" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "arr = [1,9,2,8,3,4,7,5,6]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print seq_search(arr,1)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n" + ] + } + ], + "source": [ + "print seq_search(arr,10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ordered List\n", + "\n", + "If we know the list is ordered than, we only have to check until we have found the element or an element greater than it." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def ordered_seq_search(arr,ele):\n", + " \"\"\"\n", + " Sequential search for an Ordered list\n", + " \"\"\"\n", + " # Start at position 0\n", + " pos = 0\n", + " \n", + " # Target becomes true if ele is in the list\n", + " found = False\n", + " \n", + " # Stop marker\n", + " stopped = False\n", + " \n", + " # go until end of list\n", + " while pos < len(arr) and not found and not stopped:\n", + " \n", + " # If match\n", + " if arr[pos] == ele:\n", + " found = True\n", + " \n", + " else:\n", + " \n", + " # Check if element is greater\n", + " if arr[pos] > ele:\n", + " stopped = True\n", + " \n", + " # Otherwise move on\n", + " else:\n", + " pos = pos+1\n", + " \n", + " return found" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "arr.sort() " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ordered_seq_search(arr,3)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ordered_seq_search(arr,1.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/Implementation of Binary Search.ipynb b/Sorting and Searching/Implementation of Binary Search.ipynb new file mode 100644 index 00000000..aa558014 --- /dev/null +++ b/Sorting and Searching/Implementation of Binary Search.ipynb @@ -0,0 +1,226 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Binary Search\n", + "\n", + "In this notebook we will just implement two versions of a simple binary search. View the video lecture for a full breakdown!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Binary Search" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def binary_search(arr,ele):\n", + " \n", + " # First and last index values\n", + " first = 0\n", + " last = len(arr) - 1\n", + " \n", + " found = False\n", + " \n", + " \n", + " while first <= last and not found:\n", + " \n", + " mid = (first+last)/2 # or // for Python 3\n", + " \n", + " # Match found\n", + " if arr[mid] == ele:\n", + " found = True\n", + " \n", + " # Set new midpoints up or down depending on comparison\n", + " else:\n", + " # Set down\n", + " if ele < arr[mid]:\n", + " last = mid -1\n", + " # Set up \n", + " else:\n", + " first = mid + 1\n", + " \n", + " return found" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# list must already be sorted!\n", + "arr = [1,2,3,4,5,6,7,8,9,10]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "binary_search(arr,4)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "binary_search(arr,2.2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Recursive Version of Binary Search" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def rec_bin_search(arr,ele):\n", + " \n", + " # Base Case!\n", + " if len(arr) == 0:\n", + " return False\n", + " \n", + " # Recursive Case\n", + " else:\n", + " \n", + " mid = len(arr)/2\n", + " \n", + " # If match found\n", + " if arr[mid]==ele:\n", + " return True\n", + " \n", + " else:\n", + " \n", + " # Call again on second half\n", + " if elearr[k+1]:\n", + " temp = arr[k]\n", + " arr[k] = arr[k+1]\n", + " arr[k+1] = temp" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "arr = [3,2,13,4,6,5,7,8,1,20]\n", + "bubble_sort(arr)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 13, 20]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Great Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Sorting and Searching/Implementation of Insertion Sort.ipynb b/Sorting and Searching/Implementation of Insertion Sort.ipynb new file mode 100644 index 00000000..b00bb835 --- /dev/null +++ b/Sorting and Searching/Implementation of Insertion Sort.ipynb @@ -0,0 +1,103 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Insertion Sort\n", + "\n", + "Insertion Sort builds the final sorted array (or list) one item at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Insertion sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Animation](http://cs.armstrong.edu/liang/animation/web/InsertionSort.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/insertion-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def insertion_sort(arr):\n", + " \n", + " # For every index in array\n", + " for i in range(1,len(arr)):\n", + " \n", + " # Set current values and position\n", + " currentvalue = arr[i]\n", + " position = i\n", + " \n", + " # Sorted Sublist\n", + " while position>0 and arr[position-1]>currentvalue:\n", + " \n", + " arr[position]=arr[position-1]\n", + " position = position-1\n", + "\n", + " arr[position]=currentvalue" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 6, 8, 12, 25, 41]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr =[3,5,4,6,8,1,2,12,41,25]\n", + "insertion_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Sorting and Searching/Implementation of Merge Sort.ipynb b/Sorting and Searching/Implementation of Merge Sort.ipynb new file mode 100644 index 00000000..0ad3b17d --- /dev/null +++ b/Sorting and Searching/Implementation of Merge Sort.ipynb @@ -0,0 +1,117 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Merge Sort\n", + "\n", + "Merge sort is a recursive algorithm that continually splits a list in half. If the list is empty or has one item, it is sorted by definition (the base case). If the list has more than one item, we split the list and recursively invoke a merge sort on both halves. Once the two halves are sorted, the fundamental operation, called a merge, is performed. Merging is the process of taking two smaller sorted lists and combining them together into a single, sorted, new list. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Merge sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/merge-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def merge_sort(arr):\n", + " \n", + " if len(arr)>1:\n", + " mid = len(arr)/2\n", + " lefthalf = arr[:mid]\n", + " righthalf = arr[mid:]\n", + "\n", + " merge_sort(lefthalf)\n", + " merge_sort(righthalf)\n", + "\n", + " i=0\n", + " j=0\n", + " k=0\n", + " while i < len(lefthalf) and j < len(righthalf):\n", + " if lefthalf[i] < righthalf[j]:\n", + " arr[k]=lefthalf[i]\n", + " i=i+1\n", + " else:\n", + " arr[k]=righthalf[j]\n", + " j=j+1\n", + " k=k+1\n", + "\n", + " while i < len(lefthalf):\n", + " arr[k]=lefthalf[i]\n", + " i=i+1\n", + " k=k+1\n", + "\n", + " while j < len(righthalf):\n", + " arr[k]=righthalf[j]\n", + " j=j+1\n", + " k=k+1" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 4, 5, 6, 7, 8, 11, 23]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr = [11,2,5,4,7,6,8,1,23]\n", + "merge_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Sorting and Searching/Implementation of Quick Sort.ipynb b/Sorting and Searching/Implementation of Quick Sort.ipynb new file mode 100644 index 00000000..bf2e99c0 --- /dev/null +++ b/Sorting and Searching/Implementation of Quick Sort.ipynb @@ -0,0 +1,130 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Quick Sort\n", + "\n", + "A quick sort first selects a value, which is called the pivot value. Although there are many different ways to choose the pivot value, we will simply use the first item in the list. The role of the pivot value is to assist with splitting the list. The actual position where the pivot value belongs in the final sorted list, commonly called the split point, will be used to divide the list for subsequent calls to the quick sort." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Insertion sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Quicksort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/quick-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def quick_sort(arr):\n", + " \n", + " quick_sort_help(arr,0,len(arr)-1)\n", + "\n", + "def quick_sort_help(arr,first,last):\n", + " \n", + " if first= pivotvalue and rightmark >= leftmark:\n", + " rightmark = rightmark -1\n", + "\n", + " if rightmark < leftmark:\n", + " done = True\n", + " else:\n", + " temp = arr[leftmark]\n", + " arr[leftmark] = arr[rightmark]\n", + " arr[rightmark] = temp\n", + "\n", + " temp = arr[first]\n", + " arr[first] = arr[rightmark]\n", + " arr[rightmark] = temp\n", + "\n", + "\n", + " return rightmark" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 4, 5, 6, 7, 11, 12]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr = [2,5,4,6,7,3,1,4,12,11]\n", + "quick_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Sorting and Searching/Implementation of Selection Sort.ipynb b/Sorting and Searching/Implementation of Selection Sort.ipynb new file mode 100644 index 00000000..c6d82a2d --- /dev/null +++ b/Sorting and Searching/Implementation of Selection Sort.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Selection Sort\n", + "\n", + "The selection sort improves on the bubble sort by making only one exchange for every pass through the list. In order to do this, a selection sort looks for the largest value as it makes a pass and, after completing the pass, places it in the proper location. As with a bubble sort, after the first pass, the largest item is in the correct place. After the second pass, the next largest is in place. This process continues and requires n−1 passes to sort n items, since the final item must be in place after the (n−1) st pass." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Selection sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Selection_sort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Animation](http://cs.armstrong.edu/liang/animation/web/SelectionSort.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/selection-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def selection_sort(arr):\n", + " \n", + " # For every slot in array\n", + " for fillslot in range(len(arr)-1,0,-1):\n", + " positionOfMax=0\n", + " \n", + " # For every set of 0 to fillslot+1\n", + " for location in range(1,fillslot+1):\n", + " # Set maximum's location\n", + " if arr[location]>arr[positionOfMax]:\n", + " positionOfMax = location\n", + "\n", + " temp = arr[fillslot]\n", + " arr[fillslot] = arr[positionOfMax]\n", + " arr[positionOfMax] = temp" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 3, 5, 6, 7, 8, 12, 21, 40]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr = [3,5,2,7,6,8,12,40,21]\n", + "selection_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/Implementation of Shell Sort.ipynb b/Sorting and Searching/Implementation of Shell Sort.ipynb new file mode 100644 index 00000000..52bc30fc --- /dev/null +++ b/Sorting and Searching/Implementation of Shell Sort.ipynb @@ -0,0 +1,114 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Shell Sort\n", + "\n", + "The shell sort improves on the insertion sort by breaking the original list into a number of smaller sublists, each of which is sorted using an insertion sort. The unique way that these sublists are chosen is the key to the shell sort. Instead of breaking the list into sublists of contiguous items, the shell sort uses an increment i, sometimes called the gap, to create a sublist by choosing all items that are i items apart." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Resources for Review\n", + "\n", + "Check out the resources below for a review of Shell sort!\n", + "\n", + "* [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)\n", + "* [Visual Algo](http://visualgo.net/sorting.html)\n", + "* [Sorting Algorithms Animcation with Pseudocode](http://www.sorting-algorithms.com/shell-sort)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def shell_sort(arr):\n", + " sublistcount = len(arr)/2\n", + " \n", + " # While we still have sub lists\n", + " while sublistcount > 0:\n", + " for start in range(sublistcount):\n", + " # Use a gap insertion\n", + " gap_insertion_sort(arr,start,sublistcount)\n", + "\n", + " \n", + "\n", + " sublistcount = sublistcount / 2\n", + "\n", + "def gap_insertion_sort(arr,start,gap):\n", + " for i in range(start+gap,len(arr),gap):\n", + "\n", + " currentvalue = arr[i]\n", + " position = i\n", + "\n", + " # Using the Gap\n", + " while position>=gap and arr[position-gap]>currentvalue:\n", + " arr[position]=arr[position-gap]\n", + " position = position-gap\n", + " \n", + " # Set current value\n", + " arr[position]=currentvalue" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[2, 4, 6, 7, 21, 23, 24, 45, 45, 67, 90]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "arr = [45,67,23,45,21,24,7,2,6,4,90]\n", + "shell_sort(arr)\n", + "arr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Sorting and Searching/Implementation of a Hash Table.ipynb b/Sorting and Searching/Implementation of a Hash Table.ipynb new file mode 100644 index 00000000..e71d50a8 --- /dev/null +++ b/Sorting and Searching/Implementation of a Hash Table.ipynb @@ -0,0 +1,269 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of a Hash Table\n", + "\n", + "In this lecture we will be implementing our own Hash Table to complete our understanding of Hash Tables and Hash Functions! Make sure to review the video lecture before this to fully understand this implementation!\n", + "\n", + "Keep in mind that Python already has a built-in dictionary object that serves as a Hash Table, you would never actually need to implement your own hash table in Python.\n", + "\n", + "___\n", + "## Map\n", + "The idea of a dictionary used as a hash table to get and retrieve items using **keys** is often referred to as a mapping. In our implementation we will have the following methods:\n", + "\n", + "\n", + "* **HashTable()** Create a new, empty map. It returns an empty map collection.\n", + "* **put(key,val)** Add a new key-value pair to the map. If the key is already in the map then replace the old value with the new value.\n", + "* **get(key)** Given a key, return the value stored in the map or None otherwise.\n", + "* **del** Delete the key-value pair from the map using a statement of the form del map[key].\n", + "* **len()** Return the number of key-value pairs stored \n", + "* **in** the map in Return True for a statement of the form **key in map**, if the given key is in the map, False otherwise." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class HashTable(object):\n", + " \n", + " def __init__(self,size):\n", + " \n", + " # Set up size and slots and data\n", + " self.size = size\n", + " self.slots = [None] * self.size\n", + " self.data = [None] * self.size\n", + " \n", + " def put(self,key,data):\n", + " #Note, we'll only use integer keys for ease of use with the Hash Function\n", + " \n", + " # Get the hash value\n", + " hashvalue = self.hashfunction(key,len(self.slots))\n", + "\n", + " # If Slot is Empty\n", + " if self.slots[hashvalue] == None:\n", + " self.slots[hashvalue] = key\n", + " self.data[hashvalue] = data\n", + " \n", + " else:\n", + " \n", + " # If key already exists, replace old value\n", + " if self.slots[hashvalue] == key:\n", + " self.data[hashvalue] = data \n", + " \n", + " # Otherwise, find the next available slot\n", + " else:\n", + " \n", + " nextslot = self.rehash(hashvalue,len(self.slots))\n", + " \n", + " # Get to the next slot\n", + " while self.slots[nextslot] != None and self.slots[nextslot] != key:\n", + " nextslot = self.rehash(nextslot,len(self.slots))\n", + " \n", + " # Set new key, if NONE\n", + " if self.slots[nextslot] == None:\n", + " self.slots[nextslot]=key\n", + " self.data[nextslot]=data\n", + " \n", + " # Otherwise replace old value\n", + " else:\n", + " self.data[nextslot] = data \n", + "\n", + " def hashfunction(self,key,size):\n", + " # Remainder Method\n", + " return key%size\n", + "\n", + " def rehash(self,oldhash,size):\n", + " # For finding next possible positions\n", + " return (oldhash+1)%size\n", + " \n", + " \n", + " def get(self,key):\n", + " \n", + " # Getting items given a key\n", + " \n", + " # Set up variables for our search\n", + " startslot = self.hashfunction(key,len(self.slots))\n", + " data = None\n", + " stop = False\n", + " found = False\n", + " position = startslot\n", + " \n", + " # Until we discern that its not empty or found (and haven't stopped yet)\n", + " while self.slots[position] != None and not found and not stop:\n", + " \n", + " if self.slots[position] == key:\n", + " found = True\n", + " data = self.data[position]\n", + " \n", + " else:\n", + " position=self.rehash(position,len(self.slots))\n", + " if position == startslot:\n", + " \n", + " stop = True\n", + " return data\n", + "\n", + " # Special Methods for use with Python indexing\n", + " def __getitem__(self,key):\n", + " return self.get(key)\n", + "\n", + " def __setitem__(self,key,data):\n", + " self.put(key,data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see it in action!" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "h = HashTable(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Put our first key in\n", + "h[1] = 'one'" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "h[2] = 'two'" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "h[3] = 'three'" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'one'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "h[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "h[1] = 'new_one'" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'new_one'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "h[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n" + ] + } + ], + "source": [ + "print h[4]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Great Job!\n", + "\n", + "That's it for this rudimentary implementation, try implementing a different hash function for practice!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Sorting and Searching/Sequential Search.ipynb b/Sorting and Searching/Sequential Search.ipynb new file mode 100644 index 00000000..f514dc75 --- /dev/null +++ b/Sorting and Searching/Sequential Search.ipynb @@ -0,0 +1,235 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sequential Search\n", + "\n", + "Check out the video lecture for a full breakdown, in this Notebook all we do is implement Sequential Search for an Unordered List and an Ordered List." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "## Sequential Search" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def seq_search(arr,ele):\n", + " \"\"\"\n", + " General Sequential Search. Works on Unordered lists.\n", + " \"\"\"\n", + " \n", + " # Start at position 0\n", + " pos = 0\n", + " # Target becomes true if ele is in the list\n", + " found = False\n", + " \n", + " # go until end of list\n", + " while pos < len(arr) and not found:\n", + " \n", + " # If match\n", + " if arr[pos] == ele:\n", + " found = True\n", + " \n", + " # Else move one down\n", + " else:\n", + " pos = pos+1\n", + " \n", + " return found" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "arr = [1,9,2,8,3,4,7,5,6]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print seq_search(arr,1)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n" + ] + } + ], + "source": [ + "print seq_search(arr,10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ordered List\n", + "\n", + "If we know the list is ordered than, we only have to check until we have found the element or an element greater than it." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def ordered_seq_search(arr,ele):\n", + " \"\"\"\n", + " Sequential search for an Ordered list\n", + " \"\"\"\n", + " # Start at position 0\n", + " pos = 0\n", + " \n", + " # Target becomes true if ele is in the list\n", + " found = False\n", + " \n", + " # Stop marker\n", + " stopped = False\n", + " \n", + " # go until end of list\n", + " while pos < len(arr) and not found and not stopped:\n", + " \n", + " # If match\n", + " if arr[pos] == ele:\n", + " found = True\n", + " \n", + " else:\n", + " \n", + " # Check if element is greater\n", + " if arr[pos] > ele:\n", + " stopped = True\n", + " \n", + " # Otherwise move on\n", + " else:\n", + " pos = pos+1\n", + " \n", + " return found" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "arr.sort() " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ordered_seq_search(arr,3)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ordered_seq_search(arr,1.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Stacks, Queues and Deques/.ipynb_checkpoints/Deques Overview-checkpoint.ipynb b/Stacks, Queues and Deques/.ipynb_checkpoints/Deques Overview-checkpoint.ipynb new file mode 100644 index 00000000..413f2635 --- /dev/null +++ b/Stacks, Queues and Deques/.ipynb_checkpoints/Deques Overview-checkpoint.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Deques Overview\n", + "\n", + "A deque, also known as a double-ended queue, is an ordered collection of items similar to the queue. It has two ends, a front and a rear, and the items remain positioned in the collection. What makes a deque different is the unrestrictive nature of adding and removing items. New items can be added at either the front or the rear. Likewise, existing items can be removed from either end. In a sense, this hybrid linear structure provides all the capabilities of stacks and queues in a single data structure. \n", + "\n", + "It is important to note that even though the deque can assume many of the characteristics of stacks and queues, it does not require the LIFO and FIFO orderings that are enforced by those data structures. It is up to you to make consistent use of the addition and removal operations.\n", + "\n", + "Let's see an Image to visualize the Deque Data Structure:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "Image('http://www.codeproject.com/KB/recipes/669131/deque.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we can both add and remove from the front and the back of the Deque. In the next lecture, we will implement our own Deque class!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Deque-checkpoint.ipynb b/Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Deque-checkpoint.ipynb new file mode 100644 index 00000000..9016eaa9 --- /dev/null +++ b/Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Deque-checkpoint.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Deque\n", + "\n", + "In this lecture we will implement our own Deque class!\n", + "\n", + "## Methods and Attributes\n", + "\n", + "* Deque() creates a new deque that is empty. It needs no parameters and returns an empty deque.\n", + "* addFront(item) adds a new item to the front of the deque. It needs the item and returns nothing.\n", + "* addRear(item) adds a new item to the rear of the deque. It needs the item and returns nothing.\n", + "* removeFront() removes the front item from the deque. It needs no parameters and returns the item. The deque is modified.\n", + "* removeRear() removes the rear item from the deque. It needs no parameters and returns the item. The deque is modified.\n", + "* isEmpty() tests to see whether the deque is empty. It needs no parameters and returns a boolean value.\n", + "* size() returns the number of items in the deque. It needs no parameters and returns an integer.\n", + "\n", + "## Deque Implementation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Deque:\n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def addFront(self, item):\n", + " self.items.append(item)\n", + "\n", + " def addRear(self, item):\n", + " self.items.insert(0,item)\n", + "\n", + " def removeFront(self):\n", + " return self.items.pop()\n", + "\n", + " def removeRear(self):\n", + " return self.items.pop(0)\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "d = Deque()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "d.addFront('hello')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "d.addRear('world')" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello world\n" + ] + } + ], + "source": [ + "print d.removeFront() + ' ' + d.removeRear()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d.size()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Queue-checkpoint.ipynb b/Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Queue-checkpoint.ipynb new file mode 100644 index 00000000..23c0e784 --- /dev/null +++ b/Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Queue-checkpoint.ipynb @@ -0,0 +1,181 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Queue\n", + "\n", + "In this lecture we will build on our previous understanding of Queues by implementing our own class of Queue!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "____\n", + "## Queue Methods and Attributes\n", + "\n", + "\n", + "Before we begin implementing our own queue, let's review the attribute and methods it will have:\n", + "\n", + "* Queue() creates a new queue that is empty. It needs no parameters and returns an empty queue.\n", + "* enqueue(item) adds a new item to the rear of the queue. It needs the item and returns nothing.\n", + "* dequeue() removes the front item from the queue. It needs no parameters and returns the item. The queue is modified.\n", + "* isEmpty() tests to see whether the queue is empty. It needs no parameters and returns a boolean value.\n", + "* size() returns the number of items in the queue. It needs no parameters and returns an integer." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "## Queue Implementation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue:\n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def enqueue(self, item):\n", + " self.items.insert(0,item)\n", + "\n", + " def dequeue(self):\n", + " return self.items.pop()\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "q = Queue()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "q.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "q.isEmpty()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "q.enqueue(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "q.dequeue()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Stack-checkpoint.ipynb b/Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Stack-checkpoint.ipynb new file mode 100644 index 00000000..fc3983dd --- /dev/null +++ b/Stacks, Queues and Deques/.ipynb_checkpoints/Implementation of Stack-checkpoint.ipynb @@ -0,0 +1,334 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Stack\n", + "\n", + "## Stack Attributes and Methods\n", + "\n", + "Before we implement our own Stack class, let's review the properties and methods of a Stack.\n", + "\n", + "The stack abstract data type is defined by the following structure and operations. A stack is structured, as described above, as an ordered collection of items where items are added to and removed from the end called the “top.” Stacks are ordered LIFO. The stack operations are given below.\n", + "\n", + "* Stack() creates a new stack that is empty. It needs no parameters and returns an empty stack.\n", + "* push(item) adds a new item to the top of the stack. It needs the item and returns nothing.\n", + "* pop() removes the top item from the stack. It needs no parameters and returns the item. The stack is modified.\n", + "* peek() returns the top item from the stack but does not remove it. It needs no parameters. The stack is not modified.\n", + "* isEmpty() tests to see whether the stack is empty. It needs no parameters and returns a boolean value.\n", + "* size() returns the number of items on the stack. It needs no parameters and returns an integer." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "\n", + "## Stack Implementation" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class Stack:\n", + " \n", + " \n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def push(self, item):\n", + " self.items.append(item)\n", + "\n", + " def pop(self):\n", + " return self.items.pop()\n", + "\n", + " def peek(self):\n", + " return self.items[len(self.items)-1]\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's try it out!" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "s = Stack()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print s.isEmpty()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "s.push(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "s.push('two')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'two'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.peek()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "s.push(True)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.isEmpty()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "two\n" + ] + } + ], + "source": [ + "s.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.isEmpty()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/.ipynb_checkpoints/Queues Overview-checkpoint.ipynb b/Stacks, Queues and Deques/.ipynb_checkpoints/Queues Overview-checkpoint.ipynb new file mode 100644 index 00000000..be7a713a --- /dev/null +++ b/Stacks, Queues and Deques/.ipynb_checkpoints/Queues Overview-checkpoint.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Queues Overview\n", + "\n", + "In this lecture we will get an overview of what a Queue is, in the next lecture we will implement our own Queue class." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "A **queue** is an ordered collection of items where the addition of new items happens at one end, called the “rear,” and the removal of existing items occurs at the other end, commonly called the “front.” As an element enters the queue it starts at the rear and makes its way toward the front, waiting until that time when it is the next element to be removed.\n", + "\n", + "The most recently added item in the queue must wait at the end of the collection. The item that has been in the collection the longest is at the front. This ordering principle is sometimes called **FIFO, first-in first-out**. It is also known as “first-come first-served.”\n", + "\n", + "The simplest example of a queue is the typical line that we all participate in from time to time. We wait in a line for a movie, we wait in the check-out line at a grocery store, and we wait in the cafeteria line. The first person in that line is also the first person to get serviced/helped. \n", + "\n", + "Let's see a diagram which shows this and compares it to the Stack Data Structure:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "url = 'https://netmatze.files.wordpress.com/2014/08/queue.png'\n", + "Image(url)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we have two terms here, **Enqueue** and **Dequeue**. The enqueue term describes when we add a new item to the rear of the queue. The dequeue term describes removing the front item from the queue.\n", + "\n", + "Let's take a look at how pop and push methods would work with a Queue (versus that of a Stack):" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEP\nERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4e\nHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCADwApUDASIA\nAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA\nAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3\nODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm\np6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA\nAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx\nBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK\nU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3\nuLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD7Looo\noAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig\nAooooAKKKKACiiigArwfw9ow1waxqOo694tadvEGrwgQ+J9QgjRI9QuI40WOOdUVVRFUAADAr3iv\nGvh//wAgvVv+xk1v/wBOl1WlJJvU5cXJxgmn1D/hD7D/AKDfjP8A8K/VP/kij/hD7D/oN+M//Cv1\nT/5IroqK35Y9jzva1P5mcb4g8NNZaTNcaTL411W9GBDbDxtqMIYk4yztcYVR1JAJwDhWOAcH4Q6L\nea34HhvvEfiDxVLqgvbyC4Nv4t1RYgY7mWMBP34O0BQATyQMnnNeoVzHwx0q/wBG8LPZalB5FwdS\n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\nDNgcgEYUnj23wzrNj4i8O6br2mOz2Wo2sd1bsy4Yo6hlyOxwarlet+m5HMna3Xb+v63NCiiikMKK\nKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo\noAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig\nAooooAKKKKACiiigAooooAKKKKACiiigAooooA82/aQ8Eat46+Gctj4dkjTXtOu4dT0vzGCq08LZ\nC5PAyCwBOBkjJAzXmfir9qjTNK8LQ+bp6aD4zs5Yzqvh3xBaXkMjRiPc6wSRROoZyVEbSYGDuYAY\nz9K0UtVdJ6PX5/0tR3Ts300/r9D5R+C2tJ8WfF3xR8T39xZ6T4l1bRm0XTvDss/+lW1uIuXYMqlg\nXKHIGAc5xkVyEfxO0WL9kG/+FS6frD+M9OsZ7XUdN+wyKbJEnLPPK5GxUUYGM7txC45zX2l/Zmm/\n2v8A2x/Z9p/aXkfZvtnkr53k7t3l78btm7nbnGeat0TSlBwWiat919fnd39Rxk1JSe6d/wAtPwVj\n5I+MvhK1vvAHwc8a6/4YvvE3hLRNDji16ysnkE0cElrGRONjKdqFSzHI6DJwcir4U0r9m/W/iB4d\n0/4SfDq98V34vY5ry+S+1K2t9JiQ7vPkaY4Y5HypjDEYyCQD9g0Valabku7f367+vo/Pa2co3jby\nt/S9D5d8JeO9F+D/AMcfihpPjODVYbrxDqMWpaHHbWEk7akHD7YoggOXLMEGcLuBBIIrlfAXhPXP\nHX7IHxB0bTLCRdYbxVdXS2LN87PG0DtDx1bAYD1OK+zKKzcbxs97Jfc00/wV+/331U7SbWzd/vvf\n82fDv/GKj+H1gsvhjrt545I8j/hExNqi3f2oEq0RbcUGCCSRkgfw7vlr7G+H+lxaL4H0XSoNHXRU\ntrKJBpy3TXItTtGYvNbl9pyNx64zW5RWnNo/P7v69b/55KNmvL7woooqSgooooAKKKKACiiigAoo\nooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiii\ngAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\nCiiigAooooAKKKKACiiigDifjh49Pw0+HF94vXSP7XNrJDGLX7T5G/zJFT7+1sY3Z6Vxy/EX46so\nYfs65BGR/wAVrZf/ABFRftu7v+GdNc2Y3fabPGemftEdSQ/8NS+Sm3/hTW3aMZ/tLNTB35r9Hb8E\n/wBRz05bdV+p6r4VvdW1Hw9ZXuu6L/YmpzRBrnT/ALUtx9nb+75ifK/1FadfNn7TOla3rnif4KaP\nqt+NP1a81KWG/udIdkEbNFEJjAz/ADKMb9pPI4PWubl+EfhjTP2m1+F+jT6tpngjV/Dq6rqmjW+o\nziO8eOR4wjuXL7SQCfmz1HArS15eraXbRc33W9SW1GKu+if3u35+h9b0V8//ALLVlH4Y+JHxW8A6\nTLcL4d0XUraTTbSWVpBbecjs6qzc44XqSeMkkkk+dfs9fBHw38SPhXq+q+J7zUpbwapew6M8V1Ii\naUQ+TLGikKzs/LFs5CoOMVF1bmW3LzfLT/MpqzcXupcv5/5H0n8ZfHtv8NvAdz4puNOl1ERTRQR2\n8cgj3vI4QZYg4HOScH6V2VfFPxHmT4h/sZeHfFvixH1HxDo+ojT4715XDMDciJ2IDYdmREyzAnOT\nwTmvTvjP4W0P4USfDPxp4ZsPsGkeFNVOn3UYkeTy7G8LLIxZyWIVmJGSeXqktbP+a33pW/Nfe+2p\nLa6WqTfzTaf5f1fT6IorxLwuP+E1/au8Ra8wEmm+CNLj0mzPO03dx+8mdfcJlD9RXttJaxUu/wDn\np96s/mJ/E12/y1+56fIKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiii\ngAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\nCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAPO/2i/A+sfEX\n4T6l4U0K4sLe/uZYJI5L13WIeXKrnJRWPRT2rnEX9qZEVR/wpnAGB/yEq9nopJWv56/p+g2728jy\nDXvAnxA8Va18MvEHiS58MRan4a1K4utWTT3nEEiONqCAOpYnaBncV5zita88BaxN+0jZfElbmwGk\nQeHG0poS7/aDKZmfcF27duGHO7Oe1ek0VV9vJt/euV/gS4338vwd/wAzzX4Z+AdY8M/Ff4ieLL+5\nsJLHxNcWstlHA7mWMRIyt5gKgA5YYwW/CvBf2ePDvxivfhbq0Pw/8S+GrTR9Y1W9iuhqsMxubBw+\nxpLYxgqxZcHD8AqMdSa+xKw/BPhLw/4L0VtG8M6f9gsWnkuDF50kn7xzlmy7E8ntnFKMY25Xty2/\nFb/JFyk23JbuV/wf+Z5n4y+CBm/Zug+FPhXU4Ybmy8mW3ur1SEmmWbzXZ9oJUMxboDjI64rX+I2n\napqn7OHiSy+KE+hw6gdJuXvZtL8z7JGybniZPM+ckbYzg9WzjtXqNcn8Qfhx4K8fyaY/jDQotWOl\nytLaCSWRVRm25yqsA4O1cq2QcdKmonUUk/tb/ldfhp5BTag4v+X/AIe339fM479kTwxd+HPglpdz\nqplfVtdd9XvnlOXZ5sbCc858sR5z3zXrtIoCqFUAADAA7Uta1Jc8mzKnHlikFFFFQWf/2Q==\n", + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url2 = 'http://www.csit.parkland.edu/~mbrandyberry/CS2Java/Lessons/Stack_Queue/images/QueuePushPop.jpg'\n", + "Image(url2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "You should now have a basic understanding of Queues and the FIFO principal for them. In the next lecture we will implement our own Queue class!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/.ipynb_checkpoints/Stacks Overview-checkpoint.ipynb b/Stacks, Queues and Deques/.ipynb_checkpoints/Stacks Overview-checkpoint.ipynb new file mode 100644 index 00000000..8089314d --- /dev/null +++ b/Stacks, Queues and Deques/.ipynb_checkpoints/Stacks Overview-checkpoint.ipynb @@ -0,0 +1,94 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Stacks Overview\n", + "\n", + "**Please see the lecture video for the full Overview on Stacks!**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "\n", + "A stack is an ordered collection of items where the addition of new items and the removal of existing items always takes place at the same end. This end is commonly referred to as the “top.” The end opposite the top is known as the “base.” \n", + "\n", + "The base of the stack is significant since items stored in the stack that are closer to the base represent those that have been in the stack the longest. The most recently added item is the one that is in position to be removed first. \n", + "\n", + "**This ordering principle is sometimes called LIFO, last-in first-out.** It provides an ordering based on length of time in the collection. Newer items are near the top, while older items are near the base.\n", + "\n", + "For example, consider the figure below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "url ='https://upload.wikimedia.org/wikipedia/commons/b/b4/Lifo_stack.png'\n", + "\n", + "Image(url)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how the first items \"pushed\" to the stack begin at the base, and as items are \"popped\" out. Stacks are fundamentally important, as they can be used to reverse the order of items. The order of insertion is the reverse of the order of removal.\n", + "\n", + "Considering this reversal property, you can perhaps think of examples of stacks that occur as you use your computer. For example, every web browser has a Back button. As you navigate from web page to web page, those pages are placed on a stack (actually it is the URLs that are going on the stack). The current page that you are viewing is on the top and the first page you looked at is at the base. If you click on the Back button, you begin to move in reverse order through the pages.\n", + "\n", + "In the next lecture we will implement our own Stack class!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Extra Resources:\n", + "[Wikipedia Page on Stacks](http://bit.ly/1OJybGQ)" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/.ipynb_checkpoints/Stacks, Queues, and Deques Overview-checkpoint.ipynb b/Stacks, Queues and Deques/.ipynb_checkpoints/Stacks, Queues, and Deques Overview-checkpoint.ipynb new file mode 100644 index 00000000..e020c9b7 --- /dev/null +++ b/Stacks, Queues and Deques/.ipynb_checkpoints/Stacks, Queues, and Deques Overview-checkpoint.ipynb @@ -0,0 +1,53 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Stacks, Queues, and Deques Overview" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this section of the course we will be learning about Stack, Queues, and Deques. These are linear structures. They are similar to arrays, but each of these structures differs by how it adds and removes items.\n", + "\n", + "Here's what to expect in this section:\n", + "\n", + " 1.) A Brief Overview of the Linear Structures\n", + " 2.) An Overview of Stacks\n", + " 3.) An Implementation of a Stack class\n", + " 4.) An Overview of Queues\n", + " 5.) An Implementation of a Queue class\n", + " 6.) An Overview of Deques\n", + " 7.) An Implementation of a Deque class\n", + " \n", + " Then finally a variety of interview questions based on Stacks, Queues, and Deques!\n", + " \n", + "**See the lecture video for a complete breakdown of this Section of the course!**" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Deques Overview.ipynb b/Stacks, Queues and Deques/Deques Overview.ipynb new file mode 100644 index 00000000..413f2635 --- /dev/null +++ b/Stacks, Queues and Deques/Deques Overview.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Deques Overview\n", + "\n", + "A deque, also known as a double-ended queue, is an ordered collection of items similar to the queue. It has two ends, a front and a rear, and the items remain positioned in the collection. What makes a deque different is the unrestrictive nature of adding and removing items. New items can be added at either the front or the rear. Likewise, existing items can be removed from either end. In a sense, this hybrid linear structure provides all the capabilities of stacks and queues in a single data structure. \n", + "\n", + "It is important to note that even though the deque can assume many of the characteristics of stacks and queues, it does not require the LIFO and FIFO orderings that are enforced by those data structures. It is up to you to make consistent use of the addition and removal operations.\n", + "\n", + "Let's see an Image to visualize the Deque Data Structure:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "Image('http://www.codeproject.com/KB/recipes/669131/deque.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we can both add and remove from the front and the back of the Deque. In the next lecture, we will implement our own Deque class!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Implementation of Deque.ipynb b/Stacks, Queues and Deques/Implementation of Deque.ipynb new file mode 100644 index 00000000..9016eaa9 --- /dev/null +++ b/Stacks, Queues and Deques/Implementation of Deque.ipynb @@ -0,0 +1,180 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Deque\n", + "\n", + "In this lecture we will implement our own Deque class!\n", + "\n", + "## Methods and Attributes\n", + "\n", + "* Deque() creates a new deque that is empty. It needs no parameters and returns an empty deque.\n", + "* addFront(item) adds a new item to the front of the deque. It needs the item and returns nothing.\n", + "* addRear(item) adds a new item to the rear of the deque. It needs the item and returns nothing.\n", + "* removeFront() removes the front item from the deque. It needs no parameters and returns the item. The deque is modified.\n", + "* removeRear() removes the rear item from the deque. It needs no parameters and returns the item. The deque is modified.\n", + "* isEmpty() tests to see whether the deque is empty. It needs no parameters and returns a boolean value.\n", + "* size() returns the number of items in the deque. It needs no parameters and returns an integer.\n", + "\n", + "## Deque Implementation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Deque:\n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def addFront(self, item):\n", + " self.items.append(item)\n", + "\n", + " def addRear(self, item):\n", + " self.items.insert(0,item)\n", + "\n", + " def removeFront(self):\n", + " return self.items.pop()\n", + "\n", + " def removeRear(self):\n", + " return self.items.pop(0)\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "d = Deque()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "d.addFront('hello')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "d.addRear('world')" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello world\n" + ] + } + ], + "source": [ + "print d.removeFront() + ' ' + d.removeRear()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d.size()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Implementation of Queue.ipynb b/Stacks, Queues and Deques/Implementation of Queue.ipynb new file mode 100644 index 00000000..23c0e784 --- /dev/null +++ b/Stacks, Queues and Deques/Implementation of Queue.ipynb @@ -0,0 +1,181 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Queue\n", + "\n", + "In this lecture we will build on our previous understanding of Queues by implementing our own class of Queue!" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "____\n", + "## Queue Methods and Attributes\n", + "\n", + "\n", + "Before we begin implementing our own queue, let's review the attribute and methods it will have:\n", + "\n", + "* Queue() creates a new queue that is empty. It needs no parameters and returns an empty queue.\n", + "* enqueue(item) adds a new item to the rear of the queue. It needs the item and returns nothing.\n", + "* dequeue() removes the front item from the queue. It needs no parameters and returns the item. The queue is modified.\n", + "* isEmpty() tests to see whether the queue is empty. It needs no parameters and returns a boolean value.\n", + "* size() returns the number of items in the queue. It needs no parameters and returns an integer." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "## Queue Implementation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue:\n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def enqueue(self, item):\n", + " self.items.insert(0,item)\n", + "\n", + " def dequeue(self):\n", + " return self.items.pop()\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "q = Queue()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "q.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "q.isEmpty()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "q.enqueue(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "q.dequeue()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Implementation of Stack.ipynb b/Stacks, Queues and Deques/Implementation of Stack.ipynb new file mode 100644 index 00000000..fc3983dd --- /dev/null +++ b/Stacks, Queues and Deques/Implementation of Stack.ipynb @@ -0,0 +1,334 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementation of Stack\n", + "\n", + "## Stack Attributes and Methods\n", + "\n", + "Before we implement our own Stack class, let's review the properties and methods of a Stack.\n", + "\n", + "The stack abstract data type is defined by the following structure and operations. A stack is structured, as described above, as an ordered collection of items where items are added to and removed from the end called the “top.” Stacks are ordered LIFO. The stack operations are given below.\n", + "\n", + "* Stack() creates a new stack that is empty. It needs no parameters and returns an empty stack.\n", + "* push(item) adds a new item to the top of the stack. It needs the item and returns nothing.\n", + "* pop() removes the top item from the stack. It needs no parameters and returns the item. The stack is modified.\n", + "* peek() returns the top item from the stack but does not remove it. It needs no parameters. The stack is not modified.\n", + "* isEmpty() tests to see whether the stack is empty. It needs no parameters and returns a boolean value.\n", + "* size() returns the number of items on the stack. It needs no parameters and returns an integer." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "\n", + "## Stack Implementation" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class Stack:\n", + " \n", + " \n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def push(self, item):\n", + " self.items.append(item)\n", + "\n", + " def pop(self):\n", + " return self.items.pop()\n", + "\n", + " def peek(self):\n", + " return self.items[len(self.items)-1]\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's try it out!" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "s = Stack()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print s.isEmpty()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "s.push(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "s.push('two')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'two'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.peek()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "s.push(True)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.isEmpty()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "two\n" + ] + } + ], + "source": [ + "s.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s.isEmpty()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Queues Overview.ipynb b/Stacks, Queues and Deques/Queues Overview.ipynb new file mode 100644 index 00000000..be7a713a --- /dev/null +++ b/Stacks, Queues and Deques/Queues Overview.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Queues Overview\n", + "\n", + "In this lecture we will get an overview of what a Queue is, in the next lecture we will implement our own Queue class." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "A **queue** is an ordered collection of items where the addition of new items happens at one end, called the “rear,” and the removal of existing items occurs at the other end, commonly called the “front.” As an element enters the queue it starts at the rear and makes its way toward the front, waiting until that time when it is the next element to be removed.\n", + "\n", + "The most recently added item in the queue must wait at the end of the collection. The item that has been in the collection the longest is at the front. This ordering principle is sometimes called **FIFO, first-in first-out**. It is also known as “first-come first-served.”\n", + "\n", + "The simplest example of a queue is the typical line that we all participate in from time to time. We wait in a line for a movie, we wait in the check-out line at a grocery store, and we wait in the cafeteria line. The first person in that line is also the first person to get serviced/helped. \n", + "\n", + "Let's see a diagram which shows this and compares it to the Stack Data Structure:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "url = 'https://netmatze.files.wordpress.com/2014/08/queue.png'\n", + "Image(url)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how we have two terms here, **Enqueue** and **Dequeue**. The enqueue term describes when we add a new item to the rear of the queue. The dequeue term describes removing the front item from the queue.\n", + "\n", + "Let's take a look at how pop and push methods would work with a Queue (versus that of a Stack):" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEP\nERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4e\nHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCADwApUDASIA\nAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA\nAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3\nODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm\np6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA\nAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx\nBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK\nU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3\nuLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD7Looo\noAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig\nAooooAKKKKACiiigArwfw9ow1waxqOo694tadvEGrwgQ+J9QgjRI9QuI40WOOdUVVRFUAADAr3iv\nGvh//wAgvVv+xk1v/wBOl1WlJJvU5cXJxgmn1D/hD7D/AKDfjP8A8K/VP/kij/hD7D/oN+M//Cv1\nT/5IroqK35Y9jzva1P5mcb4g8NNZaTNcaTL411W9GBDbDxtqMIYk4yztcYVR1JAJwDhWOAcH4Q6L\nea34HhvvEfiDxVLqgvbyC4Nv4t1RYgY7mWMBP34O0BQATyQMnnNeoVzHwx0q/wBG8LPZalB5FwdS\n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\nDNgcgEYUnj23wzrNj4i8O6br2mOz2Wo2sd1bsy4Yo6hlyOxwarlet+m5HMna3Xb+v63NCiiikMKK\nKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo\noAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig\nAooooAKKKKACiiigAooooAKKKKACiiigAooooA82/aQ8Eat46+Gctj4dkjTXtOu4dT0vzGCq08LZ\nC5PAyCwBOBkjJAzXmfir9qjTNK8LQ+bp6aD4zs5Yzqvh3xBaXkMjRiPc6wSRROoZyVEbSYGDuYAY\nz9K0UtVdJ6PX5/0tR3Ts300/r9D5R+C2tJ8WfF3xR8T39xZ6T4l1bRm0XTvDss/+lW1uIuXYMqlg\nXKHIGAc5xkVyEfxO0WL9kG/+FS6frD+M9OsZ7XUdN+wyKbJEnLPPK5GxUUYGM7txC45zX2l/Zmm/\n2v8A2x/Z9p/aXkfZvtnkr53k7t3l78btm7nbnGeat0TSlBwWiat919fnd39Rxk1JSe6d/wAtPwVj\n5I+MvhK1vvAHwc8a6/4YvvE3hLRNDji16ysnkE0cElrGRONjKdqFSzHI6DJwcir4U0r9m/W/iB4d\n0/4SfDq98V34vY5ry+S+1K2t9JiQ7vPkaY4Y5HypjDEYyCQD9g0Valabku7f367+vo/Pa2co3jby\nt/S9D5d8JeO9F+D/AMcfihpPjODVYbrxDqMWpaHHbWEk7akHD7YoggOXLMEGcLuBBIIrlfAXhPXP\nHX7IHxB0bTLCRdYbxVdXS2LN87PG0DtDx1bAYD1OK+zKKzcbxs97Jfc00/wV+/331U7SbWzd/vvf\n82fDv/GKj+H1gsvhjrt545I8j/hExNqi3f2oEq0RbcUGCCSRkgfw7vlr7G+H+lxaL4H0XSoNHXRU\ntrKJBpy3TXItTtGYvNbl9pyNx64zW5RWnNo/P7v69b/55KNmvL7woooqSgooooAKKKKACiiigAoo\nooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiii\ngAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\nCiiigAooooAKKKKACiiigDifjh49Pw0+HF94vXSP7XNrJDGLX7T5G/zJFT7+1sY3Z6Vxy/EX46so\nYfs65BGR/wAVrZf/ABFRftu7v+GdNc2Y3fabPGemftEdSQ/8NS+Sm3/hTW3aMZ/tLNTB35r9Hb8E\n/wBRz05bdV+p6r4VvdW1Hw9ZXuu6L/YmpzRBrnT/ALUtx9nb+75ifK/1FadfNn7TOla3rnif4KaP\nqt+NP1a81KWG/udIdkEbNFEJjAz/ADKMb9pPI4PWubl+EfhjTP2m1+F+jT6tpngjV/Dq6rqmjW+o\nziO8eOR4wjuXL7SQCfmz1HArS15eraXbRc33W9SW1GKu+if3u35+h9b0V8//ALLVlH4Y+JHxW8A6\nTLcL4d0XUraTTbSWVpBbecjs6qzc44XqSeMkkkk+dfs9fBHw38SPhXq+q+J7zUpbwapew6M8V1Ii\naUQ+TLGikKzs/LFs5CoOMVF1bmW3LzfLT/MpqzcXupcv5/5H0n8ZfHtv8NvAdz4puNOl1ERTRQR2\n8cgj3vI4QZYg4HOScH6V2VfFPxHmT4h/sZeHfFvixH1HxDo+ojT4715XDMDciJ2IDYdmREyzAnOT\nwTmvTvjP4W0P4USfDPxp4ZsPsGkeFNVOn3UYkeTy7G8LLIxZyWIVmJGSeXqktbP+a33pW/Nfe+2p\nLa6WqTfzTaf5f1fT6IorxLwuP+E1/au8Ra8wEmm+CNLj0mzPO03dx+8mdfcJlD9RXttJaxUu/wDn\np96s/mJ/E12/y1+56fIKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiii\ngAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\nCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAPO/2i/A+sfEX\n4T6l4U0K4sLe/uZYJI5L13WIeXKrnJRWPRT2rnEX9qZEVR/wpnAGB/yEq9nopJWv56/p+g2728jy\nDXvAnxA8Va18MvEHiS58MRan4a1K4utWTT3nEEiONqCAOpYnaBncV5zita88BaxN+0jZfElbmwGk\nQeHG0poS7/aDKZmfcF27duGHO7Oe1ek0VV9vJt/euV/gS4338vwd/wAzzX4Z+AdY8M/Ff4ieLL+5\nsJLHxNcWstlHA7mWMRIyt5gKgA5YYwW/CvBf2ePDvxivfhbq0Pw/8S+GrTR9Y1W9iuhqsMxubBw+\nxpLYxgqxZcHD8AqMdSa+xKw/BPhLw/4L0VtG8M6f9gsWnkuDF50kn7xzlmy7E8ntnFKMY25Xty2/\nFb/JFyk23JbuV/wf+Z5n4y+CBm/Zug+FPhXU4Ybmy8mW3ur1SEmmWbzXZ9oJUMxboDjI64rX+I2n\napqn7OHiSy+KE+hw6gdJuXvZtL8z7JGybniZPM+ckbYzg9WzjtXqNcn8Qfhx4K8fyaY/jDQotWOl\nytLaCSWRVRm25yqsA4O1cq2QcdKmonUUk/tb/ldfhp5BTag4v+X/AIe339fM479kTwxd+HPglpdz\nqplfVtdd9XvnlOXZ5sbCc858sR5z3zXrtIoCqFUAADAA7Uta1Jc8mzKnHlikFFFFQWf/2Q==\n", + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url2 = 'http://www.csit.parkland.edu/~mbrandyberry/CS2Java/Lessons/Stack_Queue/images/QueuePushPop.jpg'\n", + "Image(url2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "You should now have a basic understanding of Queues and the FIFO principal for them. In the next lecture we will implement our own Queue class!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks Overview.ipynb b/Stacks, Queues and Deques/Stacks Overview.ipynb new file mode 100644 index 00000000..8089314d --- /dev/null +++ b/Stacks, Queues and Deques/Stacks Overview.ipynb @@ -0,0 +1,94 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Stacks Overview\n", + "\n", + "**Please see the lecture video for the full Overview on Stacks!**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "____\n", + "\n", + "A stack is an ordered collection of items where the addition of new items and the removal of existing items always takes place at the same end. This end is commonly referred to as the “top.” The end opposite the top is known as the “base.” \n", + "\n", + "The base of the stack is significant since items stored in the stack that are closer to the base represent those that have been in the stack the longest. The most recently added item is the one that is in position to be removed first. \n", + "\n", + "**This ordering principle is sometimes called LIFO, last-in first-out.** It provides an ordering based on length of time in the collection. Newer items are near the top, while older items are near the base.\n", + "\n", + "For example, consider the figure below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "url ='https://upload.wikimedia.org/wikipedia/commons/b/b4/Lifo_stack.png'\n", + "\n", + "Image(url)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how the first items \"pushed\" to the stack begin at the base, and as items are \"popped\" out. Stacks are fundamentally important, as they can be used to reverse the order of items. The order of insertion is the reverse of the order of removal.\n", + "\n", + "Considering this reversal property, you can perhaps think of examples of stacks that occur as you use your computer. For example, every web browser has a Back button. As you navigate from web page to web page, those pages are placed on a stack (actually it is the URLs that are going on the stack). The current page that you are viewing is on the top and the first page you looked at is at the base. If you click on the Back button, you begin to move in reverse order through the pages.\n", + "\n", + "In the next lecture we will implement our own Stack class!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Extra Resources:\n", + "[Wikipedia Page on Stacks](http://bit.ly/1OJybGQ)" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Balanced Parentheses Check -checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Balanced Parentheses Check -checkpoint.ipynb new file mode 100644 index 00000000..40a0f8e4 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Balanced Parentheses Check -checkpoint.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Balanced Parentheses Check \n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string of opening and closing parentheses, check whether it’s balanced. We have 3 types of parentheses: round brackets: (), square brackets: [], and curly brackets: {}. Assume that the string doesn’t contain any other character than these, no spaces words or numbers. As a reminder, balanced parentheses require every opening parenthesis to be closed in the reverse order opened. For example ‘([])’ is balanced but ‘([)]’ is not. \n", + "\n", + "\n", + "You can assume the input string has no spaces.\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def balance_check(s):\n", + " chars = []\n", + " matches = {')':'(',']':'[','}':'{'}\n", + " for c in s:\n", + " if c in matches:\n", + " if chars.pop() != matches[c]:\n", + " return False\n", + " else:\n", + " chars.append(c)\n", + " return chars == [] \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[]')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[](){([[[]]])}')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('()(){]}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestBalanceCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('[](){([[[]]])}('),False)\n", + " assert_equal(sol('[{{{(())}}}]((()))'),True)\n", + " assert_equal(sol('[[[]])]'),False)\n", + " print ('ALL TEST CASES PASSED')\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestBalanceCheck()\n", + "t.test(balance_check)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Deque -checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Deque -checkpoint.ipynb new file mode 100644 index 00000000..d5c255f7 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Deque -checkpoint.ipynb @@ -0,0 +1,51 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Deque \n", + "\n", + "Finally, implement a Deque class! It should be able to do the following:\n", + "\n", + "* Check if its empty\n", + "* Add to both front and rear\n", + "* Remove from Front and Rear\n", + "* Check the Size" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Deque(object):\n", + " pass" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Queue -Using Two Stacks -checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Queue -Using Two Stacks -checkpoint.ipynb new file mode 100644 index 00000000..521c8245 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Queue -Using Two Stacks -checkpoint.ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue - Using Two Stacks\n", + "\n", + "Given the Stack class below, implement a Queue class using **two** stacks! Note, this is a \"classic\" interview problem. Use a Python list data structure as your Stack." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Uses lists instead of your own Stack class.\n", + "stack1 = []\n", + "stack2 = []" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "class Queue2Stacks(object):\n", + " \n", + " def __init__(self):\n", + " \n", + " # Two Stacks\n", + " self.in_stack = []\n", + " self.out_stack = []\n", + " \n", + " def enqueue(self, element):\n", + " # FILL OUT CODE HERE\n", + " self.in_stack.append(element)\n", + " pass\n", + " \n", + " def dequeue(self):\n", + " \n", + " # FILL OUT CODE HERE\n", + " if not self.out_stack:\n", + " while self.in_stack:\n", + " self.out_stack.append(self.in_stack.pop())\n", + " return self.out_stack.pop()\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "You should be able to tell with your current knowledge of Stacks and Queues if this is working as it should. For example, the following should print as such:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO CHECK THAT YOUR SOLUTION OUTPUT MAKES SENSE AND BEHAVES AS A QUEUE\n", + "\"\"\"\n", + "q = Queue2Stacks()\n", + "\n", + "for i in range(5):\n", + " q.enqueue(i)\n", + " \n", + "for i in range(5):\n", + " print (q.dequeue())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Queue-checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Queue-checkpoint.ipynb new file mode 100644 index 00000000..2a758805 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Queue-checkpoint.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue\n", + "\n", + "It's very common to be asked to implement a Queue class! The class should be able to do the following:\n", + "\n", + "* Check if Queue is Empty\n", + "* Enqueue\n", + "* Dequeue\n", + "* Return the size of the Queue" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "class Queue(object):\n", + " def __init__(self):\n", + " self.items = []\n", + " def is_empty(self):\n", + " return self.items == []\n", + " def enqueue(self, e):\n", + " self.items.insert(0, e)\n", + " def dequeue(self):\n", + " return self.items.pop()\n", + " def size(self):\n", + " return len(self.items)\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "two\n", + "3\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "q = Queue()\n", + "q.is_empty()\n", + "q.enqueue(1)\n", + "q.enqueue('two')\n", + "q.enqueue(3)\n", + "q.size()\n", + "print(q.dequeue())\n", + "print(q.dequeue())\n", + "print(q.dequeue())\n", + "q.is_empty()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Stack -checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Stack -checkpoint.ipynb new file mode 100644 index 00000000..d0f206c3 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/.ipynb_checkpoints/Implement a Stack -checkpoint.ipynb @@ -0,0 +1,228 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Stack \n", + "\n", + "A very common interview question is to begin by just implementing a Stack! Try your best to implement your own stack!\n", + "\n", + "It should have the methods:\n", + "\n", + "* Check if its empty\n", + "* Push a new item\n", + "* Pop an item\n", + "* Peek at the top item\n", + "* Return the size" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [], + "source": [ + "class Stack(object):\n", + " # Fill out the Stack Methods here\n", + " def __init__(self):\n", + " self.items = []\n", + " def isEmpty(self):\n", + " return len(self.items) == 0\n", + " def push(self, e):\n", + " self.items.append(e)\n", + " def pop(self):\n", + " return self.items.pop()\n", + " def size(self):\n", + " return len(self.items)\n", + " def peek(self):\n", + " return self.items[self.size()-1] # reuse the size funtion\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [], + "source": [ + "stack = Stack()" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [], + "source": [ + "stack.push(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [], + "source": [ + "stack.push(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [], + "source": [ + "stack.push('Three')" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Three'" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.isEmpty()" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.peek()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Balanced Parentheses Check .ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Balanced Parentheses Check .ipynb new file mode 100644 index 00000000..40a0f8e4 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Balanced Parentheses Check .ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Balanced Parentheses Check \n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string of opening and closing parentheses, check whether it’s balanced. We have 3 types of parentheses: round brackets: (), square brackets: [], and curly brackets: {}. Assume that the string doesn’t contain any other character than these, no spaces words or numbers. As a reminder, balanced parentheses require every opening parenthesis to be closed in the reverse order opened. For example ‘([])’ is balanced but ‘([)]’ is not. \n", + "\n", + "\n", + "You can assume the input string has no spaces.\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def balance_check(s):\n", + " chars = []\n", + " matches = {')':'(',']':'[','}':'{'}\n", + " for c in s:\n", + " if c in matches:\n", + " if chars.pop() != matches[c]:\n", + " return False\n", + " else:\n", + " chars.append(c)\n", + " return chars == [] \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[]')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[](){([[[]]])}')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('()(){]}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestBalanceCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('[](){([[[]]])}('),False)\n", + " assert_equal(sol('[{{{(())}}}]((()))'),True)\n", + " assert_equal(sol('[[[]])]'),False)\n", + " print ('ALL TEST CASES PASSED')\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestBalanceCheck()\n", + "t.test(balance_check)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Deque .ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Deque .ipynb new file mode 100644 index 00000000..2fd35590 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Deque .ipynb @@ -0,0 +1,206 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Deque \n", + "\n", + "Finally, implement a Deque class! It should be able to do the following:\n", + "\n", + "* Check if its empty\n", + "* Add to both front and rear\n", + "* Remove from Front and Rear\n", + "* Check the Size" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "class Deque(object):\n", + " def __init__(self):\n", + " self.items = []\n", + " def is_empty(self):\n", + " return self.items == []\n", + " def add_front(self, e):\n", + " self.items.insert(0, e)\n", + " def add_rear(self, e):\n", + " self.items.append(e)\n", + " def remove_front(self):\n", + " return self.items.pop(0)\n", + " def remove_rear(self):\n", + " return self.items.pop()\n", + " def size(self):\n", + " return len(self.items)\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "deq = Deque()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "deq.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "deq.add_front(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "deq.add_front(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "deq.add_rear(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "deq.remove_front()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "deq.remove_rear()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "deq.remove_rear()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "deq.is_empty()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Queue -Using Two Stacks .ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Queue -Using Two Stacks .ipynb new file mode 100644 index 00000000..521c8245 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Queue -Using Two Stacks .ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue - Using Two Stacks\n", + "\n", + "Given the Stack class below, implement a Queue class using **two** stacks! Note, this is a \"classic\" interview problem. Use a Python list data structure as your Stack." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Uses lists instead of your own Stack class.\n", + "stack1 = []\n", + "stack2 = []" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "class Queue2Stacks(object):\n", + " \n", + " def __init__(self):\n", + " \n", + " # Two Stacks\n", + " self.in_stack = []\n", + " self.out_stack = []\n", + " \n", + " def enqueue(self, element):\n", + " # FILL OUT CODE HERE\n", + " self.in_stack.append(element)\n", + " pass\n", + " \n", + " def dequeue(self):\n", + " \n", + " # FILL OUT CODE HERE\n", + " if not self.out_stack:\n", + " while self.in_stack:\n", + " self.out_stack.append(self.in_stack.pop())\n", + " return self.out_stack.pop()\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "You should be able to tell with your current knowledge of Stacks and Queues if this is working as it should. For example, the following should print as such:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO CHECK THAT YOUR SOLUTION OUTPUT MAKES SENSE AND BEHAVES AS A QUEUE\n", + "\"\"\"\n", + "q = Queue2Stacks()\n", + "\n", + "for i in range(5):\n", + " q.enqueue(i)\n", + " \n", + "for i in range(5):\n", + " print (q.dequeue())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Queue.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Queue.ipynb new file mode 100644 index 00000000..2a758805 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Queue.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue\n", + "\n", + "It's very common to be asked to implement a Queue class! The class should be able to do the following:\n", + "\n", + "* Check if Queue is Empty\n", + "* Enqueue\n", + "* Dequeue\n", + "* Return the size of the Queue" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "class Queue(object):\n", + " def __init__(self):\n", + " self.items = []\n", + " def is_empty(self):\n", + " return self.items == []\n", + " def enqueue(self, e):\n", + " self.items.insert(0, e)\n", + " def dequeue(self):\n", + " return self.items.pop()\n", + " def size(self):\n", + " return len(self.items)\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "two\n", + "3\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "q = Queue()\n", + "q.is_empty()\n", + "q.enqueue(1)\n", + "q.enqueue('two')\n", + "q.enqueue(3)\n", + "q.size()\n", + "print(q.dequeue())\n", + "print(q.dequeue())\n", + "print(q.dequeue())\n", + "q.is_empty()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Stack .ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Stack .ipynb new file mode 100644 index 00000000..d0f206c3 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions - PRACTICE/Implement a Stack .ipynb @@ -0,0 +1,228 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Stack \n", + "\n", + "A very common interview question is to begin by just implementing a Stack! Try your best to implement your own stack!\n", + "\n", + "It should have the methods:\n", + "\n", + "* Check if its empty\n", + "* Push a new item\n", + "* Pop an item\n", + "* Peek at the top item\n", + "* Return the size" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [], + "source": [ + "class Stack(object):\n", + " # Fill out the Stack Methods here\n", + " def __init__(self):\n", + " self.items = []\n", + " def isEmpty(self):\n", + " return len(self.items) == 0\n", + " def push(self, e):\n", + " self.items.append(e)\n", + " def pop(self):\n", + " return self.items.pop()\n", + " def size(self):\n", + " return len(self.items)\n", + " def peek(self):\n", + " return self.items[self.size()-1] # reuse the size funtion\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [], + "source": [ + "stack = Stack()" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [], + "source": [ + "stack.push(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [], + "source": [ + "stack.push(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [], + "source": [ + "stack.push('Three')" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Three'" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.isEmpty()" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "stack.peek()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Balanced Parentheses Check - SOLUTION-checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Balanced Parentheses Check - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..a4cf7848 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Balanced Parentheses Check - SOLUTION-checkpoint.ipynb @@ -0,0 +1,212 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Balanced Parentheses Check - SOLUTION\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string of opening and closing parentheses, check whether it’s balanced. We have 3 types of parentheses: round brackets: (), square brackets: [], and curly brackets: {}. Assume that the string doesn’t contain any other character than these, no spaces words or numbers. As a reminder, balanced parentheses require every opening parenthesis to be closed in the reverse order opened. For example ‘([])’ is balanced but ‘([)]’ is not. \n", + "\n", + "\n", + "You can assume the input string has no spaces.\n", + "\n", + "## Solution\n", + "\n", + "This is a very common interview question and is one of the main ways to check your knowledge of using Stacks! We will start our solution logic as such:\n", + "\n", + "First we will scan the string from left to right, and every time we see an opening parenthesis we push it to a stack, because we want the last opening parenthesis to be closed first. (Remember the FILO structure of a stack!)\n", + "\n", + "Then, when we see a closing parenthesis we check whether the last opened one is the corresponding closing match, by popping an element from the stack. If it’s a valid match, then we proceed forward, if not return false. \n", + "\n", + "Or if the stack is empty we also return false, because there’s no opening parenthesis associated with this closing one. In the end, we also check whether the stack is empty. If so, we return true, otherwise return false because there were some opened parenthesis that were not closed. \n", + "\n", + "Here's an example solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def balance_check(s):\n", + " \n", + " # Check is even number of brackets\n", + " if len(s)%2 != 0:\n", + " return False\n", + " \n", + " # Set of opening brackets\n", + " opening = set('([{') \n", + " \n", + " # Matching Pairs\n", + " matches = set([ ('(',')'), ('[',']'), ('{','}') ]) \n", + " \n", + " # Use a list as a \"Stack\"\n", + " stack = []\n", + " \n", + " # Check every parenthesis in string\n", + " for paren in s:\n", + " \n", + " # If its an opening, append it to list\n", + " if paren in opening:\n", + " stack.append(paren)\n", + " \n", + " else:\n", + " \n", + " # Check that there are parentheses in Stack\n", + " if len(stack) == 0:\n", + " return False\n", + " \n", + " # Check the last open parenthesis\n", + " last_open = stack.pop()\n", + " \n", + " # Check if it has a closing match\n", + " if (last_open,paren) not in matches:\n", + " return False\n", + " \n", + " return len(stack) == 0" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[]')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[](){([[[]]])}')" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('()(){]}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestBalanceCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('[](){([[[]]])}('),False)\n", + " assert_equal(sol('[{{{(())}}}]((()))'),True)\n", + " assert_equal(sol('[[[]])]'),False)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestBalanceCheck()\n", + "t.test(balance_check)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Deque - SOLUTION-checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Deque - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..af87180e --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Deque - SOLUTION-checkpoint.ipynb @@ -0,0 +1,65 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Deque - SOLUTION\n", + "\n", + "**Please refer to the Implementation of Deque lecture for a full explanation. The code from that lecture is below:**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Deque:\n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def addFront(self, item):\n", + " self.items.append(item)\n", + "\n", + " def addRear(self, item):\n", + " self.items.insert(0,item)\n", + "\n", + " def removeFront(self):\n", + " return self.items.pop()\n", + "\n", + " def removeRear(self):\n", + " return self.items.pop(0)\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Queue - SOLUTION-checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Queue - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..a400bb3d --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Queue - SOLUTION-checkpoint.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue - SOLUTION\n", + "\n", + "**Please refer to the Implementation of Queue lecture for a full explanation. The code from that lecture is below:**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue:\n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def enqueue(self, item):\n", + " self.items.insert(0,item)\n", + "\n", + " def dequeue(self):\n", + " return self.items.pop()\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Queue -Using Two Stacks - SOLUTION-checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Queue -Using Two Stacks - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..e66de679 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Queue -Using Two Stacks - SOLUTION-checkpoint.ipynb @@ -0,0 +1,134 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue - Using Two Stacks - SOLUTION\n", + "\n", + "Given the Stack class below, implement a Queue class using **two** stacks! Note, this is a \"classic\" interview problem. Use a Python list data structure as your Stack." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "stack1 = []\n", + "stack2 = []" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "The key insight is that a stack reverses order (while a queue doesn't). A sequence of elements pushed on a stack comes back in reversed order when popped. Consequently, two stacks chained together will return elements in the same order, since reversed order reversed again is original order.\n", + "\n", + " We use an in-stack that we fill when an element is enqueued and the dequeue operation takes elements from an out-stack. If the out-stack is empty we pop all elements from the in-stack and push them onto the out-stack. " + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue2Stacks(object):\n", + " \n", + " def __init__(self):\n", + " \n", + " # Two Stacks\n", + " self.instack = []\n", + " self.outstack = []\n", + " \n", + " def enqueue(self,element):\n", + " \n", + " # Add an enqueue with the \"IN\" stack\n", + " self.instack.append(element)\n", + " \n", + " def dequeue(self):\n", + " if not self.outstack:\n", + " while self.instack:\n", + " # Add the elements to the outstack to reverse the order when called\n", + " self.outstack.append(self.instack.pop())\n", + " return self.outstack.pop() " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "You should be able to tell with your current knowledge of Stacks and Queues if this is working as it should. For example, the following should print as such:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO CHECK THAT YOUR SOLUTION OUTPUT MAKES SENSE AND BEHAVES AS A QUEUE\n", + "\"\"\"\n", + "q = Queue2Stacks()\n", + "\n", + "for i in xrange(5):\n", + " q.enqueue(i)\n", + " \n", + "for i in xrange(5):\n", + " print q.dequeue()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Stack - SOLUTION-checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Stack - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..cb9fd690 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/.ipynb_checkpoints/Implement a Stack - SOLUTION-checkpoint.ipynb @@ -0,0 +1,63 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Stack -SOLUTION\n", + "\n", + "**Please refer to the lecture on implementation for a full explanation. Here is the code from that lecture:**" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Stack(object):\n", + " \n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def push(self, item):\n", + " self.items.append(item)\n", + "\n", + " def pop(self):\n", + " return self.items.pop()\n", + "\n", + " def peek(self):\n", + " return self.items[len(self.items)-1]\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Balanced Parentheses Check - SOLUTION.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Balanced Parentheses Check - SOLUTION.ipynb new file mode 100644 index 00000000..2c988d8f --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Balanced Parentheses Check - SOLUTION.ipynb @@ -0,0 +1,204 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Balanced Parentheses Check - SOLUTION\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string of opening and closing parentheses, check whether it’s balanced. We have 3 types of parentheses: round brackets: (), square brackets: [], and curly brackets: {}. Assume that the string doesn’t contain any other character than these, no spaces words or numbers. As a reminder, balanced parentheses require every opening parenthesis to be closed in the reverse order opened. For example ‘([])’ is balanced but ‘([)]’ is not. \n", + "\n", + "\n", + "You can assume the input string has no spaces.\n", + "\n", + "## Solution\n", + "\n", + "This is a very common interview question and is one of the main ways to check your knowledge of using Stacks! We will start our solution logic as such:\n", + "\n", + "First we will scan the string from left to right, and every time we see an opening parenthesis we push it to a stack, because we want the last opening parenthesis to be closed first. (Remember the FILO structure of a stack!)\n", + "\n", + "Then, when we see a closing parenthesis we check whether the last opened one is the corresponding closing match, by popping an element from the stack. If it’s a valid match, then we proceed forward, if not return false. \n", + "\n", + "Or if the stack is empty we also return false, because there’s no opening parenthesis associated with this closing one. In the end, we also check whether the stack is empty. If so, we return true, otherwise return false because there were some opened parenthesis that were not closed. \n", + "\n", + "Here's an example solution:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def balance_check(s):\n", + " \n", + " # Check is even number of brackets\n", + " if len(s)%2 != 0:\n", + " return False\n", + " \n", + " # Set of opening brackets\n", + " opening = set('([{') \n", + " \n", + " # Matching Pairs\n", + " matches = set([ ('(',')'), ('[',']'), ('{','}') ]) \n", + " \n", + " # Use a list as a \"Stack\"\n", + " stack = []\n", + " \n", + " # Check every parenthesis in string\n", + " for paren in s:\n", + " \n", + " # If its an opening, append it to list\n", + " if paren in opening:\n", + " stack.append(paren)\n", + " \n", + " else:\n", + " \n", + " # Check that there are parentheses in Stack\n", + " if len(stack) == 0:\n", + " return False\n", + " \n", + " # Check the last open parenthesis\n", + " last_open = stack.pop()\n", + " \n", + " # Check if it has a closing match\n", + " if (last_open,paren) not in matches:\n", + " return False\n", + " \n", + " return len(stack) == 0" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[]')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[](){([[[]]])}')" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('()(){]}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestBalanceCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('[](){([[[]]])}('),False)\n", + " assert_equal(sol('[{{{(())}}}]((()))'),True)\n", + " assert_equal(sol('[[[]])]'),False)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestBalanceCheck()\n", + "t.test(balance_check)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Deque - SOLUTION.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Deque - SOLUTION.ipynb new file mode 100644 index 00000000..a876e02b --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Deque - SOLUTION.ipynb @@ -0,0 +1,65 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Deque - SOLUTION\n", + "\n", + "**Please refer to the Implementation of Deque lecture for a full explanation. The code from that lecture is below:**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Deque:\n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def addFront(self, item):\n", + " self.items.append(item)\n", + "\n", + " def addRear(self, item):\n", + " self.items.insert(0,item)\n", + "\n", + " def removeFront(self):\n", + " return self.items.pop()\n", + "\n", + " def removeRear(self):\n", + " return self.items.pop(0)\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Queue - SOLUTION.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Queue - SOLUTION.ipynb new file mode 100644 index 00000000..0a2f2cdd --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Queue - SOLUTION.ipynb @@ -0,0 +1,59 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue - SOLUTION\n", + "\n", + "**Please refer to the Implementation of Queue lecture for a full explanation. The code from that lecture is below:**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue:\n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def enqueue(self, item):\n", + " self.items.insert(0,item)\n", + "\n", + " def dequeue(self):\n", + " return self.items.pop()\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Queue -Using Two Stacks - SOLUTION.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Queue -Using Two Stacks - SOLUTION.ipynb new file mode 100644 index 00000000..74ca5fee --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Queue -Using Two Stacks - SOLUTION.ipynb @@ -0,0 +1,132 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue - Using Two Stacks - SOLUTION\n", + "\n", + "Given the Stack class below, implement a Queue class using **two** stacks! Note, this is a \"classic\" interview problem. Use a Python list data structure as your Stack." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "stack1 = []\n", + "stack2 = []" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "The key insight is that a stack reverses order (while a queue doesn't). A sequence of elements pushed on a stack comes back in reversed order when popped. Consequently, two stacks chained together will return elements in the same order, since reversed order reversed again is original order.\n", + "\n", + " We use an in-stack that we fill when an element is enqueued and the dequeue operation takes elements from an out-stack. If the out-stack is empty we pop all elements from the in-stack and push them onto the out-stack. " + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue2Stacks(object):\n", + " \n", + " def __init__(self):\n", + " \n", + " # Two Stacks\n", + " self.instack = []\n", + " self.outstack = []\n", + " \n", + " def enqueue(self,element):\n", + " \n", + " # Add an enqueue with the \"IN\" stack\n", + " self.instack.append(element)\n", + " \n", + " def dequeue(self):\n", + " if not self.outstack:\n", + " while self.instack:\n", + " # Add the elements to the outstack to reverse the order when called\n", + " self.outstack.append(self.instack.pop())\n", + " return self.outstack.pop() " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "You should be able to tell with your current knowledge of Stacks and Queues if this is working as it should. For example, the following should print as such:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO CHECK THAT YOUR SOLUTION OUTPUT MAKES SENSE AND BEHAVES AS A QUEUE\n", + "\"\"\"\n", + "q = Queue2Stacks()\n", + "\n", + "for i in xrange(5):\n", + " q.enqueue(i)\n", + " \n", + "for i in xrange(5):\n", + " print q.dequeue()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Stack - SOLUTION.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Stack - SOLUTION.ipynb new file mode 100644 index 00000000..72f8e3ca --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions -SOLUTIONS/Implement a Stack - SOLUTION.ipynb @@ -0,0 +1,63 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Stack -SOLUTION\n", + "\n", + "**Please refer to the lecture on implementation for a full explanation. Here is the code from that lecture:**" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Stack(object):\n", + " \n", + " def __init__(self):\n", + " self.items = []\n", + "\n", + " def isEmpty(self):\n", + " return self.items == []\n", + "\n", + " def push(self, item):\n", + " self.items.append(item)\n", + "\n", + " def pop(self):\n", + " return self.items.pop()\n", + "\n", + " def peek(self):\n", + " return self.items[len(self.items)-1]\n", + "\n", + " def size(self):\n", + " return len(self.items)" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Balanced Parentheses Check -checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Balanced Parentheses Check -checkpoint.ipynb new file mode 100644 index 00000000..274f3ace --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Balanced Parentheses Check -checkpoint.ipynb @@ -0,0 +1,171 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Balanced Parentheses Check \n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string of opening and closing parentheses, check whether it’s balanced. We have 3 types of parentheses: round brackets: (), square brackets: [], and curly brackets: {}. Assume that the string doesn’t contain any other character than these, no spaces words or numbers. As a reminder, balanced parentheses require every opening parenthesis to be closed in the reverse order opened. For example ‘([])’ is balanced but ‘([)]’ is not. \n", + "\n", + "\n", + "You can assume the input string has no spaces.\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def balance_check(s):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[]')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[](){([[[]]])}')" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('()(){]}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestBalanceCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('[](){([[[]]])}('),False)\n", + " assert_equal(sol('[{{{(())}}}]((()))'),True)\n", + " assert_equal(sol('[[[]])]'),False)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestBalanceCheck()\n", + "t.test(balance_check)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Deque -checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Deque -checkpoint.ipynb new file mode 100644 index 00000000..d5c255f7 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Deque -checkpoint.ipynb @@ -0,0 +1,51 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Deque \n", + "\n", + "Finally, implement a Deque class! It should be able to do the following:\n", + "\n", + "* Check if its empty\n", + "* Add to both front and rear\n", + "* Remove from Front and Rear\n", + "* Check the Size" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Deque(object):\n", + " pass" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Queue -Using Two Stacks -checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Queue -Using Two Stacks -checkpoint.ipynb new file mode 100644 index 00000000..907956a6 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Queue -Using Two Stacks -checkpoint.ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue - Using Two Stacks\n", + "\n", + "Given the Stack class below, implement a Queue class using **two** stacks! Note, this is a \"classic\" interview problem. Use a Python list data structure as your Stack." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Uses lists instead of your own Stack class.\n", + "stack1 = []\n", + "stack2 = []" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue2Stacks(object):\n", + " \n", + " def __init__(self):\n", + " \n", + " # Two Stacks\n", + " self.stack1 = []\n", + " self.stack2 = []\n", + " \n", + " def enqueue(self,element):\n", + " \n", + " # FILL OUT CODE HERE\n", + " pass\n", + " \n", + " def dequeue(self):\n", + " \n", + " # FILL OUT CODE HERE\n", + " pass " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "You should be able to tell with your current knowledge of Stacks and Queues if this is working as it should. For example, the following should print as such:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO CHECK THAT YOUR SOLUTION OUTPUT MAKES SENSE AND BEHAVES AS A QUEUE\n", + "\"\"\"\n", + "q = Queue2Stacks()\n", + "\n", + "for i in xrange(5):\n", + " q.enqueue(i)\n", + " \n", + "for i in xrange(5):\n", + " print q.dequeue()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Queue-checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Queue-checkpoint.ipynb new file mode 100644 index 00000000..a5ac0019 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Queue-checkpoint.ipynb @@ -0,0 +1,51 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue\n", + "\n", + "It's very common to be asked to implement a Queue class! The class should be able to do the following:\n", + "\n", + "* Check if Queue is Empty\n", + "* Enqueue\n", + "* Dequeue\n", + "* Return the size of the Queue" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue(object):\n", + " pass" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Stack -checkpoint.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Stack -checkpoint.ipynb new file mode 100644 index 00000000..6dea3952 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/.ipynb_checkpoints/Implement a Stack -checkpoint.ipynb @@ -0,0 +1,57 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Stack \n", + "\n", + "A very common interview question is to begin by just implementing a Stack! Try your best to implement your own stack!\n", + "\n", + "It should have the methods:\n", + "\n", + "* Check if its empty\n", + "* Push a new item\n", + "* Pop an item\n", + "* Peek at the top item\n", + "* Return the size" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Stack(object):\n", + " \n", + " \n", + " # Fill out the Stack Methods here\n", + " pass" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Balanced Parentheses Check .ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Balanced Parentheses Check .ipynb new file mode 100644 index 00000000..274f3ace --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Balanced Parentheses Check .ipynb @@ -0,0 +1,171 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Balanced Parentheses Check \n", + "\n", + "## Problem Statement\n", + "\n", + "Given a string of opening and closing parentheses, check whether it’s balanced. We have 3 types of parentheses: round brackets: (), square brackets: [], and curly brackets: {}. Assume that the string doesn’t contain any other character than these, no spaces words or numbers. As a reminder, balanced parentheses require every opening parenthesis to be closed in the reverse order opened. For example ‘([])’ is balanced but ‘([)]’ is not. \n", + "\n", + "\n", + "You can assume the input string has no spaces.\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def balance_check(s):\n", + " \n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[]')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('[](){([[[]]])}')" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "balance_check('()(){]}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ALL TEST CASES PASSED\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO TEST YOUR SOLUTION\n", + "\"\"\"\n", + "from nose.tools import assert_equal\n", + "\n", + "class TestBalanceCheck(object):\n", + " \n", + " def test(self,sol):\n", + " assert_equal(sol('[](){([[[]]])}('),False)\n", + " assert_equal(sol('[{{{(())}}}]((()))'),True)\n", + " assert_equal(sol('[[[]])]'),False)\n", + " print 'ALL TEST CASES PASSED'\n", + " \n", + "# Run Tests\n", + "\n", + "t = TestBalanceCheck()\n", + "t.test(balance_check)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Deque .ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Deque .ipynb new file mode 100644 index 00000000..d5c255f7 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Deque .ipynb @@ -0,0 +1,51 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Deque \n", + "\n", + "Finally, implement a Deque class! It should be able to do the following:\n", + "\n", + "* Check if its empty\n", + "* Add to both front and rear\n", + "* Remove from Front and Rear\n", + "* Check the Size" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Deque(object):\n", + " pass" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Queue -Using Two Stacks .ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Queue -Using Two Stacks .ipynb new file mode 100644 index 00000000..907956a6 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Queue -Using Two Stacks .ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue - Using Two Stacks\n", + "\n", + "Given the Stack class below, implement a Queue class using **two** stacks! Note, this is a \"classic\" interview problem. Use a Python list data structure as your Stack." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Uses lists instead of your own Stack class.\n", + "stack1 = []\n", + "stack2 = []" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue2Stacks(object):\n", + " \n", + " def __init__(self):\n", + " \n", + " # Two Stacks\n", + " self.stack1 = []\n", + " self.stack2 = []\n", + " \n", + " def enqueue(self,element):\n", + " \n", + " # FILL OUT CODE HERE\n", + " pass\n", + " \n", + " def dequeue(self):\n", + " \n", + " # FILL OUT CODE HERE\n", + " pass " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Your Solution\n", + "\n", + "You should be able to tell with your current knowledge of Stacks and Queues if this is working as it should. For example, the following should print as such:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "RUN THIS CELL TO CHECK THAT YOUR SOLUTION OUTPUT MAKES SENSE AND BEHAVES AS A QUEUE\n", + "\"\"\"\n", + "q = Queue2Stacks()\n", + "\n", + "for i in xrange(5):\n", + " q.enqueue(i)\n", + " \n", + "for i in xrange(5):\n", + " print q.dequeue()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Queue.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Queue.ipynb new file mode 100644 index 00000000..a5ac0019 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Queue.ipynb @@ -0,0 +1,51 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Queue\n", + "\n", + "It's very common to be asked to implement a Queue class! The class should be able to do the following:\n", + "\n", + "* Check if Queue is Empty\n", + "* Enqueue\n", + "* Dequeue\n", + "* Return the size of the Queue" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Queue(object):\n", + " pass" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Stack .ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Stack .ipynb new file mode 100644 index 00000000..6dea3952 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Interview Problems/Stacks, Queues, Deques Interview Questions_/Implement a Stack .ipynb @@ -0,0 +1,57 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implement a Stack \n", + "\n", + "A very common interview question is to begin by just implementing a Stack! Try your best to implement your own stack!\n", + "\n", + "It should have the methods:\n", + "\n", + "* Check if its empty\n", + "* Push a new item\n", + "* Pop an item\n", + "* Peek at the top item\n", + "* Return the size" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Stack(object):\n", + " \n", + " \n", + " # Fill out the Stack Methods here\n", + " pass" + ] + } + ], + "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 +} diff --git a/Stacks, Queues and Deques/Stacks, Queues, and Deques Overview.ipynb b/Stacks, Queues and Deques/Stacks, Queues, and Deques Overview.ipynb new file mode 100644 index 00000000..e020c9b7 --- /dev/null +++ b/Stacks, Queues and Deques/Stacks, Queues, and Deques Overview.ipynb @@ -0,0 +1,53 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Stacks, Queues, and Deques Overview" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this section of the course we will be learning about Stack, Queues, and Deques. These are linear structures. They are similar to arrays, but each of these structures differs by how it adds and removes items.\n", + "\n", + "Here's what to expect in this section:\n", + "\n", + " 1.) A Brief Overview of the Linear Structures\n", + " 2.) An Overview of Stacks\n", + " 3.) An Implementation of a Stack class\n", + " 4.) An Overview of Queues\n", + " 5.) An Implementation of a Queue class\n", + " 6.) An Overview of Deques\n", + " 7.) An Implementation of a Deque class\n", + " \n", + " Then finally a variety of interview questions based on Stacks, Queues, and Deques!\n", + " \n", + "**See the lecture video for a complete breakdown of this Section of the course!**" + ] + } + ], + "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 +} diff --git a/Trees/.ipynb_checkpoints/Binary Heap Implementation-checkpoint.ipynb b/Trees/.ipynb_checkpoints/Binary Heap Implementation-checkpoint.ipynb new file mode 100644 index 00000000..e5630cee --- /dev/null +++ b/Trees/.ipynb_checkpoints/Binary Heap Implementation-checkpoint.ipynb @@ -0,0 +1,132 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Heap Implementation\n", + "\n", + "Here is the reference code for the Binary Heap Implementation. Make sure to refer to the video lecture for the full explanation!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Binary Heap Operations\n", + "**The basic operations we will implement for our binary heap are as follows:**\n", + "\n", + "* BinaryHeap() creates a new, empty, binary heap.\n", + "* insert(k) adds a new item to the heap.\n", + "* findMin() returns the item with the minimum key value, leaving item in the heap.\n", + "* delMin() returns the item with the minimum key value, removing the item from the heap.\n", + "* isEmpty() returns true if the heap is empty, false otherwise.\n", + "* size() returns the number of items in the heap.\n", + "* buildHeap(list) builds a new heap from a list of keys." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class BinHeap:\n", + " def __init__(self):\n", + " self.heapList = [0]\n", + " self.currentSize = 0\n", + "\n", + "\n", + " def percUp(self,i):\n", + " \n", + " while i // 2 > 0:\n", + " \n", + " if self.heapList[i] < self.heapList[i // 2]:\n", + " \n", + " \n", + " tmp = self.heapList[i // 2]\n", + " self.heapList[i // 2] = self.heapList[i]\n", + " self.heapList[i] = tmp\n", + " i = i // 2\n", + "\n", + " def insert(self,k):\n", + " \n", + " self.heapList.append(k)\n", + " self.currentSize = self.currentSize + 1\n", + " self.percUp(self.currentSize)\n", + "\n", + " def percDown(self,i):\n", + " \n", + " while (i * 2) <= self.currentSize:\n", + " \n", + " mc = self.minChild(i)\n", + " if self.heapList[i] > self.heapList[mc]:\n", + " \n", + " tmp = self.heapList[i]\n", + " self.heapList[i] = self.heapList[mc]\n", + " self.heapList[mc] = tmp\n", + " i = mc\n", + "\n", + " def minChild(self,i):\n", + " \n", + " if i * 2 + 1 > self.currentSize:\n", + " \n", + " return i * 2\n", + " else:\n", + " \n", + " if self.heapList[i*2] < self.heapList[i*2+1]:\n", + " return i * 2\n", + " else:\n", + " return i * 2 + 1\n", + "\n", + " def delMin(self):\n", + " retval = self.heapList[1]\n", + " self.heapList[1] = self.heapList[self.currentSize]\n", + " self.currentSize = self.currentSize - 1\n", + " self.heapList.pop()\n", + " self.percDown(1)\n", + " return retval\n", + "\n", + " def buildHeap(self,alist):\n", + " i = len(alist) // 2\n", + " self.currentSize = len(alist)\n", + " self.heapList = [0] + alist[:]\n", + " while (i > 0):\n", + " self.percDown(i)\n", + " i = i - 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/.ipynb_checkpoints/Binary Search Trees-checkpoint.ipynb b/Trees/.ipynb_checkpoints/Binary Search Trees-checkpoint.ipynb new file mode 100644 index 00000000..c6679bb0 --- /dev/null +++ b/Trees/.ipynb_checkpoints/Binary Search Trees-checkpoint.ipynb @@ -0,0 +1,305 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Search Trees" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is the code ot go along with the video explanation. Check out the video lecture for full details!" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class TreeNode:\n", + " \n", + " def __init__(self,key,val,left=None,right=None,parent=None):\n", + " self.key = key\n", + " self.payload = val\n", + " self.leftChild = left\n", + " self.rightChild = right\n", + " self.parent = parent\n", + "\n", + " def hasLeftChild(self):\n", + " return self.leftChild\n", + "\n", + " def hasRightChild(self):\n", + " return self.rightChild\n", + "\n", + " def isLeftChild(self):\n", + " return self.parent and self.parent.leftChild == self\n", + "\n", + " def isRightChild(self):\n", + " return self.parent and self.parent.rightChild == self\n", + "\n", + " def isRoot(self):\n", + " return not self.parent\n", + "\n", + " def isLeaf(self):\n", + " return not (self.rightChild or self.leftChild)\n", + "\n", + " def hasAnyChildren(self):\n", + " return self.rightChild or self.leftChild\n", + "\n", + " def hasBothChildren(self):\n", + " return self.rightChild and self.leftChild\n", + "\n", + " def replaceNodeData(self,key,value,lc,rc):\n", + " self.key = key\n", + " self.payload = value\n", + " self.leftChild = lc\n", + " self.rightChild = rc\n", + " if self.hasLeftChild():\n", + " self.leftChild.parent = self\n", + " if self.hasRightChild():\n", + " self.rightChild.parent = self\n", + "\n", + "\n", + "class BinarySearchTree:\n", + "\n", + " def __init__(self):\n", + " self.root = None\n", + " self.size = 0\n", + "\n", + " def length(self):\n", + " return self.size\n", + "\n", + " def __len__(self):\n", + " return self.size\n", + "\n", + " def put(self,key,val):\n", + " if self.root:\n", + " self._put(key,val,self.root)\n", + " else:\n", + " self.root = TreeNode(key,val)\n", + " self.size = self.size + 1\n", + "\n", + " def _put(self,key,val,currentNode):\n", + " if key < currentNode.key:\n", + " if currentNode.hasLeftChild():\n", + " self._put(key,val,currentNode.leftChild)\n", + " else:\n", + " currentNode.leftChild = TreeNode(key,val,parent=currentNode)\n", + " else:\n", + " if currentNode.hasRightChild():\n", + " self._put(key,val,currentNode.rightChild)\n", + " else:\n", + " currentNode.rightChild = TreeNode(key,val,parent=currentNode)\n", + "\n", + " def __setitem__(self,k,v):\n", + " self.put(k,v)\n", + "\n", + " def get(self,key):\n", + " if self.root:\n", + " res = self._get(key,self.root)\n", + " if res:\n", + " \n", + " return res.payload\n", + " else:\n", + " return None\n", + " else:\n", + " return None\n", + "\n", + " def _get(self,key,currentNode):\n", + " \n", + " if not currentNode:\n", + " return None\n", + " elif currentNode.key == key:\n", + " return currentNode\n", + " elif key < currentNode.key:\n", + " return self._get(key,currentNode.leftChild)\n", + " else:\n", + " return self._get(key,currentNode.rightChild)\n", + "\n", + " def __getitem__(self,key):\n", + " return self.get(key)\n", + "\n", + " def __contains__(self,key):\n", + " if self._get(key,self.root):\n", + " return True\n", + " else:\n", + " return False\n", + "\n", + " def delete(self,key):\n", + " \n", + " if self.size > 1:\n", + " \n", + " nodeToRemove = self._get(key,self.root)\n", + " if nodeToRemove:\n", + " self.remove(nodeToRemove)\n", + " self.size = self.size-1\n", + " else:\n", + " raise KeyError('Error, key not in tree')\n", + " elif self.size == 1 and self.root.key == key:\n", + " self.root = None\n", + " self.size = self.size - 1\n", + " else:\n", + " raise KeyError('Error, key not in tree')\n", + "\n", + " def __delitem__(self,key):\n", + " \n", + " self.delete(key)\n", + "\n", + " def spliceOut(self):\n", + " if self.isLeaf():\n", + " if self.isLeftChild():\n", + " \n", + " self.parent.leftChild = None\n", + " else:\n", + " self.parent.rightChild = None\n", + " elif self.hasAnyChildren():\n", + " if self.hasLeftChild():\n", + " \n", + " if self.isLeftChild():\n", + " \n", + " self.parent.leftChild = self.leftChild\n", + " else:\n", + " \n", + " self.parent.rightChild = self.leftChild\n", + " self.leftChild.parent = self.parent\n", + " else:\n", + " \n", + " if self.isLeftChild():\n", + " \n", + " self.parent.leftChild = self.rightChild\n", + " else:\n", + " self.parent.rightChild = self.rightChild\n", + " self.rightChild.parent = self.parent\n", + "\n", + " def findSuccessor(self):\n", + " \n", + " succ = None\n", + " if self.hasRightChild():\n", + " succ = self.rightChild.findMin()\n", + " else:\n", + " if self.parent:\n", + " \n", + " if self.isLeftChild():\n", + " \n", + " succ = self.parent\n", + " else:\n", + " self.parent.rightChild = None\n", + " succ = self.parent.findSuccessor()\n", + " self.parent.rightChild = self\n", + " return succ\n", + "\n", + " def findMin(self):\n", + " \n", + " current = self\n", + " while current.hasLeftChild():\n", + " current = current.leftChild\n", + " return current\n", + "\n", + " def remove(self,currentNode):\n", + " \n", + " if currentNode.isLeaf(): #leaf\n", + " if currentNode == currentNode.parent.leftChild:\n", + " currentNode.parent.leftChild = None\n", + " else:\n", + " currentNode.parent.rightChild = None\n", + " elif currentNode.hasBothChildren(): #interior\n", + " \n", + " succ = currentNode.findSuccessor()\n", + " succ.spliceOut()\n", + " currentNode.key = succ.key\n", + " currentNode.payload = succ.payload\n", + "\n", + " else: # this node has one child\n", + " if currentNode.hasLeftChild():\n", + " if currentNode.isLeftChild():\n", + " currentNode.leftChild.parent = currentNode.parent\n", + " currentNode.parent.leftChild = currentNode.leftChild\n", + " elif currentNode.isRightChild():\n", + " currentNode.leftChild.parent = currentNode.parent\n", + " currentNode.parent.rightChild = currentNode.leftChild\n", + " else:\n", + " \n", + " currentNode.replaceNodeData(currentNode.leftChild.key,\n", + " currentNode.leftChild.payload,\n", + " currentNode.leftChild.leftChild,\n", + " currentNode.leftChild.rightChild)\n", + " else:\n", + " \n", + " if currentNode.isLeftChild():\n", + " currentNode.rightChild.parent = currentNode.parent\n", + " currentNode.parent.leftChild = currentNode.rightChild\n", + " elif currentNode.isRightChild():\n", + " currentNode.rightChild.parent = currentNode.parent\n", + " currentNode.parent.rightChild = currentNode.rightChild\n", + " else:\n", + " currentNode.replaceNodeData(currentNode.rightChild.key,\n", + " currentNode.rightChild.payload,\n", + " currentNode.rightChild.leftChild,\n", + " currentNode.rightChild.rightChild)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "yellow\n", + "at\n" + ] + } + ], + "source": [ + "mytree = BinarySearchTree()\n", + "mytree[3]=\"red\"\n", + "mytree[4]=\"blue\"\n", + "mytree[6]=\"yellow\"\n", + "mytree[2]=\"at\"\n", + "\n", + "print(mytree[6])\n", + "print(mytree[2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** Check the video for full explanation! **" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/.ipynb_checkpoints/Tree Representation Implementation (Lists)-checkpoint.ipynb b/Trees/.ipynb_checkpoints/Tree Representation Implementation (Lists)-checkpoint.ipynb new file mode 100644 index 00000000..ad33ac3f --- /dev/null +++ b/Trees/.ipynb_checkpoints/Tree Representation Implementation (Lists)-checkpoint.ipynb @@ -0,0 +1,74 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tree Representation Implementation (Lists)\n", + "\n", + "Below is a representation of a Tree using a list of lists. Refer to the video lecture for an explanation and a live coding demonstration!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def BinaryTree(r):\n", + " return [r, [], []]\n", + "\n", + "def insertLeft(root,newBranch):\n", + " t = root.pop(1)\n", + " if len(t) > 1:\n", + " root.insert(1,[newBranch,t,[]])\n", + " else:\n", + " root.insert(1,[newBranch, [], []])\n", + " return root\n", + "\n", + "def insertRight(root,newBranch):\n", + " t = root.pop(2)\n", + " if len(t) > 1:\n", + " root.insert(2,[newBranch,[],t])\n", + " else:\n", + " root.insert(2,[newBranch,[],[]])\n", + " return root\n", + "\n", + "def getRootVal(root):\n", + " return root[0]\n", + "\n", + "def setRootVal(root,newVal):\n", + " root[0] = newVal\n", + "\n", + "def getLeftChild(root):\n", + " return root[1]\n", + "\n", + "def getRightChild(root):\n", + " return root[2]" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/.ipynb_checkpoints/Tree Representation Implementation (Nodes and References)-checkpoint.ipynb b/Trees/.ipynb_checkpoints/Tree Representation Implementation (Nodes and References)-checkpoint.ipynb new file mode 100644 index 00000000..5ca824e2 --- /dev/null +++ b/Trees/.ipynb_checkpoints/Tree Representation Implementation (Nodes and References)-checkpoint.ipynb @@ -0,0 +1,122 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Nodes and References Implementation of a Tree\n", + "\n", + "In this notebook is the code corresponding to the lecture for implementing the representation of a Tree as a class with nodes and references!" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class BinaryTree(object):\n", + " def __init__(self,rootObj):\n", + " self.key = rootObj\n", + " self.leftChild = None\n", + " self.rightChild = None\n", + "\n", + " def insertLeft(self,newNode):\n", + " if self.leftChild == None:\n", + " self.leftChild = BinaryTree(newNode)\n", + " else:\n", + " t = BinaryTree(newNode)\n", + " t.leftChild = self.leftChild\n", + " self.leftChild = t\n", + "\n", + " def insertRight(self,newNode):\n", + " if self.rightChild == None:\n", + " self.rightChild = BinaryTree(newNode)\n", + " else:\n", + " t = BinaryTree(newNode)\n", + " t.rightChild = self.rightChild\n", + " self.rightChild = t\n", + "\n", + "\n", + " def getRightChild(self):\n", + " return self.rightChild\n", + "\n", + " def getLeftChild(self):\n", + " return self.leftChild\n", + "\n", + " def setRootVal(self,obj):\n", + " self.key = obj\n", + "\n", + " def getRootVal(self):\n", + " return self.key" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see some examples of creating a tree and assigning children. Note that some outputs are Trees themselves!" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a\n", + "None\n", + "<__main__.BinaryTree object at 0x104779c10>\n", + "b\n", + "<__main__.BinaryTree object at 0x103b42c50>\n", + "c\n", + "hello\n" + ] + } + ], + "source": [ + "from __future__ import print_function\n", + "\n", + "r = BinaryTree('a')\n", + "print(r.getRootVal())\n", + "print(r.getLeftChild())\n", + "r.insertLeft('b')\n", + "print(r.getLeftChild())\n", + "print(r.getLeftChild().getRootVal())\n", + "r.insertRight('c')\n", + "print(r.getRightChild())\n", + "print(r.getRightChild().getRootVal())\n", + "r.getRightChild().setRootVal('hello')\n", + "print(r.getRightChild().getRootVal())" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Binary Heap Implementation.ipynb b/Trees/Binary Heap Implementation.ipynb new file mode 100644 index 00000000..e5630cee --- /dev/null +++ b/Trees/Binary Heap Implementation.ipynb @@ -0,0 +1,132 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Heap Implementation\n", + "\n", + "Here is the reference code for the Binary Heap Implementation. Make sure to refer to the video lecture for the full explanation!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Binary Heap Operations\n", + "**The basic operations we will implement for our binary heap are as follows:**\n", + "\n", + "* BinaryHeap() creates a new, empty, binary heap.\n", + "* insert(k) adds a new item to the heap.\n", + "* findMin() returns the item with the minimum key value, leaving item in the heap.\n", + "* delMin() returns the item with the minimum key value, removing the item from the heap.\n", + "* isEmpty() returns true if the heap is empty, false otherwise.\n", + "* size() returns the number of items in the heap.\n", + "* buildHeap(list) builds a new heap from a list of keys." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class BinHeap:\n", + " def __init__(self):\n", + " self.heapList = [0]\n", + " self.currentSize = 0\n", + "\n", + "\n", + " def percUp(self,i):\n", + " \n", + " while i // 2 > 0:\n", + " \n", + " if self.heapList[i] < self.heapList[i // 2]:\n", + " \n", + " \n", + " tmp = self.heapList[i // 2]\n", + " self.heapList[i // 2] = self.heapList[i]\n", + " self.heapList[i] = tmp\n", + " i = i // 2\n", + "\n", + " def insert(self,k):\n", + " \n", + " self.heapList.append(k)\n", + " self.currentSize = self.currentSize + 1\n", + " self.percUp(self.currentSize)\n", + "\n", + " def percDown(self,i):\n", + " \n", + " while (i * 2) <= self.currentSize:\n", + " \n", + " mc = self.minChild(i)\n", + " if self.heapList[i] > self.heapList[mc]:\n", + " \n", + " tmp = self.heapList[i]\n", + " self.heapList[i] = self.heapList[mc]\n", + " self.heapList[mc] = tmp\n", + " i = mc\n", + "\n", + " def minChild(self,i):\n", + " \n", + " if i * 2 + 1 > self.currentSize:\n", + " \n", + " return i * 2\n", + " else:\n", + " \n", + " if self.heapList[i*2] < self.heapList[i*2+1]:\n", + " return i * 2\n", + " else:\n", + " return i * 2 + 1\n", + "\n", + " def delMin(self):\n", + " retval = self.heapList[1]\n", + " self.heapList[1] = self.heapList[self.currentSize]\n", + " self.currentSize = self.currentSize - 1\n", + " self.heapList.pop()\n", + " self.percDown(1)\n", + " return retval\n", + "\n", + " def buildHeap(self,alist):\n", + " i = len(alist) // 2\n", + " self.currentSize = len(alist)\n", + " self.heapList = [0] + alist[:]\n", + " while (i > 0):\n", + " self.percDown(i)\n", + " i = i - 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Binary Search Trees.ipynb b/Trees/Binary Search Trees.ipynb new file mode 100644 index 00000000..c6679bb0 --- /dev/null +++ b/Trees/Binary Search Trees.ipynb @@ -0,0 +1,305 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Search Trees" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is the code ot go along with the video explanation. Check out the video lecture for full details!" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class TreeNode:\n", + " \n", + " def __init__(self,key,val,left=None,right=None,parent=None):\n", + " self.key = key\n", + " self.payload = val\n", + " self.leftChild = left\n", + " self.rightChild = right\n", + " self.parent = parent\n", + "\n", + " def hasLeftChild(self):\n", + " return self.leftChild\n", + "\n", + " def hasRightChild(self):\n", + " return self.rightChild\n", + "\n", + " def isLeftChild(self):\n", + " return self.parent and self.parent.leftChild == self\n", + "\n", + " def isRightChild(self):\n", + " return self.parent and self.parent.rightChild == self\n", + "\n", + " def isRoot(self):\n", + " return not self.parent\n", + "\n", + " def isLeaf(self):\n", + " return not (self.rightChild or self.leftChild)\n", + "\n", + " def hasAnyChildren(self):\n", + " return self.rightChild or self.leftChild\n", + "\n", + " def hasBothChildren(self):\n", + " return self.rightChild and self.leftChild\n", + "\n", + " def replaceNodeData(self,key,value,lc,rc):\n", + " self.key = key\n", + " self.payload = value\n", + " self.leftChild = lc\n", + " self.rightChild = rc\n", + " if self.hasLeftChild():\n", + " self.leftChild.parent = self\n", + " if self.hasRightChild():\n", + " self.rightChild.parent = self\n", + "\n", + "\n", + "class BinarySearchTree:\n", + "\n", + " def __init__(self):\n", + " self.root = None\n", + " self.size = 0\n", + "\n", + " def length(self):\n", + " return self.size\n", + "\n", + " def __len__(self):\n", + " return self.size\n", + "\n", + " def put(self,key,val):\n", + " if self.root:\n", + " self._put(key,val,self.root)\n", + " else:\n", + " self.root = TreeNode(key,val)\n", + " self.size = self.size + 1\n", + "\n", + " def _put(self,key,val,currentNode):\n", + " if key < currentNode.key:\n", + " if currentNode.hasLeftChild():\n", + " self._put(key,val,currentNode.leftChild)\n", + " else:\n", + " currentNode.leftChild = TreeNode(key,val,parent=currentNode)\n", + " else:\n", + " if currentNode.hasRightChild():\n", + " self._put(key,val,currentNode.rightChild)\n", + " else:\n", + " currentNode.rightChild = TreeNode(key,val,parent=currentNode)\n", + "\n", + " def __setitem__(self,k,v):\n", + " self.put(k,v)\n", + "\n", + " def get(self,key):\n", + " if self.root:\n", + " res = self._get(key,self.root)\n", + " if res:\n", + " \n", + " return res.payload\n", + " else:\n", + " return None\n", + " else:\n", + " return None\n", + "\n", + " def _get(self,key,currentNode):\n", + " \n", + " if not currentNode:\n", + " return None\n", + " elif currentNode.key == key:\n", + " return currentNode\n", + " elif key < currentNode.key:\n", + " return self._get(key,currentNode.leftChild)\n", + " else:\n", + " return self._get(key,currentNode.rightChild)\n", + "\n", + " def __getitem__(self,key):\n", + " return self.get(key)\n", + "\n", + " def __contains__(self,key):\n", + " if self._get(key,self.root):\n", + " return True\n", + " else:\n", + " return False\n", + "\n", + " def delete(self,key):\n", + " \n", + " if self.size > 1:\n", + " \n", + " nodeToRemove = self._get(key,self.root)\n", + " if nodeToRemove:\n", + " self.remove(nodeToRemove)\n", + " self.size = self.size-1\n", + " else:\n", + " raise KeyError('Error, key not in tree')\n", + " elif self.size == 1 and self.root.key == key:\n", + " self.root = None\n", + " self.size = self.size - 1\n", + " else:\n", + " raise KeyError('Error, key not in tree')\n", + "\n", + " def __delitem__(self,key):\n", + " \n", + " self.delete(key)\n", + "\n", + " def spliceOut(self):\n", + " if self.isLeaf():\n", + " if self.isLeftChild():\n", + " \n", + " self.parent.leftChild = None\n", + " else:\n", + " self.parent.rightChild = None\n", + " elif self.hasAnyChildren():\n", + " if self.hasLeftChild():\n", + " \n", + " if self.isLeftChild():\n", + " \n", + " self.parent.leftChild = self.leftChild\n", + " else:\n", + " \n", + " self.parent.rightChild = self.leftChild\n", + " self.leftChild.parent = self.parent\n", + " else:\n", + " \n", + " if self.isLeftChild():\n", + " \n", + " self.parent.leftChild = self.rightChild\n", + " else:\n", + " self.parent.rightChild = self.rightChild\n", + " self.rightChild.parent = self.parent\n", + "\n", + " def findSuccessor(self):\n", + " \n", + " succ = None\n", + " if self.hasRightChild():\n", + " succ = self.rightChild.findMin()\n", + " else:\n", + " if self.parent:\n", + " \n", + " if self.isLeftChild():\n", + " \n", + " succ = self.parent\n", + " else:\n", + " self.parent.rightChild = None\n", + " succ = self.parent.findSuccessor()\n", + " self.parent.rightChild = self\n", + " return succ\n", + "\n", + " def findMin(self):\n", + " \n", + " current = self\n", + " while current.hasLeftChild():\n", + " current = current.leftChild\n", + " return current\n", + "\n", + " def remove(self,currentNode):\n", + " \n", + " if currentNode.isLeaf(): #leaf\n", + " if currentNode == currentNode.parent.leftChild:\n", + " currentNode.parent.leftChild = None\n", + " else:\n", + " currentNode.parent.rightChild = None\n", + " elif currentNode.hasBothChildren(): #interior\n", + " \n", + " succ = currentNode.findSuccessor()\n", + " succ.spliceOut()\n", + " currentNode.key = succ.key\n", + " currentNode.payload = succ.payload\n", + "\n", + " else: # this node has one child\n", + " if currentNode.hasLeftChild():\n", + " if currentNode.isLeftChild():\n", + " currentNode.leftChild.parent = currentNode.parent\n", + " currentNode.parent.leftChild = currentNode.leftChild\n", + " elif currentNode.isRightChild():\n", + " currentNode.leftChild.parent = currentNode.parent\n", + " currentNode.parent.rightChild = currentNode.leftChild\n", + " else:\n", + " \n", + " currentNode.replaceNodeData(currentNode.leftChild.key,\n", + " currentNode.leftChild.payload,\n", + " currentNode.leftChild.leftChild,\n", + " currentNode.leftChild.rightChild)\n", + " else:\n", + " \n", + " if currentNode.isLeftChild():\n", + " currentNode.rightChild.parent = currentNode.parent\n", + " currentNode.parent.leftChild = currentNode.rightChild\n", + " elif currentNode.isRightChild():\n", + " currentNode.rightChild.parent = currentNode.parent\n", + " currentNode.parent.rightChild = currentNode.rightChild\n", + " else:\n", + " currentNode.replaceNodeData(currentNode.rightChild.key,\n", + " currentNode.rightChild.payload,\n", + " currentNode.rightChild.leftChild,\n", + " currentNode.rightChild.rightChild)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "yellow\n", + "at\n" + ] + } + ], + "source": [ + "mytree = BinarySearchTree()\n", + "mytree[3]=\"red\"\n", + "mytree[4]=\"blue\"\n", + "mytree[6]=\"yellow\"\n", + "mytree[2]=\"at\"\n", + "\n", + "print(mytree[6])\n", + "print(mytree[2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** Check the video for full explanation! **" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Tree Representation Implementation (Lists).ipynb b/Trees/Tree Representation Implementation (Lists).ipynb new file mode 100644 index 00000000..ad33ac3f --- /dev/null +++ b/Trees/Tree Representation Implementation (Lists).ipynb @@ -0,0 +1,74 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tree Representation Implementation (Lists)\n", + "\n", + "Below is a representation of a Tree using a list of lists. Refer to the video lecture for an explanation and a live coding demonstration!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def BinaryTree(r):\n", + " return [r, [], []]\n", + "\n", + "def insertLeft(root,newBranch):\n", + " t = root.pop(1)\n", + " if len(t) > 1:\n", + " root.insert(1,[newBranch,t,[]])\n", + " else:\n", + " root.insert(1,[newBranch, [], []])\n", + " return root\n", + "\n", + "def insertRight(root,newBranch):\n", + " t = root.pop(2)\n", + " if len(t) > 1:\n", + " root.insert(2,[newBranch,[],t])\n", + " else:\n", + " root.insert(2,[newBranch,[],[]])\n", + " return root\n", + "\n", + "def getRootVal(root):\n", + " return root[0]\n", + "\n", + "def setRootVal(root,newVal):\n", + " root[0] = newVal\n", + "\n", + "def getLeftChild(root):\n", + " return root[1]\n", + "\n", + "def getRightChild(root):\n", + " return root[2]" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Tree Representation Implementation (Nodes and References).ipynb b/Trees/Tree Representation Implementation (Nodes and References).ipynb new file mode 100644 index 00000000..5ca824e2 --- /dev/null +++ b/Trees/Tree Representation Implementation (Nodes and References).ipynb @@ -0,0 +1,122 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Nodes and References Implementation of a Tree\n", + "\n", + "In this notebook is the code corresponding to the lecture for implementing the representation of a Tree as a class with nodes and references!" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class BinaryTree(object):\n", + " def __init__(self,rootObj):\n", + " self.key = rootObj\n", + " self.leftChild = None\n", + " self.rightChild = None\n", + "\n", + " def insertLeft(self,newNode):\n", + " if self.leftChild == None:\n", + " self.leftChild = BinaryTree(newNode)\n", + " else:\n", + " t = BinaryTree(newNode)\n", + " t.leftChild = self.leftChild\n", + " self.leftChild = t\n", + "\n", + " def insertRight(self,newNode):\n", + " if self.rightChild == None:\n", + " self.rightChild = BinaryTree(newNode)\n", + " else:\n", + " t = BinaryTree(newNode)\n", + " t.rightChild = self.rightChild\n", + " self.rightChild = t\n", + "\n", + "\n", + " def getRightChild(self):\n", + " return self.rightChild\n", + "\n", + " def getLeftChild(self):\n", + " return self.leftChild\n", + "\n", + " def setRootVal(self,obj):\n", + " self.key = obj\n", + "\n", + " def getRootVal(self):\n", + " return self.key" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see some examples of creating a tree and assigning children. Note that some outputs are Trees themselves!" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a\n", + "None\n", + "<__main__.BinaryTree object at 0x104779c10>\n", + "b\n", + "<__main__.BinaryTree object at 0x103b42c50>\n", + "c\n", + "hello\n" + ] + } + ], + "source": [ + "from __future__ import print_function\n", + "\n", + "r = BinaryTree('a')\n", + "print(r.getRootVal())\n", + "print(r.getLeftChild())\n", + "r.insertLeft('b')\n", + "print(r.getLeftChild())\n", + "print(r.getLeftChild().getRootVal())\n", + "r.insertRight('c')\n", + "print(r.getRightChild())\n", + "print(r.getRightChild().getRootVal())\n", + "r.getRightChild().setRootVal('hello')\n", + "print(r.getRightChild().getRootVal())" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Binary Search Tree Check-checkpoint.ipynb b/Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Binary Search Tree Check-checkpoint.ipynb new file mode 100644 index 00000000..a97a2c8b --- /dev/null +++ b/Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Binary Search Tree Check-checkpoint.ipynb @@ -0,0 +1,82 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Search Tree Check \n", + "\n", + "## Problem Statement\n", + "\n", + "Given a binary tree, check whether it’s a binary search tree or not.\n", + "\n", + "** Again, no solution cell, just worry about your code making sense logically. Hint: Think about tree traversals. **\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Definition for a binary tree node.\n", + "class TreeNode(object):\n", + " def __init__(self, x):\n", + " self.val = x\n", + " self.left = None\n", + " self.right = None" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "class Solution(object):\n", + " def isValidBST(self, root):\n", + " return self.is_valid(root, -math.inf, math.inf)\n", + " \n", + " def is_valid(self, root, min_val, max_val):\n", + " if root is None:\n", + " return True\n", + " else:\n", + " return ( root.val > min_val and root.val < max_val and\n", + " self.is_valid(root.left, min_val, root.val) and\n", + " self.is_valid(root.right, root.val, max_val) )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a classic interview problem, so feel free to just Google search \"Validate BST\" for more information on this problem!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Tree Level Order Print-checkpoint.ipynb b/Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Tree Level Order Print-checkpoint.ipynb new file mode 100644 index 00000000..b1e45bd2 --- /dev/null +++ b/Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Tree Level Order Print-checkpoint.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tree Level Order Print \n", + "\n", + "Given a binary tree of integers, print it in level order. The output will contain space between the numbers in the same level, and new line between different levels. For example, if the tree is: \n", + "___\n", + "![title](tree_print.png)\n", + "___\n", + "The output should be: \n", + "\n", + " 1 \n", + " 2 3 \n", + " 4 5 6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "class Node:\n", + " def __init__(self, val=None):\n", + " self.left = None\n", + " self.right = None\n", + " self.val = val " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import deque\n", + "def levelOrderPrint(tree):\n", + " if tree is None:\n", + " return\n", + "\n", + " queue = deque()\n", + " queue.append(tree)\n", + " while len(queue) != 0:\n", + " temp = deque()\n", + " while len(queue) != 0:\n", + " node = queue.pop()\n", + " print(str(node.val) + ' ')\n", + " if node.left is not None:\n", + " temp.append(tree.left)\n", + " if node.right is not None:\n", + " temp.append(tree.right)\n", + " queue = temp" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2 \n", + "3 \n", + "1 \n" + ] + } + ], + "source": [ + "root = Node(2)\n", + "root.left = Node(1)\n", + "root.right = Node(3)\n", + "\n", + "levelOrderPrint(root)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Trim a Binary Search Tree -checkpoint.ipynb b/Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Trim a Binary Search Tree -checkpoint.ipynb new file mode 100644 index 00000000..1b7bf768 --- /dev/null +++ b/Trees/Trees Interview Problems - PRACTICE/.ipynb_checkpoints/Trim a Binary Search Tree -checkpoint.ipynb @@ -0,0 +1,83 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Trim a Binary Search Tree \n", + "\n", + "## Problem Statement\n", + "\n", + "Given the root of a binary search tree and 2 numbers min and max, trim the tree such that all the numbers in the new tree are between min and max (inclusive). The resulting tree should still be a valid binary search tree. So, if we get this tree as input:\n", + "___\n", + "\n", + "![title](bst1.png)\n", + "___\n", + "and we’re given **min value as 5** and **max value as 13**, then the resulting binary search tree should be: \n", + "___\n", + "![title](bst_trim.png)\n", + "___\n", + "We should remove all the nodes whose value is not between min and max. \n", + "\n", + "___\n", + "** Feel free to reference the lecture on Binary Search Tree for the node class, but what it more important here is the logic of your function. In which case your function should be in the form:**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# 669. Trim a Binary Search Tree\n", + "class Solution:\n", + " def trimBST(self, root, min_val, max_val):\n", + " \"\"\"\n", + " :type root: TreeNode\n", + " :type min_val: int\n", + " :type max_val: int\n", + " :rtype: TreeNode\n", + " \"\"\"\n", + " if not root:\n", + " return None\n", + " if root.val < min_val:\n", + " return self.trimBST(root.right, min_val, max_val)\n", + " if root.val > max_val:\n", + " return self.trimBST(root.left, min_val, max_val)\n", + " root.left = self.trimBST(root.left, min_val, max_val)\n", + " root.right = self.trimBST(root.right, min_val, max_val)\n", + " return root" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** There is no solution cell because the nature of the code should be more logical and a test would essentially give away the answer. Just focus your answer to fill out the logic of the solution using the methods described above **\n", + "\n", + "## Best of luck!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Trees/Trees Interview Problems - PRACTICE/Binary Search Tree Check.ipynb b/Trees/Trees Interview Problems - PRACTICE/Binary Search Tree Check.ipynb new file mode 100644 index 00000000..a97a2c8b --- /dev/null +++ b/Trees/Trees Interview Problems - PRACTICE/Binary Search Tree Check.ipynb @@ -0,0 +1,82 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Search Tree Check \n", + "\n", + "## Problem Statement\n", + "\n", + "Given a binary tree, check whether it’s a binary search tree or not.\n", + "\n", + "** Again, no solution cell, just worry about your code making sense logically. Hint: Think about tree traversals. **\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Definition for a binary tree node.\n", + "class TreeNode(object):\n", + " def __init__(self, x):\n", + " self.val = x\n", + " self.left = None\n", + " self.right = None" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "class Solution(object):\n", + " def isValidBST(self, root):\n", + " return self.is_valid(root, -math.inf, math.inf)\n", + " \n", + " def is_valid(self, root, min_val, max_val):\n", + " if root is None:\n", + " return True\n", + " else:\n", + " return ( root.val > min_val and root.val < max_val and\n", + " self.is_valid(root.left, min_val, root.val) and\n", + " self.is_valid(root.right, root.val, max_val) )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a classic interview problem, so feel free to just Google search \"Validate BST\" for more information on this problem!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Trees/Trees Interview Problems - PRACTICE/Node.py b/Trees/Trees Interview Problems - PRACTICE/Node.py new file mode 100644 index 00000000..348c9ac4 --- /dev/null +++ b/Trees/Trees Interview Problems - PRACTICE/Node.py @@ -0,0 +1,5 @@ +class Node(object): + def __init__(self, val=None): + self.left = None + self.right = None + self.val = val \ No newline at end of file diff --git a/Trees/Trees Interview Problems - PRACTICE/Tree Level Order Print.ipynb b/Trees/Trees Interview Problems - PRACTICE/Tree Level Order Print.ipynb new file mode 100644 index 00000000..b1e45bd2 --- /dev/null +++ b/Trees/Trees Interview Problems - PRACTICE/Tree Level Order Print.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tree Level Order Print \n", + "\n", + "Given a binary tree of integers, print it in level order. The output will contain space between the numbers in the same level, and new line between different levels. For example, if the tree is: \n", + "___\n", + "![title](tree_print.png)\n", + "___\n", + "The output should be: \n", + "\n", + " 1 \n", + " 2 3 \n", + " 4 5 6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "class Node:\n", + " def __init__(self, val=None):\n", + " self.left = None\n", + " self.right = None\n", + " self.val = val " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import deque\n", + "def levelOrderPrint(tree):\n", + " if tree is None:\n", + " return\n", + "\n", + " queue = deque()\n", + " queue.append(tree)\n", + " while len(queue) != 0:\n", + " temp = deque()\n", + " while len(queue) != 0:\n", + " node = queue.pop()\n", + " print(str(node.val) + ' ')\n", + " if node.left is not None:\n", + " temp.append(tree.left)\n", + " if node.right is not None:\n", + " temp.append(tree.right)\n", + " queue = temp" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2 \n", + "3 \n", + "1 \n" + ] + } + ], + "source": [ + "root = Node(2)\n", + "root.left = Node(1)\n", + "root.right = Node(3)\n", + "\n", + "levelOrderPrint(root)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Trees/Trees Interview Problems - PRACTICE/Trim a Binary Search Tree .ipynb b/Trees/Trees Interview Problems - PRACTICE/Trim a Binary Search Tree .ipynb new file mode 100644 index 00000000..1b7bf768 --- /dev/null +++ b/Trees/Trees Interview Problems - PRACTICE/Trim a Binary Search Tree .ipynb @@ -0,0 +1,83 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Trim a Binary Search Tree \n", + "\n", + "## Problem Statement\n", + "\n", + "Given the root of a binary search tree and 2 numbers min and max, trim the tree such that all the numbers in the new tree are between min and max (inclusive). The resulting tree should still be a valid binary search tree. So, if we get this tree as input:\n", + "___\n", + "\n", + "![title](bst1.png)\n", + "___\n", + "and we’re given **min value as 5** and **max value as 13**, then the resulting binary search tree should be: \n", + "___\n", + "![title](bst_trim.png)\n", + "___\n", + "We should remove all the nodes whose value is not between min and max. \n", + "\n", + "___\n", + "** Feel free to reference the lecture on Binary Search Tree for the node class, but what it more important here is the logic of your function. In which case your function should be in the form:**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# 669. Trim a Binary Search Tree\n", + "class Solution:\n", + " def trimBST(self, root, min_val, max_val):\n", + " \"\"\"\n", + " :type root: TreeNode\n", + " :type min_val: int\n", + " :type max_val: int\n", + " :rtype: TreeNode\n", + " \"\"\"\n", + " if not root:\n", + " return None\n", + " if root.val < min_val:\n", + " return self.trimBST(root.right, min_val, max_val)\n", + " if root.val > max_val:\n", + " return self.trimBST(root.left, min_val, max_val)\n", + " root.left = self.trimBST(root.left, min_val, max_val)\n", + " root.right = self.trimBST(root.right, min_val, max_val)\n", + " return root" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** There is no solution cell because the nature of the code should be more logical and a test would essentially give away the answer. Just focus your answer to fill out the logic of the solution using the methods described above **\n", + "\n", + "## Best of luck!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Trees/Trees Interview Problems - PRACTICE/bst1.png b/Trees/Trees Interview Problems - PRACTICE/bst1.png new file mode 100644 index 0000000000000000000000000000000000000000..f4a93b03f362f40cc5c52f7a251c36a70131c638 GIT binary patch literal 61595 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 literal 0 HcmV?d00001 diff --git a/Trees/Trees Interview Problems - PRACTICE/bst_trim.png b/Trees/Trees Interview Problems - PRACTICE/bst_trim.png new file mode 100644 index 0000000000000000000000000000000000000000..095025c9ecb3166fcdcb5b5c1fc5edf2576b1d36 GIT binary patch literal 33369 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 literal 0 HcmV?d00001 diff --git a/Trees/Trees Interview Problems - PRACTICE/tree_print.png b/Trees/Trees Interview Problems - PRACTICE/tree_print.png new file mode 100644 index 0000000000000000000000000000000000000000..dfbdb2b786d107a3c782f601988ae9d646fea06a GIT binary patch literal 30513 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 @N#zk6*`4x>4KT+Y(X ziu&^pr{$aPFUk1uD5Nr0Q-KDyK*kU0ahRke5!9qzOIrOBz_wFl>9HzI0ENpZHS+Q9~0w(I@?_^>6%Wg+}4d zz{t$CnQ8gsmxkrlW8;r}3YodL`D82eqjR_Azn)u_LwokBROY5)1@4BlGY0G0JX()- z;)km063oC|ymd!@?=uPcjgylKcAFO)+j`ec0oq2!1w~)|#Wgv%;FV|gPqb<%Gib7F zk}+ghV)(V&*>ARBdl75=D1qr5rps^3|MdD8Ec9b5%Oi5k0drr4)cpEe*W?#Bs;I>K zp#PfVn=ReeADdePSo@|sqlPBFWmx08yCN7rq?<#2=WpGXKYnpQK7Rs(*BXkUAD!d& zuz!5-7Pg0FNnoJF2B4DtM~`^YQeGQTB+Pl%w)=Dv=itywsyfA0N4Vyp-gOA=y=63&gD#2 zZqDA7fA_^nd3tJ4n{rg>hwez@KfHTGzI&-4&povd`Y#UkfsVMAZf3>g-%x2FOUm4Z zZ2`YIx_ub_E6K&1H|5`aZcLs(Jf zqv3!lbHfEU?Y5N7cavX!cRO3=9LA(-d-mE*`NNYb`O-5J;JF#nb^GtWzqb!khD6`I zFfBj0ioJVNdlXEprTn4>PT@Vj2wc{0z&j}sP} z4E}>KSlq|R$#DOud==|J<}v0;Fl%$)P0=T-@_=QoVV!5bQ{LD(kOoImD9DaZ?v=lLZ&5B_12rAP zZR9otv?0tR?A3q${Y3>cM-COAxc#*WvV@td+mFe-rU4pQTgL|a zB-@P3w@=^3VxNi@?ncDj?>F*{QgC`PBY$^#PNqi2FdP?vF&ZwO@5*C~uHJNa^2SXQ z{k!qR>`{sI&$UA7Z&+E|62^&`E33R}}_U<%>H@Q^RfPXzQHUu=qe-Y!u-+ONw zi-$1ik7a{A2@2^$8ewP#8PY4LHt-||<;Yd42ZQg=eg*zCQ93Sjc6J*S{DJvK4EYFR~ ze5_HohAlCux)du zId961nHBlvt&&U)_v=s^E0ogi%6p4$a)46Coqy+EX=48E&lTR%$241E-E>>OOdEx< ze`HAh@!|^B#h9gE@I#@|gHf07a(+@6ZVW@Hl;5MM`Njv=OzXzb*jeQ~r0019p zNklMCY&k^{PH+UP#S zkgI@D5`3>e5{UcO&-Kg;Q8Jik7=r4jUFuoXCkKyUi5;gSAm=G zyIqbFidKq#dT{~!~gPC*7kJ00gZac5Vz;j@&TmtP$CM3Qk5V8O>N@U-jm_&pDEl{CgF+U zx__-E3;|nVk;T@%zV985pi9R4cFcx6CRF*3i^VcU$5s{fvu#@sBM<9Gd|$unu(<=MJ);v0aYwBSN`&XH^PK zSZKn^xEj*F7wrbP4(-UN``OI{(o9GCO{FGZ*V1mW(?L4|b80;dDcyj9PUexOD!@rb z+2PF6F4rqEk0Yl!*iJi(lTDMc5gkZpMq5rxrS;^B*OhDgnc|I(2*&>mmYG#><=TxH zjvk|lE{$7*8b3z#FbsYS-*rXzNtat@uqbF6XL%o+8iF61Jb>Q^aHPEiqb*lwaZX}r zuvIBrQQG)5ug=>Zd|^I{Wmq)@AndqvD-ML^VfA4($nVfg#xPFC&numM=Dp=1UUCMN zs}#@Q$;fB1h{=bs+0Bg4GMWt?=%9g`t1~&wLz|O)+0?7E`Lb6VQ8(?jtni+avdkmp zY9Is*!7^!d>Y0C2?kY)@R!cAf*jrwi7F~;W^T0!!F5Jz^>rYp)OrpIuME&B=8bI>{ zrO-+ii_@_TbT3XO)oD&<-X@|6+XovJuIdNxos7|k%^RCoPsk^~b~r8*H~_r_i~PU3 zR+Jkhb5t+E3j06;t*yv2%Q)Kw zd5YtxVk4cq3RUBD(cYbJd~aZ9%8Q4hvOmrtPSVxR2u3~S)}5l9S*oMuBd_?~@j$}# z+40Y3x8pOshJq29Tg4h{w4(8t*%;yWw$*zkNvaa zr1WBL1)D~SGJ;lwRmTRw=XC%Laef<%^SMfjYYPZ)4b@Rwx>ICyaE3eP-ucV1!yHL4O!WFy)gnsrVP`Km%iJH9s}lMy$oT^U*_$=eI4eiTz~ zx?NuQo;cUfd~a_Me-w1D!1(z*HXJ9gTSP0PtrYG!HhHh=256YaadHb#X9ge~EbUn3 zxhdM)Wd>V?(1c!kDk@(_rG|yG4!0lXD(>Db%X<)(JW>%#N1HbKbm+9?=%e$F9YwCU zUaEOz8iHp8I(2uMcO}Q~Yp8CwXwzy-F%Rqdn8m*3VY1%u5q` zS|$%$aj55%G?Xa(*QUKYMw8c8o-Hj18&Fzchhx5s?N<$)IAF-5gua1F$O0qns);#% z8M~?|mJhD?Hf0VEQtQaWeC{%A;~i9CW9(vEKU=5=M%PD~!Gl1_ck7IL#wTXTzHML0 zE2dt;uBR33B4HoG)1`Lw1~epe8e6Bt6Eu3HCTde)Vu+TptFu>=7@^qdphwj`^6Q7A zXd+;s5TZJST^ZCNwF7`sZ9s&xV`-cdAJf#R47gjV@CIo!d0MY8ptf=thaC(rj&x`> z-<_Gb=Mx!QhYndpTxc`YKPNTp$?TlOp$fGFZ%c$JksS`op$&W;|<#*?< zMZ0~e05A{EH@5c7W3~i4hRCzm=PDcc>;SY%DFm!T9jIWKjtjRbCH1{cL$8R$6%UiO zkFG2zV+!aTO-;n*ET##pu^vO6*lVIFj9l$H46`if68V}y{4f@0S&HgbG z)2zW|-qbiFz}Ko{*5f9xjDxKMJ3$qU!+O22&xWw3h3Jlie$6{K-F&0Zh)3g7FL=Xv zk+&MazCv1-H}tnT9LcrY6aNj4fD&{L2j;~ zPRi)omDwE$zBp;Ep`CdG{~~CK$D-`<*5y4+&Ya5BO`i#U3D$=Q&RJ(~ha(+r$Jh-2 zZ2U}!|J+W?7Zrhd2H)SRV zZn}FXN`IPHRuq8H4t@3Zz1g?OGw9X$0G4+CHy<7i4yNdFj7C2UJ3?4h^N{$MBKVD` z!qNv@Bp&cGhk<}=OBG22*;J`cp9+#)CSE36P(l2Uzh(z%t`ZTBtBg%SO~AE_d42 z8{aV>WWE+Mu3foOubcj(@t{&5Qc7x8;$9V*X|}T1x-qF}Q;l%Yf}m2-C+u(>NeSz( zI!NkU(*^m-g{+*zsR2!$vP;JMKU=hj^JA$7(gcGa~`2EWn zIkno5*bv~y_|Se(*Q_A&2GioZHO^s1$2ap}3zMBJm9QG=nh3V^f>Chffhvyb_e@HY zGifq1=BWL|H*Lozk>8r=gIv6W(+HqQW(r_Bz`bWEEaTYWO!ez`A;A`Zu`2VBHc%&f z(C*O9s5=rfAf_PjVIdEVxU)=MzT27E${ivg?Hti!gsjM|@^JB$>2zerl?K&7tD>nN zpw$DF=*n%J1A|WST-0}Or%i%Yy0(}6Gt6L z8HiZcI(Mul9j3<^NDnt1L~s}mjhmQ!tc_u-Z)mCuod_L=Wm%fsu1`C^cYpOZYVz$5 zR#l%XqtX&5UJP^m&NKb;g?(Y{kPgeq0k3?09`-6w@M{ZoeY%+z`4z^&M;x}?P8UR8 zXo7(1rcuL~k520BlP!nVGnhram_L?HIaii%y}cywW*aCc@Ca+^|J|#wzcT2TVT^VR z)^R#8{o?1QwiBf$_I6r^SAO(H*s<&kXE@OV(8h@PKop$=bmEvn0@R(50gs8!ogE`T z05mWpj7g8@#*Li?57rWY<+%YZSP!Gyse!$P;k@I%N`QySRP82W6Q^kMU3z|Jq`jeT#}?|}@c zvcM1r0iDlQEL{jmLk;zRt* z0pqZGqz$>*tI~vcqL}!KdCN+>9~HY-x!dyQ)s(k$1-%?6=5QZ#M78biN>z$zMfw1~ z+2xYl%2gH6VeI-D$Kg$vAZ{awr7bQQlCG0x`%F?@azR0O6n2wPuJ$;I2W*f(1Bj|YHK}n|9!1z@{<2`P{H~w*g;L-~2ydqzV z=;2QQ5Gfdnr;fxp?-$IBR`Z1N=*KKb%3qZQw0udw8M1Y!PuiI^zB5_088ufQYVkad zAH$+vi9s+-rabcD3QiqE2bjwpBHFJ&MTZWYrqsr%T#6OO$0*o(+bH>npW88?TpJ$4 z@q9zTr=gwY-uBr6XoGkI=tLxdBXaYS!P&N^A!EV`3w-?P|AZ3Vl-|MSo0B#GK- z!`8Vw9HyWCTkH|*L$mQq?1DM70y9!L?l=fy*fh21Q36f8%0TCswqF8E9)vJj&|USiM~}M z+_|wS!wIJSAVAh{()rUOrwZW9HE-2lhne5P(j17lr)uWsKRvKkN9KG}fh?k`8TKtt1Bq zaNrRvP;s{OLFi_F7@qv2F_urfo%KatG%%j!K^u$_9XRN! z=!A@-j6IOHtf}(kDVCf8bSsA$Au80x?`ezh$9uMEjibO4`zDkV=liBut(fA+zW{C~69{0rn+0d`N? z5uWA4Bm3gs3Kl(?Bk6hxu{D6U1M`4WoXgn<+@nA>TG43F)gWFDyyDo13TDkch z3&_9m_MF54;`5l)r_925yvEi6X!^C3x|%-vsX)+st9d!H7Znek1C`JZSg=+~1yG0s ziI5yk7395iK?1N>=ca>75%bW~A)gTt^wz~yS)9lD;R(OQF*F5LTqhkCv6Ah*X@DKf zz$dN5jAvcCyAuIF^01Nj#l1}&VF8P!&~uGRv2}CQ9YfD&rJaC=#HR(=<3oA*$y^>S zbKmA^XUxbS)#R1sy!`3UtMc*~`c4r@etalms+tx3^b$|=r5bvVGVjVM`*9f@GWvy~ znxx_>lsP0c^31%u-MWCLNaqT+qr+MG_(mQ*YaW?vS%v?(n+en;;`NOcdPOi{DqNU4prKY;t;0Dus%-LG+6#@ zhHmn{faZEnuqgX+o?!&rqXN)#w}WoYvjWeV`}0kkEKfDU0X^#M!>9A3!Fg+dHB=#0==OII65T!lo9>UlT&B756 zAz04e&hu!2+pcx7E=m-jypgB2~mpj+6 zpu7zGzwG^LjioQ^+QhW)>^FNgVC9oBS7P2WdB*veJh)jIhc%%;uvMCdN3cxwW)32t^H>Fclzk2 zdu=GbF=5z@XNv_n9xuwF5lCl;?(I-FY`UbKWgdp9uNW%ukXXiH(0%cf=6l z5KftT0mt9>=E`I*7!GyTxip zy}h*OG1m~OXXKU123iiBNrQ6Pi1wa@acb&y--x`wnjRooUxGQ`a5{r^&V5ixTq8c~mU}ntma47MPQ96OKFt=cq)(*&r}wqT+hkrG>%pX##KVtT57Z12B{^W z{iS_piMH4F7xx`A%~(pX2%iL)zc5ykeZxEp+?=|)ox@f(U0bMbx=)N%VL2%WeHxVu zwjsDE$f_SU+{ScUI=ip!(A{_15yCK47+`*5yoid0(`IpM7LUK9gj%mayW`pFvn}&D zTIMp!{4fMbsg{?Y&tnL=iJ?NYQd^_l=3r~I6U-j;mA-%xmm{MQLpyNDa@nY5S{KmF z1_QD-P)gTubT2LNKVM%$foA316?AU=F=M+Iwbf>~Epgj#2uiy48}rP+>%pD{#$|$~ zT1Cc?-seV3^3+HSQ|NEtUNfK@dGY~Nj{4E2$=;c( zrK|gDb7SAzXM1I1!)lzzc=G_%jL(e~HtluR8*YM|vNm2F|RO|&CU^1fKb7&y{<4PZWo37Y=?0niV1!#U4!qsqJ? zph+Z~bR(@WB7unk_O?&TGUny8I&HmLjcKh_0Fq2g8w0!CdIjk6(jj%Y9jcClgpP!B z^4u_+oH)Qdq=eanDmNm`9q;|zvof;HOYUx>;{RjK z1#D74>%3T(yA_r>S_$x|CCavecCPB=B}QC!k5N zZHB0N=<4dQVa!)83ixa7QlZeczaL^Kkm2mPiNj?JubjJfHB7t zeFe-m;rKTkd67b)4&rRT7?`{n!c2@0_Lp?Cc~63FqLKye^DSZZ7>+PoF3aUYTq@YE z<$+BQst9hnSecmRI4UCIp9~@8RC9B)=pRe!K4F@cZ(I}sU&JD&H_&+?ID%u5P`Xm zLPA+4S-ROm@jPyVN!L91ma$$uE0ft(xs(pcoiePl!lF+Ng-g1%QiE=epBm}x6eTW< zvqd)&;t*({3A#NM*&l&=ktoZalpmF-Pb+ahnp#%khp9JPdfiv%(+V=pGoEQd%O3!! zA;|V*R^{VN5O!72dDfC6?VLn%mAR7Ln|6-Ha~(@SDp(3zk;za=jwH)6fx-I}08G_V z4`oG}TlJFpxR=`$pcx4xGvkzI9jdA#kY0h{Dpo#aWITpdRhXK*l@H5u#Sc5q0ZG@n zTpUd|nPVbp<%dfMxe=2K^izSVBmm|;5fB!`S_RmJNG4+1)28mk8p_J_s3dbMlP@}CxxA5s0hCHWaxkN{T7wxaz?R_VESc77l}|ia$SO&aj83b_NU^tYP;V3E~ zme$?Ohh)AK1nsaF0@|zCkHv$ZsF1kxOx2B(E||%X6zERiHxjDKK9u=z6cc4Qwb+y0o-hXJ`DblcK$5wEawbp&pEUgF|3)xl314c3Vx)$1ldbq z*SXmcj%%e!I~V82unxK}1ll9mq=2;#JTIJM>z4L7Cbjs^w#HkbeanEh3}Z(@57gwa z4nUmG7cf1E*+dXqE@68O)~(jiTctfStV_}6g-tL4Ocy0|W%#|{Lr5GnxBa%PfX zW?@D#Ur!)gsk{}UY#txRm2~r0Y0(Xu(K2ae#_`WQbh3sKiV7rg2?bjP{hf4UwILSv zaz>JLQ#TAN-L%qAx}yr@okll#Nl+Ve2N=dgnJe9(on>CcmFu)gKP}akunAUaw^RQp zc-kWgV+}NoU~+L$5Urf0os&5n`)4I4?G#}5Q|9*#XiK22x$K>C+>(Uq755yw=6fE% z$RRkRM?*?$Q^xhY0c}zU+%SJ2hCenltev*0xgWwF2AFM}R$|%0CB2q*8hhk@6@X{w zR_O*1=tu`g2Dt8+OEoRcO23Ql$K4uPI(uE+v{Pc+vet6fvag`bK|9Kv6`%g;ly>OY zTq~nTC}S4d($6vvvCJJHKS)dbK!COcGt*Xbv5-k9fy^s^d}oLwWsuO0ZpMOBoeYE! zz!t+fOb{Xyfmw6k2@ zwA*s$JL=5bXJ~0+nR2$#mb>KvpZU#zo^AO3yKMoqP2Lh|ueOHTtMz9y?k2*0Z~c9e zuDxg`-Ds$tkq$$RrL+4=o_tbWFWT)pUajjzvwdg%Jm_^>0o|P$H!=KXpSugM`?))w zPujDk)8^YgchlMZZ2fuUjP6A07*qoM6N<$ Eg43C7*Z=?k literal 0 HcmV?d00001 diff --git a/Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Binary Search Tree Check - SOLUTION-checkpoint.ipynb b/Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Binary Search Tree Check - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..1ac09210 --- /dev/null +++ b/Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Binary Search Tree Check - SOLUTION-checkpoint.ipynb @@ -0,0 +1,155 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Search Tree Check - SOLUTION\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a binary tree, check whether it’s a binary search tree or not.\n", + "\n", + "** Again, no solution cell, just worry about your code making sense logically. Hint: Think about tree traversals. **\n", + "\n", + "## Solution\n", + "\n", + "Here is a simple solution- If a tree is a binary search tree, then traversing the tree inorder should lead to sorted order of the values in the tree. So, we can perform an inorder traversal and check whether the node values are sorted or not. " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "tree_vals = []\n", + "\n", + "def inorder(tree):\n", + " if tree != None:\n", + " inorder(tree.getLeftChild())\n", + " tree_vals.append(tree.getRootVal())\n", + " inorder(tree.getRightChild())\n", + " \n", + "def sort_check(tree_vals):\n", + " return tree_vals == sorted(tree_vals)\n", + "\n", + "inorder(tree)\n", + "sort_check(tree_vals)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another classic solution is to keep track of the minimum and maximum values a node can take. And at each node we will check whether its value is between the min and max values it’s allowed to take. The root can take any value between negative infinity and positive infinity. At any node, its left child should be smaller than or equal than its own value, and similarly the right child should be larger than or equal to. So during recursion, we send the current value as the new max to our left child and send the min as it is without changing. And to the right child, we send the current value as the new min and send the max without changing." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n" + ] + } + ], + "source": [ + "class Node:\n", + " def __init__(self, k, val):\n", + " self.key = k\n", + " self.value = val\n", + " self.left = None\n", + " self.right = None\n", + "\n", + "def tree_max(node):\n", + " if not node:\n", + " return float(\"-inf\")\n", + " maxleft = tree_max(node.left)\n", + " maxright = tree_max(node.right)\n", + " return max(node.key, maxleft, maxright)\n", + "\n", + "def tree_min(node):\n", + " if not node:\n", + " return float(\"inf\")\n", + " minleft = tree_min(node.left)\n", + " minright = tree_min(node.right)\n", + " return min(node.key, minleft, minright)\n", + "\n", + "def verify(node):\n", + " if not node:\n", + " return True\n", + " if (tree_max(node.left) <= node.key <= tree_min(node.right) and\n", + " verify(node.left) and verify(node.right)):\n", + " return True\n", + " else:\n", + " return False\n", + "\n", + "root= Node(10, \"Hello\")\n", + "root.left = Node(5, \"Five\")\n", + "root.right= Node(30, \"Thirty\")\n", + "\n", + "print(verify(root)) # prints True, since this tree is valid\n", + "\n", + "root = Node(10, \"Ten\")\n", + "root.right = Node(20, \"Twenty\")\n", + "root.left = Node(5, \"Five\")\n", + "root.left.right = Node(15, \"Fifteen\")\n", + "\n", + "print(verify(root)) # prints False, since 15 is to the left of 10" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a classic interview problem, so feel free to just Google search \"Validate BST\" for more information on this problem!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Tree Level Order Print - SOLUTION-checkpoint.ipynb b/Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Tree Level Order Print - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..015366eb --- /dev/null +++ b/Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Tree Level Order Print - SOLUTION-checkpoint.ipynb @@ -0,0 +1,113 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tree Level Order Print - SOLUTION\n", + "\n", + "Given a binary tree of integers, print it in level order. The output will contain space between the numbers in the same level, and new line between different levels. For example, if the tree is: \n", + "___\n", + "![title](tree_print.png)\n", + "___\n", + "The output should be: \n", + "\n", + " 1 \n", + " 2 3 \n", + " 4 5 6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "It won’t be practical to solve this problem using recursion, because recursion is similar to depth first search, but what we need here is breadth first search. So we will use a queue as we did previously in breadth first search. First, we’ll push the root node into the queue. Then we start a while loop with the condition queue not being empty. Then, at each iteration we pop a node from the beginning of the queue and push its children to the end of the queue. Once we pop a node we print its value and space.\n", + "\n", + "To print the new line in correct place we should count the number of nodes at each level. We will have 2 counts, namely current level count and next level count. Current level count indicates how many nodes should be printed at this level before printing a new line. We decrement it every time we pop an element from the queue and print it. Once the current level count reaches zero we print a new line. Next level count contains the number of nodes in the next level, which will become the current level count after printing a new line. We count the number of nodes in the next level by counting the number of children of the nodes in the current level. Understanding the code is easier than its explanation:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node:\n", + " def __init__(self, val=None):\n", + " self.left = None\n", + " self.right = None\n", + " self.val = val " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def levelOrderPrint(tree):\n", + " if not tree:\n", + " return\n", + " nodes=collections.deque([tree])\n", + " currentCount, nextCount = 1, 0\n", + " while len(nodes)!=0:\n", + " currentNode=nodes.popleft()\n", + " currentCount-=1\n", + " print currentNode.val,\n", + " if currentNode.left:\n", + " nodes.append(currentNode.left)\n", + " nextCount+=1\n", + " if currentNode.right:\n", + " nodes.append(currentNode.right)\n", + " nextCount+=1\n", + " if currentCount==0:\n", + " #finished printing current level\n", + " print '\\n',\n", + " currentCount, nextCount = nextCount, currentCount" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The time complexity of this solution is O(N), which is the number of nodes in the tree, so it’s optimal. Because we should visit each node at least once. The space complexity depends on maximum size of the queue at any point, which is the most number of nodes at one level. The worst case occurs when the tree is a complete binary tree, which means each level is completely filled with maximum number of nodes possible. In this case, the most number of nodes appear at the last level, which is (N+1)/2 where N is the total number of nodes. So the space complexity is also O(N). Which is also optimal while using a queue. \n", + "\n", + "Again, this is a very common tree interview question!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Trim a Binary Search Tree - SOLUTION-checkpoint.ipynb b/Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Trim a Binary Search Tree - SOLUTION-checkpoint.ipynb new file mode 100644 index 00000000..36e4317d --- /dev/null +++ b/Trees/Trees Interview Problems - SOLUTIONS/.ipynb_checkpoints/Trim a Binary Search Tree - SOLUTION-checkpoint.ipynb @@ -0,0 +1,100 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Trim a Binary Search Tree - SOLUTION\n", + "\n", + "## Problem Statement\n", + "\n", + "Given the root of a binary search tree and 2 numbers min and max, trim the tree such that all the numbers in the new tree are between min and max (inclusive). The resulting tree should still be a valid binary search tree. So, if we get this tree as input:\n", + "___\n", + "\n", + "![title](bst1.png)\n", + "___\n", + "and we’re given **min value as 5** and **max value as 13**, then the resulting binary search tree should be: \n", + "___\n", + "![title](bst_trim.png)\n", + "___\n", + "We should remove all the nodes whose value is not between min and max. \n", + "\n", + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "We can do this by performing a post-order traversal of the tree. We first process the left children, then right children, and finally the node itself. So we form the new tree bottom up, starting from the leaves towards the root. As a result while processing the node itself, both its left and right subtrees are valid trimmed binary search trees (may be NULL as well).\n", + "\n", + "At each node we’ll return a reference based on its value, which will then be assigned to its parent’s left or right child pointer, depending on whether the current node is left or right child of the parent. If current node’s value is between min and max (min<=node<=max) then there’s no action need to be taken, so we return the reference to the node itself. If current node’s value is less than min, then we return the reference to its right subtree, and discard the left subtree. Because if a node’s value is less than min, then its left children are definitely less than min since this is a binary search tree. But its right children may or may not be less than min we can’t be sure, so we return the reference to it. Since we’re performing bottom-up post-order traversal, its right subtree is already a trimmed valid binary search tree (possibly NULL), and left subtree is definitely NULL because those nodes were surely less than min and they were eliminated during the post-order traversal. Remember that in post-order traversal we first process all the children of a node, and then finally the node itself.\n", + "\n", + "Similar situation occurs when node’s value is greater than max, we now return the reference to its left subtree. Because if a node’s value is greater than max, then its right children are definitely greater than max. But its left children may or may not be greater than max. So we discard the right subtree and return the reference to the already valid left subtree. The code is easier to understand:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def trimBST(tree, minVal, maxVal): \n", + " \n", + " if not tree: \n", + " return \n", + " \n", + " tree.left=trimBST(tree.left, minVal, maxVal) \n", + " tree.right=trimBST(tree.right, minVal, maxVal) \n", + " \n", + " if minVal<=tree.val<=maxVal: \n", + " return tree \n", + " \n", + " if tree.valmaxVal: \n", + " return tree.left " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The complexity of this algorithm is O(N), where N is the number of nodes in the tree. Because we basically perform a post-order traversal of the tree, visiting each and every node one. This is optimal because we should visit every node at least once. This is a very elegant question that demonstrates the effectiveness of recursion in trees. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems - SOLUTIONS/Binary Search Tree Check - SOLUTION.ipynb b/Trees/Trees Interview Problems - SOLUTIONS/Binary Search Tree Check - SOLUTION.ipynb new file mode 100644 index 00000000..1ac09210 --- /dev/null +++ b/Trees/Trees Interview Problems - SOLUTIONS/Binary Search Tree Check - SOLUTION.ipynb @@ -0,0 +1,155 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Search Tree Check - SOLUTION\n", + "\n", + "## Problem Statement\n", + "\n", + "Given a binary tree, check whether it’s a binary search tree or not.\n", + "\n", + "** Again, no solution cell, just worry about your code making sense logically. Hint: Think about tree traversals. **\n", + "\n", + "## Solution\n", + "\n", + "Here is a simple solution- If a tree is a binary search tree, then traversing the tree inorder should lead to sorted order of the values in the tree. So, we can perform an inorder traversal and check whether the node values are sorted or not. " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "tree_vals = []\n", + "\n", + "def inorder(tree):\n", + " if tree != None:\n", + " inorder(tree.getLeftChild())\n", + " tree_vals.append(tree.getRootVal())\n", + " inorder(tree.getRightChild())\n", + " \n", + "def sort_check(tree_vals):\n", + " return tree_vals == sorted(tree_vals)\n", + "\n", + "inorder(tree)\n", + "sort_check(tree_vals)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another classic solution is to keep track of the minimum and maximum values a node can take. And at each node we will check whether its value is between the min and max values it’s allowed to take. The root can take any value between negative infinity and positive infinity. At any node, its left child should be smaller than or equal than its own value, and similarly the right child should be larger than or equal to. So during recursion, we send the current value as the new max to our left child and send the min as it is without changing. And to the right child, we send the current value as the new min and send the max without changing." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n" + ] + } + ], + "source": [ + "class Node:\n", + " def __init__(self, k, val):\n", + " self.key = k\n", + " self.value = val\n", + " self.left = None\n", + " self.right = None\n", + "\n", + "def tree_max(node):\n", + " if not node:\n", + " return float(\"-inf\")\n", + " maxleft = tree_max(node.left)\n", + " maxright = tree_max(node.right)\n", + " return max(node.key, maxleft, maxright)\n", + "\n", + "def tree_min(node):\n", + " if not node:\n", + " return float(\"inf\")\n", + " minleft = tree_min(node.left)\n", + " minright = tree_min(node.right)\n", + " return min(node.key, minleft, minright)\n", + "\n", + "def verify(node):\n", + " if not node:\n", + " return True\n", + " if (tree_max(node.left) <= node.key <= tree_min(node.right) and\n", + " verify(node.left) and verify(node.right)):\n", + " return True\n", + " else:\n", + " return False\n", + "\n", + "root= Node(10, \"Hello\")\n", + "root.left = Node(5, \"Five\")\n", + "root.right= Node(30, \"Thirty\")\n", + "\n", + "print(verify(root)) # prints True, since this tree is valid\n", + "\n", + "root = Node(10, \"Ten\")\n", + "root.right = Node(20, \"Twenty\")\n", + "root.left = Node(5, \"Five\")\n", + "root.left.right = Node(15, \"Fifteen\")\n", + "\n", + "print(verify(root)) # prints False, since 15 is to the left of 10" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a classic interview problem, so feel free to just Google search \"Validate BST\" for more information on this problem!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems - SOLUTIONS/Tree Level Order Print - SOLUTION.ipynb b/Trees/Trees Interview Problems - SOLUTIONS/Tree Level Order Print - SOLUTION.ipynb new file mode 100644 index 00000000..9b0ec477 --- /dev/null +++ b/Trees/Trees Interview Problems - SOLUTIONS/Tree Level Order Print - SOLUTION.ipynb @@ -0,0 +1,113 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tree Level Order Print - SOLUTION\n", + "\n", + "Given a binary tree of integers, print it in level order. The output will contain space between the numbers in the same level, and new line between different levels. For example, if the tree is: \n", + "___\n", + "![title](tree_print.png)\n", + "___\n", + "The output should be: \n", + "\n", + " 1 \n", + " 2 3 \n", + " 4 5 6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "It won’t be practical to solve this problem using recursion, because recursion is similar to depth first search, but what we need here is breadth first search. So we will use a queue as we did previously in breadth first search. First, we’ll push the root node into the queue. Then we start a while loop with the condition queue not being empty. Then, at each iteration we pop a node from the beginning of the queue and push its children to the end of the queue. Once we pop a node we print its value and space.\n", + "\n", + "To print the new line in correct place we should count the number of nodes at each level. We will have 2 counts, namely current level count and next level count. Current level count indicates how many nodes should be printed at this level before printing a new line. We decrement it every time we pop an element from the queue and print it. Once the current level count reaches zero we print a new line. Next level count contains the number of nodes in the next level, which will become the current level count after printing a new line. We count the number of nodes in the next level by counting the number of children of the nodes in the current level. Understanding the code is easier than its explanation:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node:\n", + " def __init__(self, val=None):\n", + " self.left = None\n", + " self.right = None\n", + " self.val = val " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def levelOrderPrint(tree):\n", + " if not tree:\n", + " return\n", + " nodes=collections.deque([tree])\n", + " currentCount, nextCount = 1, 0\n", + " while len(nodes)!=0:\n", + " currentNode=nodes.popleft()\n", + " currentCount-=1\n", + " print currentNode.val,\n", + " if currentNode.left:\n", + " nodes.append(currentNode.left)\n", + " nextCount+=1\n", + " if currentNode.right:\n", + " nodes.append(currentNode.right)\n", + " nextCount+=1\n", + " if currentCount==0:\n", + " #finished printing current level\n", + " print '\\n',\n", + " currentCount, nextCount = nextCount, currentCount" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The time complexity of this solution is O(N), which is the number of nodes in the tree, so it’s optimal. Because we should visit each node at least once. The space complexity depends on maximum size of the queue at any point, which is the most number of nodes at one level. The worst case occurs when the tree is a complete binary tree, which means each level is completely filled with maximum number of nodes possible. In this case, the most number of nodes appear at the last level, which is (N+1)/2 where N is the total number of nodes. So the space complexity is also O(N). Which is also optimal while using a queue. \n", + "\n", + "Again, this is a very common tree interview question!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Trees/Trees Interview Problems - SOLUTIONS/Trim a Binary Search Tree - SOLUTION.ipynb b/Trees/Trees Interview Problems - SOLUTIONS/Trim a Binary Search Tree - SOLUTION.ipynb new file mode 100644 index 00000000..cb59ddc4 --- /dev/null +++ b/Trees/Trees Interview Problems - SOLUTIONS/Trim a Binary Search Tree - SOLUTION.ipynb @@ -0,0 +1,100 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Trim a Binary Search Tree - SOLUTION\n", + "\n", + "## Problem Statement\n", + "\n", + "Given the root of a binary search tree and 2 numbers min and max, trim the tree such that all the numbers in the new tree are between min and max (inclusive). The resulting tree should still be a valid binary search tree. So, if we get this tree as input:\n", + "___\n", + "\n", + "![title](bst1.png)\n", + "___\n", + "and we’re given **min value as 5** and **max value as 13**, then the resulting binary search tree should be: \n", + "___\n", + "![title](bst_trim.png)\n", + "___\n", + "We should remove all the nodes whose value is not between min and max. \n", + "\n", + "___" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "We can do this by performing a post-order traversal of the tree. We first process the left children, then right children, and finally the node itself. So we form the new tree bottom up, starting from the leaves towards the root. As a result while processing the node itself, both its left and right subtrees are valid trimmed binary search trees (may be NULL as well).\n", + "\n", + "At each node we’ll return a reference based on its value, which will then be assigned to its parent’s left or right child pointer, depending on whether the current node is left or right child of the parent. If current node’s value is between min and max (min<=node<=max) then there’s no action need to be taken, so we return the reference to the node itself. If current node’s value is less than min, then we return the reference to its right subtree, and discard the left subtree. Because if a node’s value is less than min, then its left children are definitely less than min since this is a binary search tree. But its right children may or may not be less than min we can’t be sure, so we return the reference to it. Since we’re performing bottom-up post-order traversal, its right subtree is already a trimmed valid binary search tree (possibly NULL), and left subtree is definitely NULL because those nodes were surely less than min and they were eliminated during the post-order traversal. Remember that in post-order traversal we first process all the children of a node, and then finally the node itself.\n", + "\n", + "Similar situation occurs when node’s value is greater than max, we now return the reference to its left subtree. Because if a node’s value is greater than max, then its right children are definitely greater than max. But its left children may or may not be greater than max. So we discard the right subtree and return the reference to the already valid left subtree. The code is easier to understand:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def trimBST(tree, minVal, maxVal): \n", + " \n", + " if not tree: \n", + " return \n", + " \n", + " tree.left=trimBST(tree.left, minVal, maxVal) \n", + " tree.right=trimBST(tree.right, minVal, maxVal) \n", + " \n", + " if minVal<=tree.val<=maxVal: \n", + " return tree \n", + " \n", + " if tree.valmaxVal: \n", + " return tree.left " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The complexity of this algorithm is O(N), where N is the number of nodes in the tree. Because we basically perform a post-order traversal of the tree, visiting each and every node one. This is optimal because we should visit every node at least once. This is a very elegant question that demonstrates the effectiveness of recursion in trees. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Good Job!" + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Trees/Trees Interview Problems - SOLUTIONS/bst1.png b/Trees/Trees Interview Problems - SOLUTIONS/bst1.png new file mode 100644 index 0000000000000000000000000000000000000000..f4a93b03f362f40cc5c52f7a251c36a70131c638 GIT binary patch literal 61595 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 literal 0 HcmV?d00001 diff --git a/Trees/Trees Interview Problems - SOLUTIONS/bst_trim.png b/Trees/Trees Interview Problems - SOLUTIONS/bst_trim.png new file mode 100644 index 0000000000000000000000000000000000000000..095025c9ecb3166fcdcb5b5c1fc5edf2576b1d36 GIT binary patch literal 33369 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 literal 0 HcmV?d00001 diff --git a/Trees/Trees Interview Problems - SOLUTIONS/tree_print.png b/Trees/Trees Interview Problems - SOLUTIONS/tree_print.png new file mode 100644 index 0000000000000000000000000000000000000000..dfbdb2b786d107a3c782f601988ae9d646fea06a GIT binary patch literal 30513 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 @N#zk6*`4x>4KT+Y(X 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 Eg43C7*Z=?k literal 0 HcmV?d00001 diff --git a/Trees/Trees Interview Problems/.ipynb_checkpoints/Binary Search Tree Check-checkpoint.ipynb b/Trees/Trees Interview Problems/.ipynb_checkpoints/Binary Search Tree Check-checkpoint.ipynb new file mode 100644 index 00000000..74a68fe1 --- /dev/null +++ b/Trees/Trees Interview Problems/.ipynb_checkpoints/Binary Search Tree Check-checkpoint.ipynb @@ -0,0 +1,60 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Search Tree Check \n", + "\n", + "## Problem Statement\n", + "\n", + "Given a binary tree, check whether it’s a binary search tree or not.\n", + "\n", + "** Again, no solution cell, just worry about your code making sense logically. Hint: Think about tree traversals. **\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Code goes Here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a classic interview problem, so feel free to just Google search \"Validate BST\" for more information on this problem!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems/.ipynb_checkpoints/Tree Level Order Print-checkpoint.ipynb b/Trees/Trees Interview Problems/.ipynb_checkpoints/Tree Level Order Print-checkpoint.ipynb new file mode 100644 index 00000000..7d44b4d9 --- /dev/null +++ b/Trees/Trees Interview Problems/.ipynb_checkpoints/Tree Level Order Print-checkpoint.ipynb @@ -0,0 +1,79 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tree Level Order Print \n", + "\n", + "Given a binary tree of integers, print it in level order. The output will contain space between the numbers in the same level, and new line between different levels. For example, if the tree is: \n", + "___\n", + "![title](tree_print.png)\n", + "___\n", + "The output should be: \n", + "\n", + " 1 \n", + " 2 3 \n", + " 4 5 6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node:\n", + " def __init__(self, val=None):\n", + " self.left = None\n", + " self.right = None\n", + " self.val = val " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def levelOrderPrint(tree):\n", + " #Code here\n", + " pass" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems/.ipynb_checkpoints/Trim a Binary Search Tree -checkpoint.ipynb b/Trees/Trees Interview Problems/.ipynb_checkpoints/Trim a Binary Search Tree -checkpoint.ipynb new file mode 100644 index 00000000..b3aa23dd --- /dev/null +++ b/Trees/Trees Interview Problems/.ipynb_checkpoints/Trim a Binary Search Tree -checkpoint.ipynb @@ -0,0 +1,76 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Trim a Binary Search Tree \n", + "\n", + "## Problem Statement\n", + "\n", + "Given the root of a binary search tree and 2 numbers min and max, trim the tree such that all the numbers in the new tree are between min and max (inclusive). The resulting tree should still be a valid binary search tree. So, if we get this tree as input:\n", + "___\n", + "\n", + "![title](bst1.png)\n", + "___\n", + "and we’re given **min value as 5** and **max value as 13**, then the resulting binary search tree should be: \n", + "___\n", + "![title](bst_trim.png)\n", + "___\n", + "We should remove all the nodes whose value is not between min and max. \n", + "\n", + "___\n", + "** Feel free to reference the lecture on Binary Search Tree for the node class, but what it more important here is the logic of your function. In which case your function should be in the form:**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def trimBST(tree,minVal,maxVal):\n", + " \n", + " print tree.left # LeftChild\n", + " print tree.right # Right Child\n", + " print tree.val # Node's value\n", + " \n", + " pass\n", + "\n", + "# Use tree.left , tree.right , and tree.val as your methods to call" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** There is no solution cell because the nature of the code should be more logical and a test would essentially give away the answer. Just focus your answer to fill out the logic of the solution using the methods described above **\n", + "\n", + "## Best of luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems/Binary Search Tree Check.ipynb b/Trees/Trees Interview Problems/Binary Search Tree Check.ipynb new file mode 100644 index 00000000..74a68fe1 --- /dev/null +++ b/Trees/Trees Interview Problems/Binary Search Tree Check.ipynb @@ -0,0 +1,60 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binary Search Tree Check \n", + "\n", + "## Problem Statement\n", + "\n", + "Given a binary tree, check whether it’s a binary search tree or not.\n", + "\n", + "** Again, no solution cell, just worry about your code making sense logically. Hint: Think about tree traversals. **\n", + "\n", + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Code goes Here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a classic interview problem, so feel free to just Google search \"Validate BST\" for more information on this problem!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems/Tree Level Order Print.ipynb b/Trees/Trees Interview Problems/Tree Level Order Print.ipynb new file mode 100644 index 00000000..7d44b4d9 --- /dev/null +++ b/Trees/Trees Interview Problems/Tree Level Order Print.ipynb @@ -0,0 +1,79 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tree Level Order Print \n", + "\n", + "Given a binary tree of integers, print it in level order. The output will contain space between the numbers in the same level, and new line between different levels. For example, if the tree is: \n", + "___\n", + "![title](tree_print.png)\n", + "___\n", + "The output should be: \n", + "\n", + " 1 \n", + " 2 3 \n", + " 4 5 6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution\n", + "\n", + "Fill out your solution below:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "class Node:\n", + " def __init__(self, val=None):\n", + " self.left = None\n", + " self.right = None\n", + " self.val = val " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def levelOrderPrint(tree):\n", + " #Code here\n", + " pass" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems/Trim a Binary Search Tree .ipynb b/Trees/Trees Interview Problems/Trim a Binary Search Tree .ipynb new file mode 100644 index 00000000..b3aa23dd --- /dev/null +++ b/Trees/Trees Interview Problems/Trim a Binary Search Tree .ipynb @@ -0,0 +1,76 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Trim a Binary Search Tree \n", + "\n", + "## Problem Statement\n", + "\n", + "Given the root of a binary search tree and 2 numbers min and max, trim the tree such that all the numbers in the new tree are between min and max (inclusive). The resulting tree should still be a valid binary search tree. So, if we get this tree as input:\n", + "___\n", + "\n", + "![title](bst1.png)\n", + "___\n", + "and we’re given **min value as 5** and **max value as 13**, then the resulting binary search tree should be: \n", + "___\n", + "![title](bst_trim.png)\n", + "___\n", + "We should remove all the nodes whose value is not between min and max. \n", + "\n", + "___\n", + "** Feel free to reference the lecture on Binary Search Tree for the node class, but what it more important here is the logic of your function. In which case your function should be in the form:**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def trimBST(tree,minVal,maxVal):\n", + " \n", + " print tree.left # LeftChild\n", + " print tree.right # Right Child\n", + " print tree.val # Node's value\n", + " \n", + " pass\n", + "\n", + "# Use tree.left , tree.right , and tree.val as your methods to call" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "** There is no solution cell because the nature of the code should be more logical and a test would essentially give away the answer. Just focus your answer to fill out the logic of the solution using the methods described above **\n", + "\n", + "## Best of luck!" + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/Trees/Trees Interview Problems/bst1.png b/Trees/Trees Interview Problems/bst1.png new file mode 100644 index 0000000000000000000000000000000000000000..f4a93b03f362f40cc5c52f7a251c36a70131c638 GIT binary patch literal 61595 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 literal 0 HcmV?d00001 diff --git a/Trees/Trees Interview Problems/bst_trim.png b/Trees/Trees Interview Problems/bst_trim.png new file mode 100644 index 0000000000000000000000000000000000000000..095025c9ecb3166fcdcb5b5c1fc5edf2576b1d36 GIT binary patch literal 33369 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 literal 0 HcmV?d00001 diff --git a/Trees/Trees Interview Problems/tree_print.png b/Trees/Trees Interview Problems/tree_print.png new file mode 100644 index 0000000000000000000000000000000000000000..dfbdb2b786d107a3c782f601988ae9d646fea06a GIT binary patch literal 30513 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 @N#zk6*`4x>4KT+Y(X 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 Eg43C7*Z=?k literal 0 HcmV?d00001