├── README.md ├── Recusrion-and-Dynamic-Programming ├── nth-fibonacci-number.py └── triple-step.py ├── Trees-and-Graphs ├── check-balanced.py ├── list-of-depths.py ├── minimal-tree.py ├── route-between-nodes.py ├── successor.py └── validate-BST.py ├── arrays-and-strings ├── URLify.py ├── check-permutation.py ├── is-unique.py ├── one-away.py ├── palindrome-permutation.py ├── rotate-matrix.py ├── string-compression.py ├── string-rotation.py └── zero-matrix.py ├── linked-lists ├── delete-middle-node.py ├── intersection.py ├── loop-detection.py ├── palindrome.py ├── partition.py ├── remove-dups.py ├── return-kth-element-to-last.py └── sum-lists.py └── stacks-and-queues ├── animal-shelter.py ├── queue-via-stacks.py ├── sort-stack.py ├── stack-min.py ├── stack-of-plates.py └── three-in-one.py /README.md: -------------------------------------------------------------------------------- 1 | # Cracking the Coding Interview 2 | Solutions to the problems from book Cracking the Coding Interview 3 | 4 | Topics Covered: 5 | - [x] [Arrays and Strings](arrays-and-strings/) 6 | - [x] [Linked Lists](linked-lists/) 7 | - [x] [Stacks and Queues](stacks-and-queues/) 8 | - [ ] [Trees and Graphs](Trees-and-Graphs/) 9 | - [ ] [Recusrion and Dynamic Programming](Recusrion-and-Dynamic-Programming/) 10 | -------------------------------------------------------------------------------- /Recusrion-and-Dynamic-Programming/nth-fibonacci-number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Compute the nth Fibonacci Number. 3 | """ 4 | # Recusive Approach 5 | # Time Complexity -> O(2^n) 6 | def fib_recursive(n): 7 | if n <= 1: 8 | return n 9 | 10 | return fib_recursive(n-1) + fib_recursive(n-2) 11 | 12 | 13 | # Top Down Approach (or Memoization) 14 | # Time Complexity -> O(n) 15 | # Space Complexity -> O(n) 16 | def fib(n): 17 | memo = [0] * (n+1) 18 | 19 | def fib_recursive(n, memo): 20 | if n <= 1: 21 | return n 22 | 23 | if memo[n] == 0: 24 | memo[n] = fib_recursive(n-1, memo) + fib_recursive(n-2, memo) 25 | 26 | return memo[n] 27 | 28 | return fib_recursive(n, memo) 29 | 30 | 31 | # Bottom Up Approach 32 | # Time Complexity -> O(n) 33 | # Space Complexity -> O(1) 34 | def fib_bottom_up(n): 35 | if n <= 1: 36 | return n 37 | 38 | a, b = 0, 1 39 | 40 | for _ in range(2, n+1): 41 | a, b = b, a + b 42 | 43 | return b 44 | -------------------------------------------------------------------------------- /Recusrion-and-Dynamic-Programming/triple-step.py: -------------------------------------------------------------------------------- 1 | """ 2 | A child is running up a staircase with n steps and can hop either 1 step, 2 steps or 3 steps at a time. 3 | Implement a method to count how many possible ways the child can run up the satirs. 4 | """ 5 | # Recursive Method 6 | def countWays(n): 7 | memo = [-1]*(n+1) 8 | return countWaysRecursive(n,memo) 9 | 10 | def countWaysRecursive(n, memo): 11 | if n < 0: 12 | return 0 13 | elif n == 0: 14 | return 1 15 | elif memo[n] > -1: 16 | return memo[n] 17 | else: 18 | memo[n] = countWaysRecursive(n-1, memo) + countWaysRecursive(n-2, memo) + countWaysRecursive(n-3, memo) 19 | return memo[n] 20 | 21 | # Iterative Method 22 | def countWaysIterative(n) : 23 | memo = [-1] * (n + 1) 24 | memo[0] = 1 25 | memo[1] = 1 26 | memo[2] = 2 27 | for i in range(3, n + 1) : 28 | memo[i] = memo[i - 1] + memo[i - 2] + memo[i - 3] 29 | return memo[n] -------------------------------------------------------------------------------- /Trees-and-Graphs/check-balanced.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement a function to check if a binary tree is balanced. For the purposes of this question, a balanced tree is defined 3 | to be a tree such that the heights of the two subtrees of any node never differ by more than one. 4 | """ 5 | class Solution(object): 6 | def isBalanced(self, root): 7 | def check(root): 8 | if root is None: 9 | return 0 10 | left = check(root.left) 11 | right = check(root.right) 12 | if left == -1 or right == -1 or abs(left - right) > 1: 13 | return -1 14 | return 1 + max(left, right) 15 | return check(root) != -1 -------------------------------------------------------------------------------- /Trees-and-Graphs/list-of-depths.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a binary tree, design an algorithm which creates a linked list of all the nodes at each depth 3 | (eg: if you have a tree with Depth D, you'll have D linked lists). 4 | """ 5 | class node: 6 | def __init__(self, data = None): 7 | self.data = data 8 | self.next = None 9 | 10 | class LinkedList: 11 | def __init__(self): 12 | self.head = node() 13 | 14 | def append(self, data): 15 | new_node = node(data) 16 | cur = self.head 17 | while cur.next != None: 18 | cur = cur.next 19 | cur.next = new_node 20 | 21 | class Solution(object): 22 | def levelOrder(self, root): 23 | if root is None: 24 | return [] 25 | 26 | current, res, level = [root], {}, 0 27 | 28 | while current: 29 | nex = [] 30 | temp = LinkedList() 31 | for n in current: 32 | temp.append(n.val) 33 | if n.left: 34 | nex.append(n.left) 35 | if n.right: 36 | nex.append(n.right) 37 | current = nex 38 | res[level] = temp.head 39 | level += 1 40 | for i in res: 41 | self.display(res[i]) 42 | print("") 43 | 44 | def display(self, head): 45 | cur = head 46 | while cur.next != None: 47 | cur = cur.next 48 | print(cur.data) -------------------------------------------------------------------------------- /Trees-and-Graphs/minimal-tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a sorted(increasing order) array with unique integer elements, 3 | write an algorithm to create a binary search tree with minimal height. 4 | """ 5 | # class TreeNode(object): 6 | # def __init__(self, x): 7 | # self.val = x 8 | # self.left = None 9 | # self.right = None 10 | 11 | def createMinimalBST(nums): 12 | if not nums: 13 | return None 14 | mid = (len(nums)-1)//2 15 | root = TreeNode(nums[mid]) 16 | root.left = createMinimalBST(nums[:mid]) 17 | root.right = createMinimalBST(nums[mid+1:]) 18 | return root -------------------------------------------------------------------------------- /Trees-and-Graphs/route-between-nodes.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a directed graph, design an algorithm to find out whether there is a route between two nodes. 3 | """ 4 | def connectedTo(graph, start, d): 5 | if start == d: 6 | return True 7 | visited, queue = set(), [start] 8 | visited.add(start) 9 | while queue: 10 | vertex = queue.pop(0) 11 | if vertex == d: 12 | return True 13 | for neighbour in graph[vertex]: 14 | if neighbour not in visited: 15 | visited.add(neighbour) 16 | queue.append(neighbour) 17 | return False -------------------------------------------------------------------------------- /Trees-and-Graphs/successor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write an algorithm to find the "next" node (i.e., in-order successor) of a given node in a binary search tree. 3 | You may assume that each node has link to its parent. 4 | """ 5 | def inOrderSuccessor(n): 6 | if not n: 7 | return None 8 | if n.right is not None: 9 | return leftMostChild(n.right) 10 | q = n 11 | x = q.parent 12 | while x != None and x.left != q: 13 | q = x 14 | x = x.parent 15 | return x 16 | 17 | def leftMostChild(node): 18 | if not node: 19 | return None 20 | while node.left: 21 | node = node.left 22 | return node 23 | -------------------------------------------------------------------------------- /Trees-and-Graphs/validate-BST.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement a function to check if a binary tree is a binary search tree. 3 | """ 4 | def isBST(root,minn = float('-inf'), maxx=float('inf')): 5 | if not root: 6 | return True 7 | if root.data <= minn or root.data > maxx: 8 | return False 9 | if not isBST(root.left,minn,root.data): 10 | return False 11 | if not isBST(root.right,root.data,maxx): 12 | return False 13 | return True -------------------------------------------------------------------------------- /arrays-and-strings/URLify.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a method to replace all the spaces in a string S with ‘%20’. You may assume that the string has sufficient space 3 | at the end to hold the additional characters, and that you are given the "true" length of the string. 4 | """ 5 | def replaceSpaces(s, length): 6 | s = list(s) 7 | count = 0 8 | for i in range(length): 9 | if s[i] == ' ': 10 | count += 1 11 | index = length + count*2 12 | for i in range(length-1, -1, -1): 13 | if s[i] == " ": 14 | s[index-1] = "0" 15 | s[index-2] = "2" 16 | s[index-3] = "%" 17 | index -= 3 18 | else: 19 | s[index-1] = s[i] 20 | index -= 1 21 | return "".join(s) 22 | 23 | print(replaceSpaces("Mr John Smith ",13)) -------------------------------------------------------------------------------- /arrays-and-strings/check-permutation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two strings write a method to decide if one is a permutation of the other. 3 | """ 4 | import collections 5 | def permutationCheck(s1,s2): 6 | if len(s1) != len(s2): 7 | return False 8 | letters = collections.defaultdict(int) 9 | for i in s1: 10 | letters[i] += 1 11 | for i in s2: 12 | letters[i] -= 1 13 | if letters[i] < 0: 14 | return False 15 | return True -------------------------------------------------------------------------------- /arrays-and-strings/is-unique.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement an algorithm to determine if a string has all unique characters. What if you cannot use additional data structures? 3 | """ 4 | def isUnique(s): 5 | s = ''.join(sorted(s)) 6 | for i in range(len(s)-1): 7 | if s[i] == s[i+1]: 8 | return False 9 | return True -------------------------------------------------------------------------------- /arrays-and-strings/one-away.py: -------------------------------------------------------------------------------- 1 | """ 2 | There are three types of edits that can be performed on strings: insert a character, remove a charachter or replace a character. 3 | Given two strings, write a function to check if they are one edit(or xero edits) away. 4 | """ 5 | def oneEditAway(s1,s2): 6 | if abs(len(s1)-len(s2)) > 1: 7 | return False 8 | if len(s2) > len(s1): 9 | return oneEditAway(s2,s1) 10 | i,j,foundDiff = 0,0,False 11 | while i < len(s1) and j < len(s2): 12 | if s1[i] != s2[j]: 13 | if foundDiff: 14 | return False 15 | foundDiff = True 16 | if len(s1) == len(s2): 17 | j += 1 18 | else: 19 | j += 1 20 | i += 1 21 | return True -------------------------------------------------------------------------------- /arrays-and-strings/palindrome-permutation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string, write a function to check if it is a permutation of a palindrome. 3 | """ 4 | import collections 5 | def palindromePermutation(s): 6 | countOdd = 0 7 | d = collections.defaultdict(int) 8 | for i in s: 9 | d[i] += 1 10 | if d[i] % 2 == 1: 11 | countOdd += 1 12 | else: 13 | countOdd -= 1 14 | return countOdd <= 1 -------------------------------------------------------------------------------- /arrays-and-strings/rotate-matrix.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an image represented by an N * N matrix, where each pixel in the image is 4 bytes, write a method to rotate the 3 | image by 90 degrees. Can you do this in place? 4 | """ 5 | def rotate(matrix): 6 | l = len(matrix) 7 | if l == 0 or l != len(matrix[0]): 8 | return False 9 | for layer in range(l//2): 10 | first,last = layer, l-1-layer 11 | for i in range(first,last): 12 | offset = i - first 13 | top = matrix[first][i] 14 | matrix[first][i] = matrix[last-offset][first] 15 | matrix[last-offset][first] = matrix[last][last-offset] 16 | matrix[last][last-offset] = matrix[i][last] 17 | matrix[i][last] = top 18 | return True -------------------------------------------------------------------------------- /arrays-and-strings/string-compression.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implememnt a method to perform basic string string compression using the counts of repeated characters. For example, the string aabcccccaaa would become a2b1c5a3. 3 | If the 'compressed' string would not become smaller than the original string, your method should return the original string. You can assume the string has only 4 | uppercase and lowercase letters(a-z). 5 | """ 6 | def compress(s): 7 | compressed = [] 8 | countConsecutive = 0 9 | i = 0 10 | while i < len(s): 11 | ch = s[i] 12 | while i < len(s) and s[i] == ch: 13 | countConsecutive += 1 14 | i += 1 15 | compressed.append(ch) 16 | compressed.append(str(countConsecutive)) 17 | countConsecutive = 0 18 | res = "".join(compressed) 19 | return res if len(s) > len(res) else s -------------------------------------------------------------------------------- /arrays-and-strings/string-rotation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Assume you have a method isSubstring which checks if one word is a substring of another. Given two strings, 3 | s1 and s2, write code to check if s2 is a rotation of s1 using only one call to isSubstring(eg. "waterbottle" is a 4 | rotation of "erbottlewat".) 5 | """ 6 | def isRotation(s1,s2): 7 | if len(s1) != len(s2): 8 | return False 9 | newS = s1 + s1 10 | return s2 in newS # Alternative of IsSubstring method. 11 | -------------------------------------------------------------------------------- /arrays-and-strings/zero-matrix.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write an algorithm such that if an element in an M * N matrix is 0, its entire row and column are set to 0. 3 | """ 4 | def setZeroes(matrix): 5 | row = len(matrix) 6 | col = len(matrix[0]) 7 | is_col= False 8 | for i in range(row): 9 | if matrix[i][0] == 0: 10 | is_col= True 11 | for j in range(1,col): 12 | if matrix[i][j] == 0: 13 | matrix[0][j] = 0 14 | matrix[i][0] = 0 15 | 16 | for i in range(1,row): 17 | for j in range(1,col): 18 | if matrix[i][0] == 0 or matrix[0][j] == 0: 19 | matrix[i][j] = 0 20 | if matrix[0][0] == 0: 21 | for j in range(col): 22 | matrix[0][j] = 0 23 | if is_col: 24 | for i in range(row): 25 | matrix[i][0] = 0 -------------------------------------------------------------------------------- /linked-lists/delete-middle-node.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement an algorithm to delete a node in the middle (i.e. any node but the first and last node, 3 | not necessarily the exact middle) of a singly linked list, given only access to that node. 4 | """ 5 | def deleteNode(node): 6 | if node == None or node.next == None: 7 | return False 8 | node.val, node.next = node.next.val, node.next.next 9 | return True -------------------------------------------------------------------------------- /linked-lists/intersection.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two singly linked lists, determine if the two lists intersect. Return the intersecting node. Note that the intersection 3 | is defined based on reference, not value. That is, if the kth node of the first linked list is the exact same node (by reference) 4 | as the jth node of the second linked list, then they are intersecting. 5 | """ 6 | def getIntersectionNode(headA, headB): 7 | if headA == None or headB == None: 8 | return None 9 | A_pointer = headA 10 | B_pointer = headB 11 | while A_pointer != B_pointer: 12 | A_pointer = headB if A_pointer == None else A_pointer.next 13 | B_pointer = headA if B_pointer == None else B_pointer.next 14 | return A_pointer 15 | -------------------------------------------------------------------------------- /linked-lists/loop-detection.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a circular linked list, implement an algorithm that return the node at the begining of the loop. 3 | 4 | DEFINITION 5 | Circular linked list: A (corrupt) linked list in which a node's next pointer points to an earlier node, so as to make a 6 | loop in the linked list. 7 | 8 | Example: 9 | Input: A -> B -> C -> D -> E -> C [the same C as earlier] 10 | Output: C 11 | """ 12 | def detectCycle(head): 13 | slow = fast = head 14 | while fast != None and fast.next != None: 15 | slow = slow.next 16 | fast = fast.next.next 17 | if slow == fast: 18 | break 19 | if fast == None or fast.next == None: 20 | return None 21 | slow = head 22 | while slow != fast: 23 | slow = slow.next 24 | fast = fast.next 25 | return fast -------------------------------------------------------------------------------- /linked-lists/palindrome.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement a function to check if a linked list is a palindrome. 3 | """ 4 | class Solution(object): 5 | def isPalindrome(self, head): 6 | n = self.length(head) 7 | if n <= 1: 8 | return True 9 | firstHalfRev, secondHalf = self.rev(head,int(n/2)) 10 | if n % 2 != 0: 11 | secondHalf = secondHalf.next 12 | while secondHalf: 13 | if secondHalf.val != firstHalfRev.val: 14 | return False 15 | secondHalf = secondHalf.next 16 | firstHalfRev = firstHalfRev.next 17 | return True 18 | 19 | def rev(self, node, l): 20 | newHead = None 21 | for i in range(l): 22 | if newHead is None: 23 | newHead = node 24 | node = node.next 25 | newHead.next = None 26 | else: 27 | tmp = node 28 | node = node.next 29 | tmp.next = newHead 30 | newHead = tmp 31 | return newHead,node 32 | 33 | def length(self, head): 34 | count = 0 35 | while (head): 36 | count = count + 1 37 | head = head.next 38 | return count -------------------------------------------------------------------------------- /linked-lists/partition.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a code to partition a linked list around a value x, such that all nodes less than x come before all nodes greater 3 | than or equal to x. If x is contained within the list, the values of x only need to be after the elements less than x. 4 | The partition element x can appear anywhere in the "right partition"; it does not need to appear between the left and right 5 | partitions. 6 | 7 | Example: 8 | Input: head = 1->4->3->2->5->2, partition = 3 9 | Output: 1->2->2->4->3->5 10 | """ 11 | def partition(head, x): 12 | headLess, headGreater = ListNode(0),ListNode(0) 13 | cur1, cur2 = headLess, headGreater 14 | 15 | while head: 16 | if head.val < x: 17 | cur1.next = head 18 | cur1 = cur1.next 19 | else: 20 | cur2.next = head 21 | cur2 = cur2.next 22 | head = head.next 23 | 24 | cur2.next = None 25 | cur1.next = headGreater.next 26 | return headLess.next -------------------------------------------------------------------------------- /linked-lists/remove-dups.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a code to remove duplicates from an unsorted linked list. 3 | Follow Up: 4 | How would you solve this problem if a temprorary buffer is not allowed? 5 | """ 6 | def deleteDuplicates(head): 7 | if not head: 8 | return head 9 | cur = head 10 | while cur: 11 | runner = cur 12 | while runner.next: 13 | if runner.next.val == cur.val: 14 | runner.next = runner.next.next 15 | else: 16 | runner = runner.next 17 | cur = cur.next 18 | return head -------------------------------------------------------------------------------- /linked-lists/return-kth-element-to-last.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement an algorithm to find the kth to last element of a singly linked list. 3 | """ 4 | def NthFromEnd(self, head, n): 5 | p1,p2 = head,head 6 | if not head: 7 | return head 8 | for i in range(n): 9 | p1 = p1.next 10 | while p1: 11 | p1 = p1.next 12 | p2 = p2.next 13 | return p2 -------------------------------------------------------------------------------- /linked-lists/sum-lists.py: -------------------------------------------------------------------------------- 1 | """ 2 | You have two numbers represented by a linked list, where each node contains a single digit. The digits are stored in reverse 3 | order, such that the 1's digit is at the head of the list. Write a function that adds the two numbers and returns the sum as 4 | the linked list. 5 | 6 | Example: 7 | Input: (7 -> 1 -> 6) + (5 -> 9 -> 2). That is, 617 + 295. 8 | Output: 2 -> 1 -> 9. That is, 912. 9 | 10 | FOLLOW UP: 11 | Suppose the digits are stored in forward order. Repeat the above problem. 12 | Input: (6 -> 1 -> 7) + (2 -> 9 -> 5). That is, 617 + 295. 13 | Output: 9 -> 1 -> 2. That is, 912. 14 | """ 15 | def addTwoNumbers(l1, l2): 16 | res = ListNode(0) 17 | cur = res 18 | carry = 0 19 | while l1 or l2: 20 | x = l1.val if l1 else 0 21 | y = l2.val if l2 else 0 22 | summ = carry + x + y 23 | carry = summ // 10 24 | cur.next = ListNode(summ%10) 25 | cur = cur.next 26 | if l1: 27 | l1 = l1.next 28 | if l2: 29 | l2 = l2.next 30 | if carry > 0: 31 | cur.next = ListNode(carry) 32 | return res.next 33 | 34 | """ Follow Up """ 35 | class Solution(object): 36 | def addTwoList(self, l1, l2): 37 | len1,len2 = self.getLength(l1),self.getLength(l2) 38 | if len1 > len2: 39 | l2 = self.addLeadingZeroes(len1-len2,l2) 40 | else: 41 | l1 = self.addLeadingZeroes(len2-len1,l1) 42 | carry, summ = self.addNumbers(l1,l2) 43 | if carry > 0: 44 | new = ListNode(carry) 45 | new.next = summ 46 | summ = new 47 | return summ 48 | 49 | def getLength(self, node): 50 | count = 0 51 | while node: 52 | count += 1 53 | node = node.next 54 | return count 55 | 56 | def addLeadingZeroes(self,count,node): 57 | for i in range(count): 58 | new = ListNode(0) 59 | new.next = node 60 | node = new 61 | return node 62 | 63 | def addNumbers(self,l1,l2): 64 | if not l1 and not l2: 65 | return (0,None) 66 | carry,new = self.addNumbers(l1.next,l2.next) 67 | summ = l1.val + l2.val + carry 68 | ans = ListNode(summ%10) 69 | ans.next = new 70 | return (summ//10,ans) -------------------------------------------------------------------------------- /stacks-and-queues/animal-shelter.py: -------------------------------------------------------------------------------- 1 | """ 2 | An animal shelter, which holds only dogs and cats, operates on a strictly "first in, first out" basis. People must adopt 3 | either the "oldest" (based on arrival time) of all animals at the shelter, or they can select whether they would prefer a 4 | dog or a cat (receive the oldest animal of that type). They cannot select which specific animal they would like. 5 | Create the data structures to maintain this system and implement operations such as enqueue, dequeueAny, dequeueDog, and 6 | dequeueCat. You may use the built-in LinkedList data structure. 7 | """ 8 | class Animal: 9 | def __init__(self, animalName=None, animalType=None): 10 | self.animalName = animalName 11 | self.animalType = animalType 12 | self.next = None 13 | self.timestamp = 0 14 | 15 | class AnimalShelter: 16 | def __init__(self): 17 | self.headCat = None 18 | self.tailCat = None 19 | self.headDog = None 20 | self.tailDog = None 21 | self.order = 0 22 | 23 | def enqueue(self, animalName, animalType): 24 | self.order += 1 25 | newAnimal = Animal(animalName, animalType) 26 | newAnimal.timestamp = self.order 27 | 28 | if animalType == 'cat': 29 | if not self.headCat: 30 | self.headCat = newAnimal 31 | if self.tailCat: 32 | self.tailCat.next = newAnimal 33 | self.tailCat = newAnimal 34 | 35 | elif animalType == 'dog': 36 | if not self.headDog: 37 | self.headDog = newAnimal 38 | if self.tailDog: 39 | self.tailDog.next = newAnimal 40 | self.tailDog = newAnimal 41 | 42 | def dequeueCat(self): 43 | if self.headCat: 44 | newAnimal = self.headCat 45 | self.headCat = newAnimal.next 46 | return str(newAnimal.animalName) 47 | else: 48 | return "No cat left!" 49 | 50 | def dequeueDog(self): 51 | if self.headDog: 52 | newAnimal = self.headDog 53 | self.headDog = newAnimal.next 54 | return str(newAnimal.animalName) 55 | else: 56 | return "No dog left!" 57 | 58 | def dequeueAny(self): 59 | if self.headCat and not self.headDog: 60 | return self.dequeueCat() 61 | elif not self.headCat and self.headDog: 62 | return self.dequeueDog() 63 | elif self.headCat: 64 | if self.headCat.timestamp < self.headDog.timestamp: 65 | return self.dequeueCat() 66 | else: 67 | return self.dequeueDog() 68 | else: 69 | return "No animal left!" -------------------------------------------------------------------------------- /stacks-and-queues/queue-via-stacks.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement a MyQueue class which implements a queue using two stacks. 3 | """ 4 | class MyQueue(object): 5 | 6 | def __init__(self): 7 | self.s1 = [] 8 | self.s2 = [] 9 | 10 | 11 | def push(self, x): 12 | self.s1.append(x) 13 | 14 | 15 | def pop(self): 16 | self.shiftStack() 17 | return self.s2.pop() 18 | 19 | 20 | def peek(self): 21 | self.shiftStack() 22 | return self.s2[-1] 23 | 24 | 25 | def empty(self): 26 | return True if (len(self.s1)+len(self.s2)) <= 0 else False 27 | 28 | def shiftStack(self): 29 | if len(self.s2) == 0: 30 | while self.s1: 31 | self.s2.append(self.s1.pop()) -------------------------------------------------------------------------------- /stacks-and-queues/sort-stack.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a program to sort a stack such that the smallest items are on the top. You can use an addittional temporary stack, but you may not copy the elements into 3 | any other data structure(such as an array). The stack supports the following operations: push, pop, peek and isEmpty. 4 | """ 5 | def sort(s): 6 | tempStack = [] 7 | while s: 8 | temp = s.pop() 9 | while tempStack and tempStack[-1] > temp: 10 | s.push(tempStack.pop()) 11 | tempStack.push(temp) 12 | while tempStack: 13 | s.push(tempStack.pop()) -------------------------------------------------------------------------------- /stacks-and-queues/stack-min.py: -------------------------------------------------------------------------------- 1 | """ 2 | How would you design a stack which, in addition to push and pop, has a function min which returns the minimum element? 3 | Push, pop and min should all operate in O(1) time. 4 | """ 5 | class MinStack(object): 6 | 7 | def __init__(self): 8 | self.stack = [] 9 | self.min_stack = [] 10 | 11 | def push(self, x): 12 | self.stack.append(x) 13 | if not self.min_stack or x <= self.min_stack[-1]: 14 | self.min_stack.append(x) 15 | 16 | def pop(self): 17 | n = self.stack.pop() 18 | if self.min_stack[-1] == n: 19 | self.min_stack.pop() 20 | 21 | def top(self): 22 | return self.stack[-1] 23 | 24 | def getMin(self): 25 | return self.min_stack[-1] -------------------------------------------------------------------------------- /stacks-and-queues/stack-of-plates.py: -------------------------------------------------------------------------------- 1 | class stackOfPlates: 2 | def __init__(self, capacity): 3 | self.stacks = [] 4 | if capacity < 1: 5 | raise NameError("Capacity should be greater than zero") 6 | else: 7 | self.capacity = capacity 8 | 9 | def push(self, item): 10 | if len(self.stacks) == 0: 11 | self.stacks.append([item]) 12 | else: 13 | if len(self.stacks[-1]) >= self.capacity: 14 | self.stacks.append([item]) 15 | else: 16 | self.stacks[-1].append(item) 17 | 18 | def pop(self): 19 | if len(self.stacks) == 0: 20 | return None 21 | popData = self.stacks[-1].pop() 22 | if len(self.stacks[-1]) == 0: 23 | self.stacks.pop() 24 | return popData 25 | 26 | def popAt(self, index): 27 | if len(self.stacks) == 0 or index >= len(self.stacks): 28 | return None 29 | popData = self.stacks[index][-1] 30 | if len(self.stacks[index]) == 1 and index == len(self.stacks) - 1: 31 | del self.stacks[index] 32 | return popData 33 | elif len(self.stacks[index]) == 1: 34 | del self.stacks[index] 35 | elif index == len(self.stacks) - 1: 36 | del self.stacks[index][-1] 37 | return popData 38 | else: 39 | for i in range(index+1,len(self.stacks)): 40 | self.stacks[index][-1] = self.stacks[index+1][0] 41 | for j in range(len(self.stacks[i])-1): 42 | self.stacks[i][j] = self.stacks[i][j+1] 43 | if len(self.stacks[-1]) == 1: 44 | del self.stacks[-1] 45 | else: 46 | del self.stacks[-1][-1] 47 | return popData -------------------------------------------------------------------------------- /stacks-and-queues/three-in-one.py: -------------------------------------------------------------------------------- 1 | """ 2 | Describe how you could use a single array to implement three stacks. 3 | """ 4 | class FixedMultiStack: 5 | def __init__(self,capacity): 6 | self.capacity = capacity 7 | self.arr = [None] * 3 * capacity 8 | self.sizes = [0] * 3 9 | 10 | def push(self, stackNum, data): 11 | if self.sizes[stackNum] == self.capacity: 12 | print("Stack is already Full") 13 | else: 14 | self.sizes[stackNum] += 1 15 | self.arr[self.indexOfTop(stackNum)] = data 16 | 17 | def pop(self, stackNum): 18 | if self.sizes[stackNum] == 0: 19 | return "Stack is empty" 20 | topIndex = self.indexOfTop(stackNum) 21 | data = self.arr[topIndex] 22 | self.arr[topIndex] = None 23 | self.sizes[stackNum] -= 1 24 | return data 25 | 26 | def indexOfTop(self, stackNum): 27 | offset = stackNum * self.capacity 28 | s = self.sizes[stackNum] 29 | return offset + s - 1 30 | 31 | 32 | class MultiStack: 33 | def __init__(self, capacity): 34 | self.capacity = capacity 35 | self.arr = [None] * 3 * capacity 36 | self.top = [-1] * 3 37 | self.nextt = [i+1 for i in range(3*capacity)] 38 | self.nextt[-1] = -1 39 | self.free = 0 40 | 41 | def isFull(self): 42 | return self.free == -1 43 | 44 | def isEmpty(self, stackNum): 45 | return self.top[stackNum] == -1 46 | 47 | def push(self, stackNum, data): 48 | if self.isFull(): 49 | print("Stack is Full") 50 | return 51 | i = self.free 52 | self.free = self.nextt[i] 53 | self.nextt[i] = self.top[stackNum] 54 | self.top[stackNum] = i 55 | self.arr[i] = data 56 | 57 | def pop(self, stackNum): 58 | if self.isEmpty(stackNum): 59 | return None 60 | i = self.top[stackNum] 61 | self.top[stackNum] = self.nextt[i] 62 | self.nextt[i] = self.free 63 | self.free = i 64 | return self.arr[i] --------------------------------------------------------------------------------