├── presentations ├── trees_presentation_gmmowry.pptx ├── stacks_and_queues_amelia_downs.pptx ├── linkedlist_presentation_dalrayes.pptx ├── big_o_presentation_gmmowry.md ├── intro_to_whiteboarding_presentation_daniellekienzle.pptx ├── recursion_presentation_mjsteichen.md └── intro_to_whiteboarding_presentation_devdame.md ├── solutions ├── reverse_recursive_solution_fgv02009.rb ├── fibonnaci_recursive_solution_fgv02009.rb ├── factorials_recursive_solution_fgv02009.rb ├── linked_lists_sort_solutions_gmmowry.rb ├── intro_to_whiteboarding_flatten_solution_daniellekienzle.rb ├── linked_lists_zip_solutions_gmmowry.rb ├── intro_to_whiteboarding_counting_candy_solution_daniellekienzle.rb ├── recursion_is_palindrome_solution_arnamak.rb ├── recursion_is_palindrome_solution_mjsteichen.rb ├── recursive_person_creator_solution_arnamak.rb ├── big_o_reverse_a_string_solution_gmmowry.rb ├── linked_lists_add_two_lists_solution_gmmowry.rb ├── big_o_are_anagrams_solution_gmmowry.rb ├── linked_lists_find_beginning_of_loop_solutions_gmmowry.rb ├── trees_is_value_present_solution_gmmowry.rb ├── linked_lists_nth_node_from_end_solutions_gmmowry.rb ├── linked_lists_basic_methods_solutions_gmmowry.rb ├── trees_valid_solution_gmmowry.rb └── trees_delete_node_solution_gmmowry.rb ├── challenges ├── reverse_recursive_challenge_fgv02009.md ├── factorials_recursive_challenge_fgv02009.md ├── fibonacci_recursive_challenge_fgv02009.md ├── trees_valid_challenge_gmmowry.md ├── linked_lists_zip_challenge_gmmowry.md ├── linked_lists_sort_challenge_gmmowry.md ├── intro_to_whiteboarding_flatten_challenge_daniellekienzle.md ├── linked_lists_find_beginning_of_loop_challenge_gmmowry.md ├── trees_delete_node_challenge_gmmowry.md ├── linked_lists_nth_node_from_end_challenge_gmmowry.md ├── big_o_are_anagrams_challenge_gmmowry.md ├── trees_is_value_present_challenge_gmmowry.md ├── big_o_reverse_a_string_challenge_gmmowry.md ├── linked_lists_add_two_lists_challenge_gmmowry.md ├── linked_lists_basic_methods_challenge_gmmowry.md ├── recursion_is_palindrome_challenge_mjsteichen.md ├── intro_to_whiteboarding_counting_candy_challenge_daniellekienzle.md └── recursive_person_creator_challenge_arnamak.md └── README.md /presentations/trees_presentation_gmmowry.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmmowry/Whiteboarding-DBC-Chicago/HEAD/presentations/trees_presentation_gmmowry.pptx -------------------------------------------------------------------------------- /presentations/stacks_and_queues_amelia_downs.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmmowry/Whiteboarding-DBC-Chicago/HEAD/presentations/stacks_and_queues_amelia_downs.pptx -------------------------------------------------------------------------------- /presentations/linkedlist_presentation_dalrayes.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmmowry/Whiteboarding-DBC-Chicago/HEAD/presentations/linkedlist_presentation_dalrayes.pptx -------------------------------------------------------------------------------- /solutions/reverse_recursive_solution_fgv02009.rb: -------------------------------------------------------------------------------- 1 | def reverse(string) 2 | string.size < 2 ? string : string[-1] + reverse(string[1..-2]) + string[0] 3 | end 4 | 5 | puts reverse("Hello") == "olleH" -------------------------------------------------------------------------------- /challenges/reverse_recursive_challenge_fgv02009.md: -------------------------------------------------------------------------------- 1 | ## Reverse 2 | 3 | Write a recursive function that reverses a string 4 | 5 | *Example Input:* "Hello there" 6 | 7 | *Example Output:* "ereht olleH" -------------------------------------------------------------------------------- /presentations/big_o_presentation_gmmowry.md: -------------------------------------------------------------------------------- 1 | ##Glenna's Big O Presentation 2 | 3 | [Check it out here](https://docs.google.com/presentation/d/1qpk8rzx1q9PHwOPCdoD5XOjGRnUlPX2FOxH4FcGbzz0/edit?usp=sharing) -------------------------------------------------------------------------------- /challenges/factorials_recursive_challenge_fgv02009.md: -------------------------------------------------------------------------------- 1 | ## Factorials 2 | 3 | Write a recursive function that returns n! 4 | Reminder: 7! = 7*6*5*4*3*2*1 5 | 6 | *Example Input:* 9 7 | 8 | *Example Output:* 362880 -------------------------------------------------------------------------------- /presentations/intro_to_whiteboarding_presentation_daniellekienzle.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmmowry/Whiteboarding-DBC-Chicago/HEAD/presentations/intro_to_whiteboarding_presentation_daniellekienzle.pptx -------------------------------------------------------------------------------- /presentations/recursion_presentation_mjsteichen.md: -------------------------------------------------------------------------------- 1 | ##Michael's Recursion Presentation 2 | 3 | [Check it out here](https://docs.google.com/presentation/d/1HXz4P_-gO2ZBoqisZeagu9KVn1TDEgUSycBVYPZFSRM/edit?usp=sharing) 4 | -------------------------------------------------------------------------------- /presentations/intro_to_whiteboarding_presentation_devdame.md: -------------------------------------------------------------------------------- 1 | ##Lauren's Big O Presentation 2 | 3 | [Check it out here!](https://docs.google.com/presentation/d/1uWRG3KJDgC-I6ukUHEwmFFmEbmVOzwP438PQo1ue-Q0/edit?usp=sharing) 4 | -------------------------------------------------------------------------------- /solutions/fibonnaci_recursive_solution_fgv02009.rb: -------------------------------------------------------------------------------- 1 | def fibonacci(n) 2 | if n == 1 3 | return 0 4 | elsif n == 2 5 | return 1 6 | end 7 | 8 | fibonacci(n-1) + fibonacci(n-2) 9 | end 10 | 11 | puts fibonacci(10) == 34 12 | -------------------------------------------------------------------------------- /challenges/fibonacci_recursive_challenge_fgv02009.md: -------------------------------------------------------------------------------- 1 | ## Fibonacci 2 | 3 | The fibonacci sequence: 0,1,1,2,3,5,8,13,21... 4 | 5 | Write a recursive function to output me the nth fibonacci number. 6 | 7 | *Example Input:* 10 8 | 9 | *Example Output:* 34 -------------------------------------------------------------------------------- /challenges/trees_valid_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | Write a method that takes in a binary tree and returns true -- if the tree is a binary search tree. 2 | 3 | **HINTS** 4 | First Way: Think about how many parameters you need to pass in. 5 | Second Way: Use (and write out) helper methods -------------------------------------------------------------------------------- /challenges/linked_lists_zip_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | Implement LinkedList#zip (again, no arrays!) 2 | 3 | LinkedList#zip accepts one argument which is a LinkedList object, and returns one LinkedList object 4 | list1 = [0,2,4,6] 5 | list2 = [1,3,5,7] 6 | p list1.zip(list2) # returns LinkedList object [0,1,2,3,4,5,6,7] 7 | p list2.zip(list1) # returns LinkedList object [1,0,3,2,5,4,7,6] -------------------------------------------------------------------------------- /challenges/linked_lists_sort_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | Implement LinkedList#sort (I shouldn’t have to say it, but I will – NO ARRAYS!) 2 | 3 | LinkedList#sort sorts a Linked List, with nodes whose values are all integers, from smallest to largest based on node value. It accepts no arguments, and it returns a sorted LinkedList object. 4 | list=[1,0,3,2,5,4,7,6] 5 | list.sort # returns LinkedList object [0,1,2,3,4,5,6,7] -------------------------------------------------------------------------------- /solutions/factorials_recursive_solution_fgv02009.rb: -------------------------------------------------------------------------------- 1 | def factorial_recursive(n) 2 | return 1 if n == 0 || n == 1 3 | n * factorial_recursive(n-1) 4 | end 5 | 6 | def factorial_iterative(n) 7 | product = n 8 | 9 | while n > 1 10 | product *= (n-1) 11 | n -= 1 12 | end 13 | 14 | return product 15 | end 16 | 17 | puts factorial_recursive(8) == 40320 18 | puts factorial_iterative(8) == 40320 -------------------------------------------------------------------------------- /challenges/intro_to_whiteboarding_flatten_challenge_daniellekienzle.md: -------------------------------------------------------------------------------- 1 | # Create the Ruby method *flatten* 2 | * takes one array argument that may have multiple nested arrays 3 | * outputs a new one-dimensional array 4 | (i.e. for every element in the input array, extract its elements into the new array) 5 | 6 | ### Example: 7 | input = [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] 8 | flatten(input) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -------------------------------------------------------------------------------- /challenges/linked_lists_find_beginning_of_loop_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | ## Find beginning of loop in linked list 2 | 3 | Given a circular linked list, implement an algorithm which returns the node at the beginning of the loop 4 | Resource: Cracking the Coding Interview by Gayle Laakmann McDowell 5 | 6 | ###Solutions 7 | [Amadou's Solution](https://github.com/adowns01/Intro-to-Whiteboarding-DBC/blob/master/solutions/linked_list_find_beginning_of_loop_amadou.rb) -------------------------------------------------------------------------------- /solutions/linked_lists_sort_solutions_gmmowry.rb: -------------------------------------------------------------------------------- 1 | class LinkedList 2 | def sort 3 | output_list = LinkedList.new(self.remove(0)) 4 | to_add = self.remove(0) 5 | until to_add == nil 6 | counter = 0 7 | until output_list[counter].value > to_add.value 8 | counter += 1 9 | end 10 | output_list.insert(to_add) 11 | to_add = self.remove(0) 12 | end 13 | output_list 14 | end 15 | end 16 | 17 | -------------------------------------------------------------------------------- /challenges/trees_delete_node_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | Write a function that deletes a node from a binary search tree. 2 | 3 | 4 | Given this tree: 5 | 6 | 5 7 | / \ 8 | 3 9 9 | / \ / \ 10 | 2 4 8 10 11 | / / 12 | 1 7 13 | 14 | Delete 9 and make this tree: 15 | 16 | 5 17 | / \ 18 | 3 8 19 | / \ / \ 20 | 2 4 7 10 21 | / 22 | 1 -------------------------------------------------------------------------------- /challenges/linked_lists_nth_node_from_end_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | ## nth node from end of linked list 2 | 3 | Write a function, nth_node_from_end, that takes a head of a singly Linked List and a number n and returns the nth node from the end of the Linked List. 4 | 5 | Example, for list: 1 => 2 => 3 => 4 => 5, if head is the first node and n = 2, the function returns node with value 4 6 | 7 | ###Solutions 8 | [Amadou's Solution](https://github.com/adowns01/Intro-to-Whiteboarding-DBC/blob/master/solutions/linked_list_nth_node_from_end_amadou.rb) -------------------------------------------------------------------------------- /solutions/intro_to_whiteboarding_flatten_solution_daniellekienzle.rb: -------------------------------------------------------------------------------- 1 | 2 | def flatten(array) 3 | flattened = [] 4 | 5 | array.each do |item| 6 | if item.kind_of? Array 7 | flattened += flatten(item) 8 | else 9 | flattened << item 10 | end 11 | end 12 | flattened 13 | end 14 | 15 | # Tests 16 | puts flatten([1]) == [1] 17 | puts flatten([1, 2, 3, 4, 5]) == [1, 2, 3, 4, 5] 18 | puts flatten([[1], 2, 3, [4, 5]]) == [1, 2, 3, 4, 5] 19 | puts flatten([1, [2, [3, 4], 5]]) == [1, 2, 3, 4, 5] -------------------------------------------------------------------------------- /challenges/big_o_are_anagrams_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | #Are Anagrams? 2 | Write the method are_anagrams? that takes two strings as arguments and returns true if they are anagrams of each other or false if they are not. 3 | 4 | Explain the time and space complexity of your algorithm. 5 | 6 | 7 | **Examples:** 8 | ```code 9 | are_anagrams?(“dbc”, “cdb”) #=> true 10 | are_anagrams?(“dbc”, “pizzarules”) #=> false 11 | ``` 12 | 13 | **Bonus:** Can you do it without using the Ruby method #sort? 14 | 15 | ###Solutions 16 | add a link to your solution here :) 17 | -------------------------------------------------------------------------------- /solutions/linked_lists_zip_solutions_gmmowry.rb: -------------------------------------------------------------------------------- 1 | 2 | # Question 2 3 | 4 | class LinkedList 5 | 6 | def zip(other_list) 7 | output_list = LinkedList.new(left.remove(0)) 8 | left = self 9 | right = other_list 10 | output_list.head.next = right.remove(0) 11 | take_from_left = true 12 | until left.head == nil && right.head == nil 13 | if take_from_left 14 | output_list.add_node_to_end(left.remove(0)) 15 | else 16 | output_list.add_node_to_end(right.remove(0)) 17 | end 18 | take_from_left = !take_from_left 19 | end 20 | output_list 21 | end 22 | 23 | end -------------------------------------------------------------------------------- /challenges/trees_is_value_present_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | #Is Value in Binary Search Tree? 2 | 3 | Write the function *is_value_present?* that takes the root node of a ***binary search tree*** and an integer as arguments and returns true or false if the integer is in the tree. 4 | 5 | [Here's code for a binary search tree generator for testing, but you should really make your own in the end :)](https://github.com/adowns01/Intro-to-Whiteboarding-DBC/blob/master/solutions/bst_generator.rb) 6 | 7 | ###Solutions 8 | [Amelia's Solution - Ruby](https://github.com/adowns01/Intro-to-Whiteboarding-DBC/blob/master/solutions/is_value_present_in_tree_amelia.rb) -------------------------------------------------------------------------------- /challenges/big_o_reverse_a_string_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | ## Reverse a String 2 | 3 | **Write a function to reverse a string in place. 4 | "In place" means "without creating a new string in memory."** 5 | 6 | Hints can be found at the oirginal source: [Reverse a string](https://www.interviewcake.com/question/reverse-string-in-place). 7 | Origionally from: Interview Cake 8 | 9 | ###Solutions 10 | [Amelia's Solution](https://github.com/adowns01/Intro-to-Whiteboarding-DBC/blob/master/solutions/reverse-a-string-amelia.rb) 11 | 12 | [Anna's Solution](https://github.com/shinshinwu/Intro-to-Whiteboarding-DBC/blob/master/solutions/reverse-a-string-anna.rb) 13 | 14 | 15 | -------------------------------------------------------------------------------- /solutions/intro_to_whiteboarding_counting_candy_solution_daniellekienzle.rb: -------------------------------------------------------------------------------- 1 | def count_candy(instructions) 2 | jars = {} 3 | total_candy = 0 4 | 5 | # create jars 6 | (1..instructions.first).each do |jar| 7 | jars[jar] = 0 8 | end 9 | 10 | # fill jars 11 | instructions[1..-1].each do |instruction| 12 | (instruction[0]..instruction[1]).each do |jar| 13 | jars[jar] += instruction.last 14 | total_candy += instruction.last 15 | end 16 | end 17 | 18 | # return average 19 | total_candy/jars.count 20 | end 21 | 22 | # Test 23 | instructions = [5,[1,2,100],[2,5,100],[3,4,100]] 24 | puts count_candy(instructions) == 160 -------------------------------------------------------------------------------- /solutions/recursion_is_palindrome_solution_arnamak.rb: -------------------------------------------------------------------------------- 1 | module Palindrome 2 | ### One-line solution for giggles 3 | def self.is_palindrome(str) 4 | (str.slice!(0).casecmp(str.slice!(-1)) == 0 ? is_palindrome(str) : false) if str.length > 1 5 | end 6 | end 7 | 8 | ### The more readable version of that, if that's what you're into. 9 | def self.readability_palindrome(str) 10 | return false unless str.length > 1 11 | if str.slice!(0).casecmp(str.slice!(-1)) == 0 12 | readability_palindrome(str) 13 | else 14 | return false 15 | end 16 | end 17 | 18 | Palindrome.is_palindrome("tacocat") 19 | Palindrome.is_palindrome("cat") == false 20 | Palindrome.is_palindrome("7TaCOCat7") 21 | -------------------------------------------------------------------------------- /challenges/linked_lists_add_two_lists_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | ## Add two linked lists 2 | 3 | You have two numbers represented by a linked list, where each node contains a single digit. The digits are stored in reversed order, such that the 1’s digit is at the head of the list. Write a function, add_two_lists, that adds the two numbers and returns the sum as a linked list. 4 | Example: 5 | Input: (3 => 1 => 5), (5 => 9 => 2) # represent 513, 295 6 | Output: 8 => 0 => 8 # represent 808 7 | 8 | Resource: Cracking the Coding Interview by Gayle Laakmann McDowell 9 | 10 | ###Solutions 11 | [Amadou's Solution](https://github.com/adowns01/Intro-to-Whiteboarding-DBC/blob/master/solutions/linked_list_add_two_lists_amadou.rb) -------------------------------------------------------------------------------- /challenges/linked_lists_basic_methods_challenge_gmmowry.md: -------------------------------------------------------------------------------- 1 | Implement three basic methods (#[], #insert, #remove) in the LinkedList class. Do not use any arrays in these methods! 2 | 3 | -LinkedList#[] accepts one argument which is an integer representing the position in the linked list of the node you want, and returns the Node object at that position 4 | 5 | -LinkedList#insert accepts two arguments which are an instance of the Node class and an integer representing the position in the list at which the node is to be inserted, and returns the Node object that was inserted 6 | 7 | -LinkedList#remove accepts one argument which is an “index” number in the linked list, and returns the Node object which is removed from the LinkedList -------------------------------------------------------------------------------- /challenges/recursion_is_palindrome_challenge_mjsteichen.md: -------------------------------------------------------------------------------- 1 | #Is palindrome? 2 | 3 | Please write a method to check whether a given string is a palindrome. Only letters and numbers matter. Capitalization does not matter. 4 | A palindrome is a word, phrase, number, or other sequence of characters which reads the same backward or forward. 5 | 6 | ```Ruby 7 | is_palindrome('') => true 8 | is_palindrome(‘wow’) => true 9 | is_palindrome(‘! 5Wo w4?/’) => true 10 | is_palindrome(‘wo’) => false 11 | 12 | ``` 13 | 14 | ###Solutions 15 | Add links to your solutions here: 16 | - [Michael's Recursive is_palindrome solution ](https://github.com/gmmowry/Whiteboarding-DBC-Chicago/blob/master/solutions/recursion_is_palindrome_solution_mjsteichen.rb) -------------------------------------------------------------------------------- /challenges/intro_to_whiteboarding_counting_candy_challenge_daniellekienzle.md: -------------------------------------------------------------------------------- 1 | #Counting Candy 2 | 3 | Filling Jars: 4 | You have a bunch of jars labeled 1 to N. 5 | 6 | You are given a set of instructions detailing how much candy to put in each jar. 7 | 8 | After you finish all the instructions, you need to return the average number of candies in each jar. 9 | 10 | *Example Input:* [5,[1,2,100],[2,5,100],[3,4,100]] 11 | 12 | *Explaining the Input*: 13 | - The first element in the array is the number of jars 14 | - The rest of the elements are [starting jar, ending jar, the number of candies to add to each jar] 15 | - [1, 2, 100] means: add 100 candies to jars 1-2 16 | - [2, 5, 100] means: add 100 candies to jars 2-5 17 | - [3, 4, 100] means: add 100 candies to jars 3-4 18 | 19 | *Example Output:* 160 20 | -------------------------------------------------------------------------------- /solutions/recursion_is_palindrome_solution_mjsteichen.rb: -------------------------------------------------------------------------------- 1 | def is_palindrome?(submitted) 2 | sanitized = sanitize_input(submitted) 3 | check_if_palindrome(sanitized) ? true : false 4 | end 5 | 6 | def check_if_palindrome(sanitized_string) 7 | sanitized_string.length <= 1 ? true : sanitized_string.slice!(0) == sanitized_string.slice!(-1) && check_if_palindrome(sanitized_string) 8 | end 9 | 10 | def sanitize_input(submitted_string) 11 | #downcase and filter out any non-alphanumeric characters 12 | submitted_string.downcase.gsub(/\W/,'') 13 | end 14 | 15 | ################################## 16 | p is_palindrome?("a") 17 | p is_palindrome?(" ") 18 | p is_palindrome?("2e2") 19 | p is_palindrome?("LoL") 20 | p is_palindrome?("aMaM") == false 21 | p is_palindrome?("racecar") 22 | p is_palindrome?("??46*(") == false 23 | p is_palindrome?("! 5Bo b5?") 24 | p is_palindrome?("0Rib On NObi R0") 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Whiteboarding-DBC-Chicago 2 | 3 | This is the repository containing all questions, solutions, and presentations for Whiteboarding Sessions for DBC Chicago. 4 | 5 | ## Feedback 6 | 7 | All the session leads and organizers would love your feedback after you attend a Whiteboarding Session. Please use this link to let us know how we're doing. 8 | 9 | [Feedback Form] (http://bit.ly/chi-whiteboarding-feedback) 10 | 11 | ## Resources & Links 12 | 13 | [Interview Cake] (https://www.interviewcake.com) 14 | [Interview Cake - Big O] (https://www.interviewcake.com/article/big-o-notation-time-and-space-complexity) 15 | [Interview This] (https://github.com/ChiperSoft/InterviewThis/blob/master/README.md) 16 | [Big O Cheat Sheet] (http://bigocheatsheet.com/) 17 | [UC Berkeley Algorithm Course Video] (https://www.youtube.com/watch?v=QMV45tHCYNI) 18 | 19 | There are more links to resources in almost all presentations, check there for more! 20 | 21 | -------------------------------------------------------------------------------- /solutions/recursive_person_creator_solution_arnamak.rb: -------------------------------------------------------------------------------- 1 | require 'csv' 2 | 3 | class Person 4 | def initialize(args={}) 5 | @first_name = args[:first_name] 6 | @last_name = args[:last_name] 7 | @email = args[:email] 8 | end 9 | end 10 | 11 | ################################################################################################## 12 | 13 | module RecursivePersonCreator 14 | 15 | def self.import(raw_csv) 16 | @tabled_csv = CSV.table(raw_csv) 17 | pop_csv(@tabled_csv) 18 | end 19 | 20 | def self.pop_csv(tabled_csv) 21 | if tabled_csv[1] 22 | single_csv_line = tabled_csv.delete(0) 23 | hashify_csv_values(single_csv_line) 24 | else 25 | puts "done" 26 | end 27 | end 28 | 29 | def self.hashify_csv_values(single_csv_line) 30 | hashed_csv_person = single_csv_line.to_hash 31 | instantiate_person(hashed_csv_person) 32 | end 33 | 34 | def self.instantiate_person(hashed_csv_person) 35 | Person.new(**hashed_csv_person) 36 | pop_csv(@tabled_csv) 37 | end 38 | 39 | end 40 | 41 | RecursivePersonCreator.import('people.csv') #=> done 42 | -------------------------------------------------------------------------------- /challenges/recursive_person_creator_challenge_arnamak.md: -------------------------------------------------------------------------------- 1 | ## Recursive People Creator 2 | 3 | Take a CSV file which contains a person's first and last name, email address, and whatever else your heart desires (because we're on whiteboards and there is no CSV file), and create a recursive solution for creating each row into Person objects. 4 | 5 | We're all probably familiar with the good 'ol ```CSV.foreach('people.csv') {|row| Person.new(row)}``` solution, which is probably as efficient and basic anyone will ever need it to be. But that's no fun. So, let's bring on recursion. 6 | 7 | Where to start: 8 | 9 | * Don't worry about the syntax for dealing with CSVs if you don't remember it, the recursive logic is what's important here. Ask if someone's available to answer, and if not just leave a comment with pseudocode for any CSV syntax along with what you want it to do specifically, and move on for now. 10 | * Remember that recursion is a very broad concept, and not tied to the term "recursive method". 11 | * Don't worry about defining the Person class. For now let's assume it is a very simple class which only contains an initialize method and the properties of "first name", "last name", "email address", etc. Basically whatever data you'd like to use to make the Person from the CSV is included in the Person class. 12 | 13 | ### Solutions 14 | Add a link to your solution here: 15 | 16 | * [arnamak's Recursive People Creator solution](https://github.com/gmmowry/Whiteboarding-DBC-Chicago/blob/master/solutions/recursive_person_creator_solution_arnamak.rb) 17 | 18 | #### Resources: 19 | [Link to a basic 200-person CSV file](http://pastebin.com/J0mF3YrW) 20 | 21 | -------------------------------------------------------------------------------- /solutions/big_o_reverse_a_string_solution_gmmowry.rb: -------------------------------------------------------------------------------- 1 | # Write a function to reverse a string in place. "In place" means "without creating a new string in memory." 2 | 3 | # Solution 4 | 5 | # PSEUDOCODE 6 | # We return the string itself if its length is less than 2 7 | # We define 2 variables, i and j; i starts at 0 and j start at the end of the input string (string length - 1) 8 | # We iterate as long as i is less than or equal to j. 9 | # We swap the values of the string at position i and j. 10 | # We then increment i and decrement j 11 | 12 | def reverse(string) 13 | len = string.length 14 | return string if len < 2 15 | i = 0 16 | j = len - 1 17 | while i <= j 18 | # swap string[i] with string[j] 19 | temp = string[i] 20 | string[i] = string[j] 21 | string[j] = temp 22 | # Increment i and decrement j 23 | i += 1 24 | j -= 1 25 | end 26 | string 27 | end 28 | 29 | # TEST DRIVE 30 | p reverse("") == "" 31 | p reverse("a") == "a" 32 | p reverse("Hi") == "iH" 33 | p reverse("I love programming") == "gnimmargorp evol I" 34 | 35 | 36 | 37 | # question: 38 | # Write a function to reverse a string in place. 39 | 40 | 41 | def reverse(str) 42 | 43 | len = str.length 44 | 45 | (len/2).times do |i| 46 | str[i], str[-1-i] = str[-1-i], str[i] 47 | end 48 | 49 | return str 50 | end 51 | 52 | 53 | # test 54 | puts reverse("algorithms") == "smhtirogla" 55 | 56 | def reversed_string(string) 57 | arr = [] 58 | i = string.length 59 | j = 0 60 | while i > 0 do 61 | arr[j] = string[i-1] 62 | j += 1 63 | i -= 1 64 | end 65 | return arr.join 66 | end 67 | 68 | puts reversed_string("hello") == "olleh" -------------------------------------------------------------------------------- /solutions/linked_lists_add_two_lists_solution_gmmowry.rb: -------------------------------------------------------------------------------- 1 | require_relative 'linked_list_implementation_amadou' 2 | 3 | # You have two numbers represented by a linked list, where each node contains a single digit. 4 | # The digits are stored in reversed order, such that the 1’s digit is at the head of the list. 5 | # Write a function, add_two_lists, that adds the two numbers and returns the sum as a linked list. 6 | # Example: 7 | # Input: (3 => 1 => 5), (5 => 9 => 2) # represent 513, 295 8 | # Output: 8 => 0 => 8 # represent 808 9 | 10 | def add_two_lists(head1, head2) 11 | add_two_lists_helper(head1, head2, 0) 12 | end 13 | 14 | def add_two_lists_helper(head1, head2, carry) 15 | return nil if !head1 && !head2 16 | 17 | sum = carry 18 | 19 | sum += head1.value if head1 20 | sum += head2.value if head2 21 | 22 | value = sum % 10 23 | carry = sum / 10 24 | 25 | result_head = Node.new(value) 26 | 27 | next_head1 = (head1 == nil ? nil : head1.next_node) 28 | next_head2 = (head2 == nil ? nil : head2.next_node) 29 | 30 | remaining_nodes = add_two_lists_helper(next_head1, next_head2, carry) 31 | 32 | result_head.next_node = remaining_nodes 33 | 34 | result_head 35 | end 36 | 37 | 38 | # TEST DRIVE 39 | f = Node.new(2, nil) 40 | e = Node.new(9, f) 41 | d = Node.new(5, e) 42 | 43 | c = Node.new(5, nil) 44 | b = Node.new(1, c) 45 | a = Node.new(3, b) 46 | 47 | list1 = LinkedList.new(a) # 3 -> 1 -> 5 (represents number 513) 48 | list2 = LinkedList.new(d) # 5 -> 9 -> 2 (represents number 295) 49 | 50 | print "list1 is: " 51 | list1.each {|node| print node.value, " => "} 52 | 53 | print "nil\nlist2 is: " 54 | list2.each {|node| print node.value, " => "} 55 | 56 | list_sum = add_two_lists(a, d) # 8 -> 0 -> 8 (represents 808 i.e 513 + 295) 57 | print "nil\nlist1 + list 2 gives: " 58 | LinkedList.new(list_sum).each {|n| print n.value, " => "} 59 | puts "nil" -------------------------------------------------------------------------------- /solutions/big_o_are_anagrams_solution_gmmowry.rb: -------------------------------------------------------------------------------- 1 | # Write the method are_anagrams? that takes two strings as arguments and returns true if they are anagrams of each other or false if they are not. 2 | 3 | # Explain the time and space complexity of your algorithm. 4 | 5 | # Bonus: Can you do it without using the Ruby method #sort? 6 | 7 | # SOLUTION 8 | 9 | # a) Using Ruby's sort method: 10 | # PSEUDOCODE 11 | # We return false if the 2 strings have different length 12 | # We split each input string, sort the arrays that result from the string splitting, and compare the 2 sorted arrays. 13 | 14 | def are_anagrams?(string1, string2) 15 | return false if string1.length != string2.length 16 | return string1.chars.sort == string2.chars.sort 17 | end 18 | 19 | # b) Time and space complexity 20 | #: 0(n) time and 0(1) space 21 | 22 | # c) Bonus: without using the Ruby #sort method 23 | 24 | # PSEUDOCODE 25 | # We return false if the 2 strings have different lengths 26 | # We define a hash with default value of 0 27 | # We add to the hash each character from the 1st input string 28 | # We iterate through the 2nd input string, and for each character in it, we return false if the hash 29 | # value of that character is less than 1; otherwise, we decrement it by 1 30 | # We iterate through the hash and return false if any of the values is not 0 31 | # We return true at the end 32 | 33 | def are_anagrams_2?(string1, string2) 34 | return false if string1.length != string2.length 35 | hash = Hash.new(0) 36 | string1.chars.each {|character| hash[character] += 1} 37 | string2.chars.each do |letter| 38 | return false if hash[letter] < 1 39 | hash[letter] -= 1 40 | end 41 | hash.each_value {|v| return false if v != 0} 42 | true 43 | end 44 | 45 | 46 | # TEST 47 | p are_anagrams?("dbc", "cdb") == true 48 | p are_anagrams?("dbc", "pizzarules") == false 49 | 50 | p are_anagrams_2?("dbc", "cdb") == true 51 | p are_anagrams_2?("dbc", "pizzarules") == false 52 | -------------------------------------------------------------------------------- /solutions/linked_lists_find_beginning_of_loop_solutions_gmmowry.rb: -------------------------------------------------------------------------------- 1 | require_relative 'linked_list_implementation_amadou' 2 | 3 | # Given a circular linked list, implement an algorithm which returns the node at the beginning of the loop (cracking the coding interview) 4 | 5 | # Example: 6 | # Input: A -> B -> C -> D -> E -> C [the same C as earlier] 7 | # Output: C 8 | 9 | # SOLUTION 10 | # We'll use Floyd's cycle-finding algorithm: http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare 11 | 12 | # PSEUDOCODE 13 | # 1) We create 2 nodes, fast_pointer and slow_pointer 14 | # 2) We move fast_pointer (respectively, slow_pointer) at a rate of 2 (resp. 1) nodes until they meet. 15 | # 3) Error check: case where there is no collision, i.e. no loop 16 | # we return nil if either fast_pointer or fast_pointer.next is nil 17 | # 4) At this point, the 2 pointers have met. 18 | # We then move slow_pointer to the beginning of the list; each of them is now at the same distance from the beginning of the loop 19 | # In a new iteration, we move them both at the same rate of 1 (moving them at this same rate means they will meet at the beginning of the loop). 20 | # 5) At the end of the iteration above, both nodes point to the beginning of the loop. 21 | 22 | def find_beginnig_of_loop(head) 23 | return nil if !head 24 | fast_pointer = head 25 | slow_pointer = head 26 | 27 | while fast_pointer && fast_pointer.next_node 28 | fast_pointer = fast_pointer.next_node.next_node 29 | slow_pointer = slow_pointer.next_node 30 | break if slow_pointer == fast_pointer # collision occurs 31 | end 32 | 33 | # Error check: case were there is no collision 34 | return nil if fast_pointer == nil || fast_pointer.next_node == nil 35 | 36 | slow_pointer = head 37 | while slow_pointer != fast_pointer 38 | fast_pointer = fast_pointer.next_node 39 | slow_pointer = slow_pointer.next_node 40 | end 41 | 42 | # At this point, both fast_pointer and slow_pointer point to the beginning of the loop; just return one of them 43 | slow_pointer 44 | end -------------------------------------------------------------------------------- /solutions/trees_is_value_present_solution_gmmowry.rb: -------------------------------------------------------------------------------- 1 | # Binary Search Tree generator code 2 | 3 | class Node 4 | attr_accessor :value, :left_child, :right_child 5 | def initialize(value) 6 | @value = value 7 | @left_child = nil 8 | @right_child = nil 9 | end 10 | end 11 | 12 | 13 | def make_BST(size) 14 | nums = (0..size).to_a.shuffle 15 | root = Node.new(nums.shift) 16 | while !nums.empty? 17 | add_node(root, Node.new(nums.shift)) 18 | end 19 | return root 20 | end 21 | 22 | def add_node(root, node) 23 | if node.value < root.value 24 | if root.left_child == nil 25 | # puts "root value: #{root.value} has left child #{node.value}" 26 | root.left_child = node 27 | return 28 | else 29 | add_node(root.left_child, node) 30 | end 31 | else 32 | if root.right_child == nil 33 | root.right_child = node 34 | # puts "root value: #{root.value} has right child #{node.value}" 35 | return 36 | else 37 | add_node(root.right_child, node) 38 | end 39 | end 40 | return root 41 | end 42 | 43 | 44 | # BST is_value_present? solution 45 | 46 | class Node 47 | attr_accessor :value, :left_child, :right_child 48 | def initialize(value) 49 | @value = value 50 | @left_child = nil 51 | @right_child = nil 52 | end 53 | end 54 | 55 | root = Node.new(8) 56 | root.left_child = Node.new(3) 57 | root.right_child = Node.new(10) 58 | root.left_child.left_child = Node.new(1) 59 | root.left_child.right_child = Node.new(6) 60 | root.left_child.right_child.left_child = Node.new(4) 61 | root.left_child.right_child.right_child = Node.new(7) 62 | 63 | def is_value_present(root, value) 64 | return false if root == nil 65 | 66 | if root.value == value 67 | return true 68 | elsif root.value > value 69 | return is_value_present(root.left_child, value) 70 | else 71 | return is_value_present(root.right_child, value) 72 | end 73 | 74 | end 75 | 76 | #TESTS 77 | p is_value_present(root, 8) 78 | p is_value_present(root, 7) 79 | p is_value_present(root, 4) 80 | p is_value_present(root, 11) 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /solutions/linked_lists_nth_node_from_end_solutions_gmmowry.rb: -------------------------------------------------------------------------------- 1 | require_relative 'linked_list_implementation_amadou' 2 | 3 | # Problem: Write a function, nth_node_from_end, that takes a head of a singly Linked List and a number n and returns the nth node from the end of the Linked List. 4 | # Example, for list: 1 => 2 => 3 => 4 => 5; 5 | # if head is the first node and n = 2, the function returns node with value 4 6 | 7 | 8 | # PSEUDOCODE 9 | # We return nil if the input head is nil, or if input n < 1, or if the size of linked list starting at head is less than input n. 10 | # We create 2 pointers, result_pointer and front_pointer, and we initialize them to the input head. 11 | # We advance front_pointer by n-1 nodes; this means that the 2 pointers will be separated by n nodes. 12 | # Next, we advance both pointers at a rate of 1 until front_pointer reaches the last node (i.e front_pointer's next node is nil); 13 | # When front_pointer reaches the last node of the list, this means that result_pointer is at the nth node from the last node since the 2 nodes are separated by a distance of n. 14 | # We return result_pointer 15 | 16 | def nth_node_from_end(head, n) 17 | return nil if !head || n < 1 18 | # Error check: return nil if the size of the linked list is < n 19 | return nil if LinkedList.new(head).length < n # Return nil if n is greater than the length of the linked list 20 | 21 | result_pointer = head 22 | front_pointer = head 23 | 24 | count = 0 25 | # Advance front_pointer by n-1 nodes 26 | while count < n - 1 27 | front_pointer = front_pointer.next_node # go to next node 28 | count += 1 # increment count 29 | end 30 | 31 | # Now move both pointers until front_pointer reaches the last node 32 | while front_pointer.next_node != nil 33 | result_pointer = result_pointer.next_node 34 | front_pointer = front_pointer.next_node 35 | end 36 | result_pointer 37 | end 38 | 39 | # TEST DRIVE 40 | e = Node.new(5, nil) 41 | d = Node.new(4, e) 42 | c = Node.new(3, d) 43 | b = Node.new(2, c) 44 | a = Node.new(1, b) 45 | 46 | # p nth_node_from_end(a, 2) # will return node d (of value 4) 47 | p nth_node_from_end(a, 2).value == 4 48 | p nth_node_from_end(a, 5).value == 1 # returns node a (of value 1) 49 | p nth_node_from_end(a, 6) == nil # 6 is > the length of the list, 5 50 | p nth_node_from_end(d, 3) == nil # 3 > 2 (length of list starting at d) -------------------------------------------------------------------------------- /solutions/linked_lists_basic_methods_solutions_gmmowry.rb: -------------------------------------------------------------------------------- 1 | class Node 2 | attr_accessor :value, :next 3 | def initialize(value) 4 | @value = value 5 | end 6 | end 7 | 8 | 9 | class LinkedList 10 | attr_accessor :head, :size 11 | 12 | # initially, there is no 'head' and 13 | # the size of the list is 0 14 | def initialize 15 | @head = nil 16 | @size = 0 17 | end 18 | 19 | def [](position) 20 | current_node = @head 21 | counter = 0 22 | until counter == position 23 | current_node = current_node.next 24 | counter += 1 25 | end 26 | current_node 27 | end 28 | 29 | def insert(node = Node.new, position) 30 | node.next = self[position] 31 | if position == 0 32 | self.head = node 33 | else 34 | self[position - 1].next = node 35 | end 36 | end 37 | 38 | def remove(position) 39 | removed = self[position] 40 | if position == 0 41 | @head = @head.next if @head != nil 42 | else 43 | self[position - 1].next = self[position + 1] 44 | end 45 | removed 46 | end 47 | 48 | end 49 | 50 | 51 | 52 | 53 | # Another way of solving 'insert' and 'remove' 54 | 55 | # if index is zero, due bubble sorty thing 56 | # to re-assign a new head. otherwise, loop 57 | # through to the index before desired, set 58 | # new_node.next to current.next, set current.next 59 | # to new_node 60 | def add_at_index(value, index) 61 | bounds_check(index) 62 | new_node = Node.new(value) 63 | 64 | if index == 0 65 | dummy_node = @head 66 | @head = new_node 67 | @head.next = dummy_node 68 | else 69 | current = @head 70 | counter = 0 71 | while counter < index 72 | if counter == index - 1 73 | new_node.next = current.next 74 | current.next = new_node 75 | end 76 | current = current.next 77 | counter += 1 78 | end 79 | end 80 | @size += 1 81 | end 82 | 83 | # if we remove the head, we simply assign 84 | # head to head's reference. otherwise, set our current.next 85 | # to current.next.next, skipping over the no longer 86 | # needed node 87 | def remove_at_index(index) 88 | bounds_check(index) 89 | 90 | if index == 0 91 | @head = @head.next 92 | else 93 | current = @head 94 | counter = 0 95 | while counter < index 96 | current.next = current.next.next || nil if counter == index - 1 97 | counter += 1 98 | end 99 | end 100 | @size -= 1 101 | end 102 | -------------------------------------------------------------------------------- /solutions/trees_valid_solution_gmmowry.rb: -------------------------------------------------------------------------------- 1 | # Base Classes -------------------------------------- 2 | 3 | class Node 4 | attr_accessor :value 5 | def initialize(value) 6 | @value = value 7 | end 8 | end 9 | 10 | class Tree 11 | attr_accessor :root, :left, :right 12 | 13 | def initialize(root=nil, left=nil, right=nil) 14 | @root = root 15 | @left = left 16 | @right = right 17 | end 18 | end 19 | 20 | # Methods -------------------------------------- 21 | 22 | def empty_tree 23 | Tree.new 24 | end 25 | 26 | def make_tree(value, left, right) 27 | root = Node.new(value) 28 | Tree.new(root, left, right) 29 | end 30 | 31 | def isEmpty?(tree) 32 | tree.root ? false : true 33 | end 34 | 35 | def left(tree) 36 | tree.left 37 | end 38 | 39 | def right(tree) 40 | tree.right 41 | end 42 | 43 | def leaf(value) 44 | make_tree(value, empty_tree, empty_tree) 45 | end 46 | 47 | # Creating Binary Search Tree -------------------------------------- 48 | require 'pp' 49 | 50 | def insert(new_value, bst = empty_tree) 51 | if isEmpty?(bst) 52 | return leaf(new_value) 53 | elsif new_value < bst.root.value 54 | return make_tree( bst.root.value, insert( new_value, bst.left), bst.right ) 55 | elsif new_value > bst.root.value 56 | return make_tree( bst.root.value, bst.left, insert(new_value, bst.right) ) 57 | else 58 | puts "Error." 59 | end 60 | end 61 | 62 | bst = insert(3) 63 | bst = insert(5, bst) 64 | bst = insert(1, bst) 65 | bst = insert(2, bst) 66 | bst = insert(4, bst) 67 | # pp bst 68 | 69 | # Is Valid Tree -------------------------------------- 70 | # Solution 1 -------------------------------------- 71 | 72 | def is_bst(bst = empty_tree) 73 | return isEmpty?(bst) || ( ( all_smaller(bst.left, bst.root.value) && is_bst(bst.left) ) && all_bigger(bst.right, bst.root.value) && is_bst(bst.right) ) 74 | end 75 | 76 | def all_smaller(bst, value) 77 | return isEmpty?(bst) || (bst.root.value < value && all_smaller(bst.left, value) && all_smaller(bst.right, value)) 78 | end 79 | 80 | def all_bigger(bst, value) 81 | return isEmpty?(bst) || (bst.root.value > value && all_bigger(bst.left, value) && all_bigger(bst.right, value)) 82 | end 83 | 84 | # pp is_bst(bst) 85 | 86 | # Solution 2 -------------------------------------- 87 | def is_bst?(bst = empty_tree, min, max) 88 | if isEmpty?(bst) 89 | return true 90 | elsif (bst.root.value > min) && (bst.root.value < max) && is_bst?(bst.left, min, bst.root.value) && is_bst?(bst.right, bst.root.value, max) 91 | return true 92 | else 93 | return false 94 | end 95 | end 96 | 97 | p "---------" 98 | min = -1.0/0.0 #-Infinity 99 | max = 1.0/0.0 #Infinity 100 | 101 | p is_bst?(bst, min, max) 102 | p is_bst(bst) -------------------------------------------------------------------------------- /solutions/trees_delete_node_solution_gmmowry.rb: -------------------------------------------------------------------------------- 1 | # Base Classes -------------------------------------- 2 | 3 | class Node 4 | attr_accessor :value 5 | def initialize(value) 6 | @value = value 7 | end 8 | end 9 | 10 | class Tree 11 | attr_accessor :root, :left, :right 12 | 13 | def initialize(root=nil, left=nil, right=nil) 14 | @root = root 15 | @left = left 16 | @right = right 17 | end 18 | end 19 | 20 | # Methods -------------------------------------- 21 | 22 | def empty_tree 23 | Tree.new 24 | end 25 | 26 | def make_tree(value, left, right) 27 | root = Node.new(value) 28 | Tree.new(root, left, right) 29 | end 30 | 31 | def isEmpty?(tree) 32 | tree.root ? false : true 33 | end 34 | 35 | def left(tree) 36 | tree.left 37 | end 38 | 39 | def right(tree) 40 | tree.right 41 | end 42 | 43 | def leaf(value) 44 | make_tree(value, empty_tree, empty_tree) 45 | end 46 | 47 | # Creating Binary Search Tree -------------------------------------- 48 | require 'pp' 49 | 50 | def insert(new_value, bst = empty_tree) 51 | if isEmpty?(bst) 52 | return leaf(new_value) 53 | elsif new_value < bst.root.value 54 | return make_tree( bst.root.value, insert( new_value, bst.left), bst.right ) 55 | elsif new_value > bst.root.value 56 | return make_tree( bst.root.value, bst.left, insert(new_value, bst.right) ) 57 | else 58 | puts "Error." 59 | end 60 | end 61 | 62 | # Deleting a Node -------------------------------------- 63 | 64 | # If node is a leaf, remove it 65 | # If the node has one child that is not-empty, 'move up' the subtree 66 | # If the node has two children that are not-empty, 67 | 68 | def delete(target_value, bst) 69 | if isEmpty?(bst) 70 | return bst 71 | else 72 | if target_value < bst.root.value #delete from left subtree 73 | return make_tree(bst.root.value, delete(target_value, bst.left), bst.right) 74 | elsif target_value > bst.root.value #delete from right subtree 75 | return make_tree(bst.root.value, bst.left, delete(target_value, bst.right)) 76 | else # item to be deleted is bst.root 77 | if isEmpty?(bst.left) 78 | return bst.right 79 | elsif isEmpty?(bst.left) 80 | return bst.left 81 | else 82 | return make_tree(smallestNode(bst.right), bst.left, removeSmallestNode(bst.right)) 83 | end 84 | end 85 | end 86 | end 87 | 88 | def smallestNode(bst) 89 | if isEmpty?(bst.left) #substittue for isEmpty? 90 | return bst.left 91 | else 92 | smallestNode(bst.left) 93 | end 94 | end 95 | 96 | def removeSmallestNode(bst) 97 | if isEmpty?(bst.left) #substittue for isEmpty? 98 | return bst.right 99 | else 100 | return make_tree(bst.root.value, removeSmallestNode(bst.left), bst.right) 101 | end 102 | end 103 | 104 | 105 | # bst = delete(1, bst) 106 | # bst = delete(3, bst) 107 | # pp bst 108 | 109 | bst = insert(5) 110 | bst = insert(1, bst) 111 | bst = insert(2, bst) 112 | bst = insert(3, bst) 113 | bst = insert(4, bst) 114 | bst = insert(6, bst) 115 | bst = insert(7, bst) 116 | bst = insert(8, bst) 117 | bst = insert(9, bst) 118 | bst = insert(10, bst) 119 | pp bst 120 | p '-' * 50 121 | bst = delete(3, bst) 122 | pp bst --------------------------------------------------------------------------------