Coding Problem Set
GROUP ANAGRAMS: Given an array of strings, group anagrams together. Input: ["eat", "tea", "tan", "ate", "nat", "bat"], Output: [ ["ate","eat","tea"], ["nat","tan"], ["bat"] ]
1) hashmap with sorted string as key 2) use character counts as key (reduce runtime by not having to sort every word)
MISSING NUMBER: An array A contains all the integers from 0 to n, except for one number which is missing. Write code to find the missing integer.
Sum array. Compare to sum of array 1 through n. Difference is missing number.
CHECK PERMUTATION: Given two strings, write a method to decide if one is a permutation of the other
check character counts with hashmap
ROUTE BETWEEN NODES: Given a directed graph, design an algorithm to find out whether there is a route between two nodes
Use DFS or BFS
REMOVE DUPS: Write code to remove duplicates from an unsorted list
Use hash table
ALIEN DICTIONARY: There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list of non-empty words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language.
Make a graph by comparing curr word and next word and adding edge between letters at first index where they are different. Topological sort (use incoming edges == 0 method) def alienOrder(self, words): """ :type words: List[str] :rtype: str """ from collections import defaultdict from collections import deque allLetters = set(''.join(words)) incomingEdges = defaultdict(int).fromkeys(allLetters, 0) i = 0 graph = defaultdict(list) while i < len(words) - 1: word = words[i] nextWord = words[i+1] charIndex = 0 maxLen = min(len(word), len(nextWord)) while charIndex < maxLen and word[charIndex] == nextWord[charIndex]: charIndex += 1 if charIndex < maxLen and word[charIndex] != nextWord[charIndex]: incomingEdges[nextWord[charIndex]] += 1 graph[word[charIndex]].append(nextWord[charIndex]) i += 1 result = [] queue = deque() for letter in incomingEdges: if incomingEdges[letter] == 0: queue.append(letter) while queue: letter = queue.popleft() result.append(letter) for val in graph[letter]: incomingEdges[val] -= 1 if incomingEdges[val] == 0: queue.append(val) if len(result) != len(allLetters): return '' return ''.join(result)
REVERSE NODES IN K-GROUP: Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is. Example: Given this linked list: 1->2->3->4->5 For k = 2, you should return: 2->1->4->3->5 For k = 3, you should return: 3->2->1->4->5 Note: Only constant extra memory is allowed. You may not alter the values in the list's nodes, only nodes itself may be changed.
Reverse groups k nodes at a time. Make sure to connect prev and next groups. To reverse a linked list in place, take advantage of simultaneous assignment (l.next, l, r = r, l.next, l). Just flip pointers as you iterate through. Also make sure that you have the right be one after the end of the actual list to handle the next assignments. def reverseKGroup(self, head, k): dummy = ListNode(None) connect = dummy dummy.next = left = right = head while True: for i in range(k): if right == None: return dummy.next right = right.next l, r = left, right for i in range(k): l.next, l, r = r, l.next, l connect.next, connect, left = r, left, right
PERMUTATIONS WITH DUPS: Write a method to compute all permutations of a string whose characters are not necessarily unique. The list of permutations should not have duplicates
Same idea as permutation without dups. Insert each character at each place. If see that original inserted place was same char, break. Start with [[]] def permuteUnique(self, nums): answers = [[]] for n in nums: new_ans = [] for ans in answers: for i in range(len(ans)+1): new_ans.append(ans[:i]+[n]+ans[i:]) if i < len(ans) and ans[i]==n: break #handles duplication answers = new_ans return answers
TOWERS OF HANOI: In the classic problem of the Towers of Hanoi, you have 3 towers and N disks of different sizes which can slide onto any tower. The puzzle starts with disks sorted in ascending order of size from top to bottom (ie. each disk sits on top of an even larger one). You have the following constraints: 1) Only one disk can be moved at a time 2) A disk is slid off the top of one tower onto another tower 3) A disk cannot be placed on top of a smaller disk Write a program to move the disks from the first tower to the last using stacks
Starting, Buffer, Destination move top n-1 start to buffer, move last start to dest, move everything from buffer to dest using recursion def moveDisks (n, origin, dest, buff): if n <= 0: return moveDisks(n-1, origin, buff, dest) moveTop(origin, dest) moveDisks(n-1, buff, dest, origin)
PAIRS WITH SUM: Design an algorithm to find all pairs of integers within an array which sum to a specified value (only unique)
iterate through array, put complement of number in dictionary with value being it's index. If array value exists in dictionary, then found a pair. Add values to set() to avoid duplicates
LETTERS AND NUMBERS: Given an array filled with letters and numbers, find the longest subarray with an equal number of letters and numbers
Think about: when does an equal subarray happen? if add equal number of character as numbers. Keep track of differences (between total # chars, and total # of #s) and recurring differences. If a difference recurs, that means between its first occurence and its current occurrence, an equal number of chars and #s were added. Use hashmap to keep track of index of first occurred difference. Update max when each difference is seen.
PARSE LISP EXPRESSION: You are given a string expression representing a Lisp-like expression to return the integer value of. The syntax for these expressions is given as follows. An expression is either an integer, a let-expression, an add-expression, a mult-expression, or an assigned variable. Expressions always evaluate to a single integer. (An integer could be positive or negative.) A let-expression takes the form (let v1 e1 v2 e2 ... vn en expr), where let is always the string "let", then there are 1 or more pairs of alternating variables and expressions, meaning that the first variable v1 is assigned the value of the expression e1, the second variable v2 is assigned the value of the expression e2, and so on sequentially; and then the value of this let-expression is the value of the expression expr. An add-expression takes the form (add e1 e2) where add is always the string "add", there are always two expressions e1, e2, and this expression evaluates to the addition of the evaluation of e1 and the evaluation of e2. A mult-expression takes the form (mult e1 e2) where mult is always the string "mult", there are always two expressions e1, e2, and this expression evaluates to the multiplication of the evaluation of e1 and the evaluation of e2. For the purposes of this question, we will use a smaller subset of variable names. A variable starts with a lowercase letter, then zero or more lowercase letters or digits. Additionally for your convenience, the names "add", "let", or "mult" are protected and will never be used as variable names. Finally, there is the concept of scope. When an expression of a variable name is evaluated, within the context of that evaluation, the innermost scope (in terms of parentheses) is checked first for the value of that variable, and then outer scopes are checked sequentially. It is guaranteed that every expression is legal. Please see the examples for more details on scope. Evaluation Examples: Input: (add 1 2) Output: 3 Input: (mult 3 (add 2 3)) Output: 15 Input: (let x 2 (mult x 5)) Output: 10 Input: (let x 2 (mult x (let x 3 y 4 (add x y)))) Output: 14 Explanation: In the expression (add x y), when checking for the value of the variable x, we check from the innermost scope to the outermost in the context of the variable we are trying to evaluate. Since x = 3 is found first, the value of x is 3. Input: (let x 3 x 2 x) Output: 2 Explanation: Assignment in let statements is processed sequentially. Input: (let x 1 y 2 x (add x y) (add x y)) Output: 5 Explanation: The first (add x y) evaluates as 3, and is assigned to x. The second (add x y) evaluates as 3+2 = 5. Input: (let x 2 (add (let x 3 (let x 4 x)) x)) Output: 6 Explanation: Even though (let x 4 x) has a deeper scope, it is outside the context of the final x in the add-expression. That final x will equal 2. Input: (let a1 3 b2 (add a1 1) b2) Output 4 Explanation: Variable names can contain digits after the first character.
Think of it like a call stack, with a stack that holds the tokens (the code in an array) and the variables for each frame. Create a new frame every time you see '(' and add the current tokens and vars to the stack. When you see a ')' you evaluate the current frame (whats held in the current tokens and variables). When you finish evaluating, you pop off the top of the stack (like you're returning from a function) and replace the current tokens and variables with what was popped off. Whenever you see '(' and the first token is a "let" then evaluate the current tokens so that the variables are set so that the next incoming inner frame can possibly use them. def evaluate(self, expression): """ :type expression: str :rtype: int """ stack = [] tokens = [''] variables = {} def evaluate(curTokens): if curTokens[0] in ('add', 'mult'): v1, v2 = int(variables.get(curTokens[1], curTokens[1])), int(variables.get(curTokens[2], curTokens[2])) if curTokens[0] == 'add': res = v1 + v2 return str(res) else: res = v1 * v2 return str(res) else: for i in range(1, len(tokens) - 1, 2): if tokens[i+1]: val = variables.get(tokens[i+1], tokens[i+1]) variables[tokens[i]] = val return variables.get(tokens[-1], tokens[-1]) for c in expression: if c == '(': if tokens[0] == 'let': evaluate(tokens) stack.append((tokens, dict(variables))) tokens = [''] elif c == ' ': tokens.append('') elif c == ')': res = evaluate(tokens) tokens, variables = stack.pop() tokens[-1] += res else: tokens[-1] += c return int(tokens[0])
PALINDROME: Implement a function to check if a linked list is palindrome
Use stack to check if second half is same as first half. Use slow/fast runner technique to get to middle (checking if length is odd/even as well to figure out how to handle middle element)
IS UNIQUE: Implement and algorithm to determine if a string has all unique characters. What if you cannot use additional data structures?
1) Clarify if ASCII set (128 characters) 2) boolean array of values indicating if letter has been seen yet 3) also do length check if longer than 128 return false w/o data structures -- try sorting, then linearly check
SHORTEST UNSORTED CONTINUOUS SUBARRAY: Given an integer array, you need to find one continuous subarray that if you only sort this subarray in ascending order, then the whole array will be sorted in ascending order, too. You need to find the shortest such subarray and output its length. Input: [2, 6, 4, 8, 10, 9, 15] Output: 5 Explanation: You need to sort [6, 4, 8, 10, 9] in ascending order to make the whole array sorted in ascending order.
1) Sort array and compare first places where differ 2) OPTIMAL: Multiple passes Intuition: the minimum in the subarray must be greater than the greatest in the prev array. the max in the subarray must be less than the minimum in the next array. From both ends, find indexes where slope changes. Min and max of subarray must lie between those two indices (think of increasing slope of line that goes up in down in varying middle) then pass through array again and find first point where number is greater than min. pass through end and find first point where number is less than max those are the start and end points def findUnsortedSubarray(self, nums): """ :type nums: List[int] :rtype: int """ if len(nums) < 2: return 0 maxSub = float("-inf") minSub = float("inf") l = 0 r = len(nums) - 1 while l < r and nums[l] <= nums[l+1]: l += 1 if l == r: return 0 while nums[r-1] <= nums[r]: r -= 1 while l <= r: maxSub = max(maxSub, nums[i]) minSub = min(minSub, nums[i]) l += 1 start, end = 0, len(nums) - 1 while start < len(nums) and nums[start] <= minSub: start += 1 while end >= 0 and nums[end] >= maxSub: end -= 1 return end-start + 1
URLify: Write a method to replace all strings with '%20.' You may assume that the string has sufficient space at the end to hold the additional characters, and that you are given the "true" length of the string.
1) input.replace(' ', '%20') 2) inputArray = input.split(' ') '%20'.join(inputArray)
DIVING BOARD: You are building a diving board by placing a bunch of planks of wood end-to-end. There are two types of planks, one of length shorter and one of length longer. You must use exactly K planks of wood. Write a method to generate all possible lengths for the diving board.
1)DFS search, keeping track of visited and length. If length == 0 (counting down from K), then add length to result set. Keep track of visited with key being length and number of planks 2) [OPTIMAL] see that K planks has to be a combination of shorter and longer. iterate through number of shorter + number of longer.
PALINDROME PAIRS: Given a list of unique words, find all pairs of distinct indices (i, j) in the given list, so that the concatenation of the two words, i.e. words[i] + words[j] is a palindrome. Input: ["abcd","dcba","lls","s","sssll"] Output: [[0,1],[1,0],[3,2],[2,4]] Explanation: The palindromes are ["dcbaabcd","abcddcba","slls","llssssll"]
Add words with index into a dict. Analyze all possible prefixes (and subsequent suffixes) of each word. words = ["bot", "t", "to"] Prefixes for bot are: "", "b", "bo", "bot." If the prefix (including the empty string) are palindromes, then the corresponding suffixes can be reversed and prepended to complete the palindrome. So check if reversed suffix exists. Also do the same thing for suffixes. This way you find all possible palindromes for a given word created by prepending and appending snippets of less than or equal to length (including the empty string on both sides, which is why we use the range len(word) + 1). But because we do this, we explicitly leave out the empty string (when considering suffixes) to avoid counting duplicates. That is, if a palindrome can be created by appending an entire other word to the current word, then we will already consider such a palindrome when considering the empty string as prefix for the other word. def palindromePairs(self, words): """ :type words: List[str] :rtype: List[List[int]] """ origWords = words words = {word: i for i, word in enumerate(words)} result = [] for i, word in enumerate(origWords): for j in range(len(word) + 1): prefix = word[:j] suffix = word[j:] if prefix == prefix[::-1]: revSuff = suffix[::-1] if revSuff in words and words[revSuff] != i: result.append([words[revSuff], i]) if suffix == suffix[::-1] and j!=len(word): revPref = prefix[::-1] if revPref in words and words[revPref] != i: result.append([i,words[revPref]]) return result
LARGEST RECTANGLE IN A HISTOGRAM: Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
Brute force: find the max rectangle from every to bar to every other bar. Use a stack. For any bar x, if it's in a rectangle of which the height is also the height of x, we know that every bar in the rectangle must be no shorter than x. Then the issue is to find the left and right boundary where the bars are shorter than x. According to the code, when a bar is popped out from the stack, we know it must be higher than the bar at position i, so bar[i] must be the right boundary (exclusive) of the rectangle, and the previous bar in the stack is the first one that is shorter than the popped one so it must be the left boundary (also exclusive). Then we find the rectangle. def largestRectangleArea(self, heights): """ :type heights: List[int] :rtype: int """ heights.append(0) stack = [-1] maxArea = 0 for i in range(len(heights)): while heights[i] < heights[stack[-1]]: h = heights[stack.pop()] w = i - stack[-1] - 1 maxArea = max(maxArea, h*w) stack.append(i) heights.pop() return maxArea
PATTERN MATCHING: You are given two strings, pattern and value. The pattern string consists of just the letters a and b, describing a pattern within a string. For example, the string catcatgocatgo matches the pattern aabab (where cat is a and go is b). It also matches patterns like a, ab, and b. Write a method to determine if value matches pattern.
Build string from pattern and compare.
PALINDROME PERMUTATION: Given a string, write a function to check if it is a permutation of a palindrome. A palindrome is a word that is the same forwards and backwards. The palindrome does not need to be limited to just dictionary words.
Check the frequency of all the letters. Need to all be even or if there can be one odd one if the number of characters is odd
DELETE MIDDLE NODE: Implement an algorithm to delete a node in the middle (i.e. any node but the first and last node, not necessarily the exact middle) of a singly linked list, given only access to that node
Copy the data from the next node and delete the next node
NUMBER OF ISLANDS: Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
DFS, flip water bits to 1 when done. def numIslands(self, grid): """ :type grid: List[List[str]] :rtype: int """ numIslands = 0 def exploreIsland(grid, row, col): if row < 0 or row >= len(grid) or col < 0 or col >= len(grid[0]): return if grid[row][col] == '0': return grid[row][col] = '0' exploreIsland(grid, row + 1, col) exploreIsland(grid, row - 1, col) exploreIsland(grid, row, col + 1) exploreIsland(grid, row, col - 1) for row in range(len(grid)): for col in range(len(grid[0])): if grid[row][col] == '1': exploreIsland(grid, row, col) numIslands += 1 return numIslands
COMBINATION SUM: Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target. The same repeated number may be chosen from candidates unlimited number of times. Note: All numbers (including target) will be positive integers. The solution set must not contain duplicate combinations. Example 1: Input: candidates = [2,3,6,7], target = 7, A solution set is: [ [7], [2,2,3] ]
DFS. Sort candidates and only consider numbers equal to or greater than current number (to avoid duplicates) When doing subsets like these, use a current array as a function argument to keep track of the current subset to append to the result array def combinationSum(self, candidates, target): """ :type candidates: List[int] :type target: int :rtype: List[List[int]] """ result = [] candidates.sort() def dfs(candidates, target, result, cur): if target == 0: result.append(cur) return elif target < 0: return for i in range(len(candidates)): dfs(candidates[i:], target-candidates[i], result, cur+[candidates[i]]) dfs(candidates, target, result, []) return result
MAXIMUM PRODUCT SUBARRAY: Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product. Input: [2,3,-2,4] Output: 6 Explanation: [2,3] has the largest product 6. Example 2: Input: [-2,0,-1] Output: 0 Explanation: The result cannot be 2, because [-2,-1] is not a subarray.
Dynamic Programming - ish. P[i] = max product at index i, P[i] = max( P[i-i] * n[i], n[i] ). Also should keep track of min product because if it is negative, then multiplying it by another negative will make it positive. Thus whenever see a negative num, switch min and max. def maxProduct(self, nums): """ :type nums: List[int] :rtype: int """ result = nums[0] minP = nums[0] maxP = nums[0] for i in range(1, len(nums)): if nums[i] < 0: temp = minP minP = maxP maxP = temp maxP = max(maxP*nums[i], nums[i]) minP = min(minP*nums[i], nums[i]) result = max(maxP, result) return result
UNIQUE PATHS II: A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below). Now consider if some obstacles are added to the grids. How many unique paths would there be?
Dynamic programming def uniquePathsWithObstacles(self, obstacleGrid): """ :type obstacleGrid: List[List[int]] :rtype: int """ if obstacleGrid[0][0] == 1: return 0 paths = [[0 for col in range(len(obstacleGrid[0]))] for row in range(len(obstacleGrid))] paths[0][0] = 1 for i in range(1, len(obstacleGrid)): if obstacleGrid[i][0] == 1: paths[i][0] = 0 else: paths[i][0] = paths[i-1][0] for i in range(1, len(obstacleGrid[0])): if obstacleGrid[0][i] == 1: paths[0][i] = 0 else: paths[0][i] = paths[0][i-1] for row in range(1, len(obstacleGrid)): for col in range(1, len(obstacleGrid[0])): if obstacleGrid[row][col] == 1: paths[row][col] == 0 else: paths[row][col] = paths[row - 1][col] + paths[row][col - 1] return paths[len(obstacleGrid) - 1][len(obstacleGrid[0]) - 1]
WORD BREAK: Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. The same word in the dictionary may be reused multiple times in the segmentation. You may assume the dictionary does not contain duplicate words. Input: s = "leetcode", wordDict = ["leet", "code"] Output: true Explanation: Return true because "leetcode" can be segmented as "leet code".
Dynamic programming. Keep boolean array with each W[i] indicating if word of length i is valid. Initialize W[0] = True because s of length is always valid. W[i] = W[j] and s[j:i] in wordDict Have two loops where inner loop indicates from what index to i to check if word in dictionary. def wordBreak(self, s, wordDict): """ :type s: str :type wordDict: List[str] :rtype: bool """ wordDict = set(wordDict) words = [False for x in range(len(s) + 1)] words[0] = True for i in range(1, len(s) + 1): for j in range(i): if words[j] and s[j:i] in wordDict: words[i] = True break return words[len(s)]
LONGEST PALINDROMIC SUBSTRING: Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000. Input: "babad" Output: "bab" Note: "aba" is also a valid answer.
Dynamic programming. Use a len(s) by len(s) T/F matrix where P[i][j] indicates if there is a palindrome between those two sequences. Find all palindromes of length 1, 2, then 3, etc. P(i, j) = (s_i==s_j) and P(i+1, j-1) Initialize all palindromes of length 1 and 2 def longestPalindrome(self, s): """ :type s: str :rtype: str """ if s is None or len(s) == 0: return s pals = [[0 for j in range(len(s))] for i in range(len(s))] answer = s[0] for i in range(len(s)): pals[i][i] = 1 if i+1 < len(s): if s[i] == s[i+1]: pals[i][i+1] = 1 answer = s[i: i + 2] for length in range(2, len(s)): for i in range(len(s)): j = i + length if j >= len(s): break if s[i] == s[j] and pals[i + 1][j - 1] == 1: answer = s[i:j+1] pals[i][j] = 1 return answer
BEAUTIFUL ARRANGEMENT: Suppose you have N integers from 1 to N. We define a beautiful arrangement as an array that is constructed by these N numbers successfully if one of the following is true for the ith position (1 <= i <= N) in this array: The number at the ith position is divisible by i. i is divisible by the number at the ith position. Now given N, how many beautiful arrangements can you construct?
Explore all permutations and validate that they match the conditions. Use backtracking and visited to avoid duplicate work. Recurse on numbers left to visit and the index that we're checking. If reach end, then add one (as in we have found one valid permutation). Reduce runtime by recursing from N ->1 because less likely to find valid numbers at higher N, so less likely to go down dead end track than if started at 1. def countArrangement(self, N): """ :type N: int :rtype: int """ def count(index, numbers): if index == 1: return 1 numWays = 0 for num in numbers: if isMagic(index, num): numWays += count(index-1, numbers - {num}) return numWays def isMagic(index, number): if index%number == 0 or number%index == 0: return True return False return count(N, set([i+1 for i in range(N)]))
RAND7 FROM RAND5: Implement a method rand7() given rand5(). That is, give a method that generates a random integer 0 and 4 (inclusive), write a method that generates a random integer between 0 and 6 (inclusive).
Generate numbers 0-24 randomly with 5*rand5() + rand5() Throw out 21-24 so that 0-3 aren't weight unevenly. Then mod by 7 to get result of rand7() (keep looping until get valid value)
IP TO CIDR: Given a start IP address ip and a number of ips we need to cover n, return a representation of the range as a list (of smallest possible length) of CIDR blocks. A CIDR block is a string consisting of an IP, followed by a slash, and then the prefix length. For example: "123.45.67.89/20". That prefix length "20" represents the number of common prefix bits in the specified range. Input: ip = "255.0.0.7", n = 10 Output: ["255.0.0.7/32","255.0.0.8/29","255.0.0.16/32"] Explanation: The initial ip address, when converted to binary, looks like this (spaces added for clarity): 255.0.0.7 -> 11111111 00000000 00000000 00000111 The address "255.0.0.7/32" specifies all addresses with a common prefix of 32 bits to the given address, ie. just this one address. The address "255.0.0.8/29" specifies all addresses with a common prefix of 29 bits to the given address: 255.0.0.8 -> 11111111 00000000 00000000 00001000 Addresses with common prefix of 29 bits are: 11111111 00000000 00000000 00001000 11111111 00000000 00000000 00001001 11111111 00000000 00000000 00001010 11111111 00000000 00000000 00001011 11111111 00000000 00000000 00001100 11111111 00000000 00000000 00001101 11111111 00000000 00000000 00001110 11111111 00000000 00000000 00001111 The address "255.0.0.16/32" specifies all addresses with a common prefix of 32 bits to the given address, ie. just 11111111 00000000 00000000 00010000. In total, the answer specifies the range of 10 ips starting with the address 255.0.0.7 . There were other representations, such as: ["255.0.0.7/32","255.0.0.8/30", "255.0.0.12/30", "255.0.0.16/32"], but our answer was the shortest possible. Also note that a representation beginning with say, "255.0.0.7/30" would be incorrect, because it includes addresses like 255.0.0.4 = 11111111 00000000 00000000 00000100 that are outside the specified range.
Greedy approach, try to get as many IPs per address. Identify number of IPS can get at current addr by finding rightmost set (1) bit (eg. 100100 can repr 2^2 unique addrs). Keep gathering addrs at each one, get next valid add by adding mask 1<<rightmostindex(ofprev). Convert ip to base 10 num (can still do bitwise operations on base 10 number bc computer converts back and forth from binary). Treat each part between "." as base 256 number (bc 2^8). So just left shift each part by however many to represent the binary version on it. Convert num back to ip, by right shifting each part back to where it was and also & by 255 to get rid of everything else. def ipToCIDR(self, ip, n): """ :type ip: str :type n: int :rtype: List[str] """ def ip2number(ip): numbers = list(map(int, ip.split("."))) n = (numbers[0]<<24) + (numbers[1]<<16) + (numbers[2]<<8) + numbers[3] return n def getRightmostIndex(number): for i in range(32): if (number & 1<<i): return i def number2ip(n): return ".".join([str(n>>24&255), str(n>>16&255),str(n>>8&255), str(n&255)]) result = [] cur = ip2number(ip) while n > 0: rightIndex = getRightmostIndex(cur) reprs = min(n.bit_length(), rightIndex+1) answer = number2ip(cur) + "/" +str(33-reprs) result.append(answer) n -= 2**(reprs-1) cur += 1<<(reprs-1) return result
STACK MIN: How would you design a stack which, in addition to push and pop, has a function min which returns the minimum element? Push, pop, and min should all operate in O(1) time.
Have each element have extra variable that holds the value of the minimum value from everything below it
PERMUTATION WITHOUT DUPS: Write a method to compute all permutations of a string of unique characters
Hold one letter constant, find permutations of other letters, insert letter at every spot def noDupPermutations(str): if len(nums) < 2: return [nums] else: results = self.permute(nums[1:]) answers = [] for result in results: for i in range(len(result) + 1): new = result[0:i] + [nums[0]] + result[i:] answers.append(new) return answers
EMPLOYEE FREE TIME: We are given a list schedule of employees, which represents the working time for each employee. Each employee has a list of non-overlapping Intervals, and these intervals are in sorted order. Return the list of finite intervals representing common, positive-length free time for all employees, also in sorted order. Also, we wouldn't include intervals like [5, 5] in our answer, as they have zero length. Input: schedule = [[[1,2],[5,6]],[[1,3]],[[4,10]]] Output: [[3,4]]
Idea: want to find intervals of time where zero people are working. So sort by time (keeping track of if they are start or end times). Increment for start, decrement for end. Count intervals where count = 0 def employeeFreeTime(self, schedule): """ :type schedule: List[List[Interval]] :rtype: List[Interval] """ times = [] for intervals in schedule: for interval in intervals: times.append((interval.start, 0)) times.append((interval.end, 1)) times.sort(key = lambda x: x[0]) working = 0 result = [] curBegin = -1 free = False for time in times: if time[1] == 0: working += 1 else: working -= 1 if not free and working == 0: free = True curBegin = time elif free and working != 0: if curBegin[0] != time[0]: result.append([curBegin[0], time[0]]) free = False curBegin = -1 return result
MEETING ROOMS II: Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), find the minimum number of conference rooms required.
Idea: we just need to find out how many conferences are going on at a given time. Take the max at any given time. Sort all times. Then go through list and + 1 for start and -1 for end. Taking running max as you go def minMeetingRooms(self, intervals): """ :type intervals: List[Interval] :rtype: int """ times = [] for interval in intervals: times.append((interval.start, 1)) times.append((interval.end, 0)) times.sort(key = lambda x: (x[0], x[1])) maxCount = 0 curCount = 0 for time in times: if time[1] == 1: curCount += 1 maxCount = max(curCount, maxCount) else: curCount -= 1 return maxCount
SHUFFLE: Write a method to shuffle a deck of cards. It must be a perfect shuffle -- in other words, each of the 52! permutations of the deck has to be equally likely. Assume that you are given a random number generator which is perfect.
If you have randomly shuffled cards from 0 to i, then to shuffle cards from 0 to i+1, then just need to swap in i+1 with a random card in 0 to i. def shuffle(cards): for i in range(len(cards)): toSwitch = rand(0, i) temp = cards[toSwitch] cards[toSwitch] = cards[i] cards[i] = temp return cards
KTH SMALLEST ELEMENT IN BST: Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Note: You may assume k is always valid, 1 ≤ k ≤ BST's total elements. Example 1: Input: root = [3,1,4,null,2], k = 1 3 / \ 1 4 \ 2 Output: 1
In order traversal. recurse left, visit root, then recurse right. The tricky part is storing the kth value, because initially I was just returning it but that was causing the value to be overwritten at each level. The key is to store the level and the result in a global variable so that it is only altered once and the same level is used for the whole function (instead of having to worry about passing it through) class Solution(object): def __init__(self): self.result = float("-inf") self.order = 0 def kthSmallest(self, root, k): """ :type root: TreeNode :type k: int :rtype: int """ def inOrderTraversal(node): if node: inOrderTraversal(node.left) self.order += 1 if self.order == k: self.result = node.val return inOrderTraversal(node.right) inOrderTraversal(root) return self.result
BINARY TREE RIGHT SIDE VIEW: Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom. Example: Input: [1,2,3,null,5,null,4] Output: [1, 3, 4] Explanation: 1 <--- / \ 2 3 <--- \ \ 5 4 <---
Intuitively just recurse right until you can't then check left nodes. But also have to keep in mind that the left subtree might be longer than right subtree so there would be a view on that side as well. Thus need to keep track of depths and add something at each depth. Just use DFS and recurse on right side first. def rightSideView(self, root): """ :type root: TreeNode :rtype: List[int] """ result = [] def recurse (node, depth): if node != None: if depth == len(result): result.append(node.val) recurse(node.right, depth + 1) recurse(node.left, depth + 1) recurse(root, 0) return result
VALIDATE BST: Implement a function to check if binary tree is a binary search tree
Is a BST is the left and right subtrees are also BST and everything in the left is less than or equal to root and everything in right subtree is greater than the root So recurse but also keep track of root to make sure the above invariants hold def isBST(root): def BSTutil(root, min, max): if root == NULL: return True if root.value <= min and root.value > max: return false if !BSTutil(root.left, min, root.value)|| !BSTutil(root.right, root.value, max): return false return true return BSTutil(root.left, float(-inf), root.value) and BSTutil(root.right, root.value, float(inf))
CONTIGUOUS SEQUENCE: You are given an array of integers (both positive and negative). Find the contiguous sequence with the largest sum. Return the sum. Input: 2, -8, 3, -2, 4, -10 Output: 5 (ie. {3, -2, 4})
Iterate through array keeping track of curMax and resultMax. If curMax <= 0, then reset it to 0 because this subarray sum can only detract from the total max. The only time we use a negative number is if the it doesn't result in a negative. (eg. 3, -2, 7) def maxSubArray(self, nums): """ :type nums: List[int] :rtype: int """ curMax = 0 resultMax = float("-inf") for num in nums: curMax += num resultMax = max(curMax, resultMax) if curMax <=0: curMax = 0 return resultMax
STRING COMPRESSION: Implement a method to perform basic string compression using the counts of repeated characters. For example, the string aabcccccaaa would become a2b1c5a3. If the "compressed" string would not become smaller than the original string, your method should return the original string. You can assumer the string has only uppercase and lowercase letters (a-z)
Keep running count and increment letters. If changes, append total to string and reset count. Check length of string at end compared to original.
BABY NAMES: Each year, the government releases a list of the 10000 most common baby names and their frequencies (the number of babies with that name). The only problem with this is that some names have multiple spellings. For example "John" and "Jon" are essentially the same name but would be listed separately in the list. Given two lists, one of names/frequencies and the other of pairs of equivalent names, write an algorithm to print a new list of the true frequency of each name. Note that if John and Jon are synonyms, and Jon and Johnny are synonyms, then John and Johnny are synonyms. (It is both transitive and symmetric). In the final list, any name can be used as the "real" name. Input: Names: John (15), Jon (12), Chris (13), Kris (4), Christopher (19) Synonyms: (Jon, John), (John, Johnny), (Chris, Kris), (Chris, Christopher) Output: John (27), Kris (36)
Make a graph of names. Use DFS to traverse and add up counts.
RECURSIVE MULTIPLY: Write a recursive function to multiply two positive integers without using the * operator. You can use addition, subtraction, and bit shifting, but you should minimize the number of those operations
Multiplying is just adding a number a certain number of times 1) add the bigger number to itself smaller number of times 2)divide the smaller number by two (arithmetic right shift) and add bigger # that many times and then add those together 3) can recurse on the halves by continuing to divide by two (if odd, add number at end as well) def multiply(a, b): if smaller == 0: return 0 if smaller == 1: return b bigger = max(a, b) smaller = min(a, b) halfSmaller = smaller >> 1 half = multiply(halfSmaller, bigger) if smaller % 2 == 0: odd = 0 else: odd = bigger return half + half + odd
BEST TIME TO BUY AND SELL STOCK: Say you have an array for which the ith element is the price of a given stock on day i. If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit. Note that you cannot sell a stock before you buy one. Input: [7,1,5,3,6,4] Output: 5 Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. Not 7-1 = 6, as selling price needs to be larger than buying price.
Note that once price starts increasing, then we can actually make profit. Keep track of smallest element seen, and whenever see bigger one, update maxProfit accordingly. If smaller, update minSell accordingly. def maxProfit(self, prices): """ :type prices: List[int] :rtype: int """ if len(prices) < 2: return 0 maxProfit = 0 minPrice = prices[0] maxPrice = 0 for i in range(1, len(prices)): if prices[i] > minPrice: maxPrice = max(prices[i] - minPrice, maxPrice) elif prices[i] < minPrice: minPrice = prices[i] return maxPrice
COPY LIST WITH RANDOM POINTER: A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list.
O(n) space: Iterate through linked list and add new nodes by either referencing seen dictionary for both next and random. O(1) space (edit in place): Iterate through linked list and copy next nodes and weave with original linked list. Go through again and unweave while adding in random pointers. def copyRandomList(self, head): """ :type head: RandomListNode :rtype: RandomListNode """ if head == None: return None curHead = head while curHead != None: copyNode = RandomListNode(curHead.label) copyNode.next = curHead.next curHead.next = copyNode curHead = copyNode.next origHead = head copyHead = head.next origCur = origHead copyCur = copyHead while origCur != None: if origCur.random != None: copyCur.random = origCur.random.next origCur = origCur.next.next if copyCur.next is not None: copyCur = copyCur.next.next origCur = origHead copyCur = copyHead while origCur != None: origCur.next = origCur.next.next if copyCur.next is not None: copyCur.next = copyCur.next.next origCur = origCur.next copyCur = copyCur.next return copyHead
MAGIC INDEX: A magic index in an array A[0, ... n-1] is defined to be an index such that A[i] = i. Given a sorted array of distinct integers, write a method to find a magic index, if one exists, in array A Follow up: what if the values are not distinct?
Recursion. Start at middle index i, if value at i is less than i, then search right side, else search left Follow up (not distinct): start at middle index i and check for equality. if not equal, recursively search the left and right side: left: search indices start through min(midIndex -1, midValue) right: search indices max(midIndex + 1, midValue) through end def magicIndex(arr): def magicHelper(arr, start, end): if end < start: return -1 mid = (start + end) / 2 if arr[mid] == mid: return mid left = magicHelper(arr, start, min(arr[mid], mid - 1)) if left >= 0: return left right = magicHelper(arr, max(mid + 1, arr[mid]), end) if right >= 0: return right return magicHelper(arr, 0, len(arr))
CHECK BALANCED: Implement a function to check if a binary tree is balanced. For the purpose of this question, a balanced tree is defined to be a tree such that the heights of the two subtrees of any node never differ by more than one
Recursive Is only balanced if left and right subtrees are balanced and their heights never differ by more than one def isBalanced(root): def balancedUtil(root): if root == Null: return -1 left = balancedUtil(root.left) if left == float("inf): return left right = balancedUtil(root.right) if right == float("inf): return right if abs(left - right) > 1: return float("inf") else: return max(left, right) + 1 return balancedUtil(root) != float("inf")
RANDOM SET: Write a method to randomly generate a set of m integers from an array of size n. Each element must have equal probability of being chosen
Similar idea to shuffle deck. If we can pull a random set of m elements from an array of size n-1, then to pull a set of m elements from an array of size of n, we need to decide of arr[n] should be inserted into subset by using rand(0, n). If it is less than n-1, then swap at that index. def randSet(original, m): newSet = original[0:m] for i in range(m, len(original): k = rand(0, i) if k < m: newSet[k] = original[i] return newSet
SMALLEST DIFFERENCE: Given two arrays of integers, compute the pair of values (one value in each array) with the smallest (non-negative) difference. Return the difference.
Sort both arrays, and then compare.
CIRCUS TOWER: A circus is designing a tower routine consisting of people standing atop one another's shoulders. For practical and aesthetic reasons, each person must be both shorter and lighter than the person below him or her. Given the heights and weights of each person in the circus, write a method to compute the largest possible number of people in such a tower.
Sort by increasing height. Then do longest increasing subsequence on weights.
INSERT DELETE GETRANDOM O(1) - DUPLICATES ALLOWED: Design a data structure that supports all following operations in average O(1) time. Note: Duplicate elements are allowed. insert(val): Inserts an item val to the collection. remove(val): Removes an item val from the collection if present. getRandom: Returns a random element from current collection of elements. The probability of each element being returned is linearly related to the number of same value the collection contains.
Store actual data in an array and use random.choice(arr) to get a random element from it. Use a dict to store the indexes of the elements (store in set so addition and removal is constant time). When time to remove, switch toRemove with val at end so can pop off at constant time. from collections import defaultdict class RandomizedCollection(object): def __init__(self): """ Initialize your data structure here. """ self.structure = [] self.indexes = defaultdict(set) def insert(self, val): """ Inserts a value to the collection. Returns true if the collection did not already contain the specified element. :type val: int :rtype: bool """ exists = False self.structure.append(val) if val not in self.indexes or not self.indexes[val]: exists = True self.indexes[val].add(len(self.structure) - 1) return exists def remove(self, val): """ Removes a value from the collection. Returns true if the collection contained the specified element. :type val: int :rtype: bool """ if val not in self.indexes or not self.indexes[val]: return False index = self.indexes[val].pop() replace = self.structure[-1] self.indexes[replace].add(index) self.indexes[replace].remove(len(self.structure) - 1) self.structure[index] = replace self.structure.pop() return True def getRandom(self): """ Get a random element from the collection. :rtype: int """ return random.choice(self.structure)
SUM SWAP: Given two array of integers, find a pair of values (one value from each array) that you can swap to give the two arrays the same sum Input: {4, 1, 2, 1, 1, 2} and {3, 6, 3, 3} Output: {1, 3}
The difference between the two numbers swapped needs to be equal to |sum(a) - sum(b)| / 2 with the larger number coming from the larger sum array. add the contents of one array to a dict. iterate through other array and find value that fulfills equation above
SLIDING PUZZLE: On a 2x3 board, there are 5 tiles represented by the integers 1 through 5, and an empty square represented by 0. A move consists of choosing 0 and a 4-directionally adjacent number and swapping it. The state of the board is solved if and only if the board is [[1,2,3],[4,5,0]]. Given a puzzle board, return the least number of moves required so that the state of the board is solved. If it is impossible for the state of the board to be solved, return -1. Examples: Input: board = [[1,2,3],[4,0,5]] Output: 1 Explanation: Swap the 0 and the 5 in one move. Input: board = [[1,2,3],[5,4,0]] Output: -1 Explanation: No number of moves will make the board solved.
Use BFS with the boards as nodes. Represent the board as a string, and then keep a dictionary of possible moves with 0 at each index. When doing BFS where trying to keep count of minimum number of moves, use a children list to populate and then replace the queue with it. def slidingPuzzle(self, board): """ :type board: List[List[int]] :rtype: int """ solution = "123450" moves = { 0: [1, 3], 1: [0, 2, 4], 2: [1, 5], 3: [0, 4], 4: [1, 3, 5], 5: [2, 4] } curBoard = "".join([str(x) for row in board for x in row]) visited = set() visited.add(curBoard) count = 0 queue = [curBoard] while queue: children = [] for b in queue: if b == solution: return count visited.add(b) index = b.index("0") strb = [c for c in b] for move in moves[index]: new_b = strb[:] new_b[index], new_b[move] = new_b[move], new_b[index] new_s = "".join(new_b) if new_s not in visited: children.append(new_s) queue = children count += 1 return -1
LETTER COMBINATIONS OF A PHONE NUMBER: Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters. numToLetter = { '2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', '6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz' }
Use DFS. Key is to pass along current prefix in DFS function and then append to result when it's length is the same as the initial number of digits def letterCombinations(self, digits): """ :type digits: str :rtype: List[str] """ if digits is None or len(digits) == 0: return [] numToLetter = { '2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', '6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz' } result = [] def dfs(prefix, curDigits): if len(prefix) == len(digits): result.append(prefix) return letters = numToLetter[curDigits[0]] for letter in letters: dfs(prefix+letter, curDigits[1:]) dfs('', digits) return result
CHEAPEST FLIGHTS WITHIN K STOPS: There are n cities connected by m flights. Each fight starts from city u and arrives at v with a price w. Now given all the cities and flights, together with starting city src and the destination dst, your task is to find the cheapest price from src to dst with up to k stops. If there is no such route, output -1.
Use Dijkstra's collections.defaultdict(dict) for holding edges with associated prices for flights from a to b f[a][b] = price heap = [(0, src, K + 1)] priority, location, how many stops have left heapq.heappop heapq.heappush for priority queue stuff on list def findCheapestPrice(self, n, flights, src, dst, K): """ :type n: int :type flights: List[List[int]] :type src: int :type dst: int :type K: int :rtype: int """ f = collections.defaultdict(dict) for a, b, p in flights: f[a][b] = p heap = [(0, src, K + 1)] while heap: p, i, K = heapq.heappop(heap) if i == dst: return p if K > 0: for j in f[i]: heapq.heappush(heap, (p + f[i][j], j, K - 1)) return -1
RETURN KTH TO LAST: Implement an algorithm to find the kth to last element of a singly linked list
Use two pointers. One is k steps ahead of the other. Begin to increment until the second one hits the end, the first one will be at the answer
MASTER MIND: The game of Master Mind is played as follows: The computer has four slots, and each slot will contain a ball that is red(R), yellow(Y), green(G), or blue(B). For example, the computer might have RGGB (Slot #1 is red, Slots #2 and #3 are green, Slot #4 is blue) You, the user, are trying to guess the solution. You might, for example, guess YRGB. When you guess the solution. You might, for example, guess YRGB. When you guess the correct color for the correct slot, you get a "hit." If you guess a color that exists but is in the wrong slot, you get a "pseudo-hit." Note that a slot that is a hit can never count as a pseudo-hit. For example, if the actual solution is RGBY and you guess GGRR, you have one hit and one pseudo-hit. Write a method that, given a guess and a solution, returns the number of hits and pseudo-hits.
Use a hashmap to keep track of character frequencies in solution, but don't increment counter for hits. Go through guess again to find pseudo hits.
FLATTEN 2D VECTOR: Implement an iterator to flatten a 2d vector. Input: 2d vector = [ [1,2], [3], [4,5,6] ] Output: [1,2,3,4,5,6] Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,2,3,4,5,6].
Use a list comprehension! Initialize a flat 1d array with the contents of the 2d array and go from there. For using list comprehensions on a multidimensional array order the loops in the same way they would be nested, from left to right eg. loop over rows in vec2d first, then over each element in the row class Vector2D(object): def __init__(self, vec2d): self.cur = 0 self.vec = [x for row in vec2d for x in row] def next(self): val = self.vec[self.cur] self.cur += 1 return val def hasNext(self): return self.cur < len(self.vec)
MINMAL TREE: Given a sorted (increasing order) array with unique integer elements, write an algorithm to create a binary search tree with minimal height
Use a recursive algorithm. Use middle index as root, then recurse on left and right (continuing to use the middle indexes of the respective slices as roots)
LONGEST INDCREASING SUBSEQUENCE: Given an unsorted array of integers, find the length of longest increasing subsequence. Input: [10,9,2,5,3,7,101,18] Output: 4 Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
Use dynamic programming. With an array that contains the longest subsequence up to and including i at each index. lenSub[j] = 1 or max(lenSub[i] where nums[j] > nums[i]) def lengthOfLIS(self, nums): """ :type nums: List[int] :rtype: int """ if len(nums) < 2: return len(nums) lenSub = [0 for num in nums] lenSub[0] = 1 totalMax = 1 for i in range(1, len(nums)): num = nums[i] curMax = 0 for j in range(i): if num > nums[j]: curMax = max(curMax, lenSub[j]) lenSub[i] = curMax + 1 totalMax = max(totalMax, curMax+1) return totalMax
LRU CACHE: Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put. get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. FOLLOW UP: Could you do both operations in O(1) time complexity?
Use hashmap for storing values, and a queue for keeping track of accessed values Use hashmap for storing values (but values are nodes in linked list). Use doubly linked list to keep track of accessed values. Can set and remove and move to front in constant time given the node to edit (have to build doubly linked list from scratch tho)
MINIMUM WINDOW SUBSTRING: Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n). Input: S = "ADOBECODEBANC", T = "ABC" Output: "BANC"
Use substring template. Use a hashmap to keep track of needed frequencies of characters. Use start and end pointer and increment end. Whenever condition is met, increase start while condition holds to find minimum. def minWindow(self, s, t): """ :type s: str :type t: str :rtype: str """ if s is None or len(t) > len(s): return "" counter = len(t) chars = collections.defaultdict(int) start, end = 0, 0 minWindow = len(s) + 1 head = 0 for char in t: chars[char] += 1 while end < len(s): if s[end] in chars: chars[s[end]] -= 1 if chars[s[end]] >= 0: counter -= 1 while start <= end and counter == 0: if end-start + 1 < minWindow: minWindow = end-start + 1 head = start if s[start] in chars: chars[s[start]] += 1 if chars[s[start]] > 0: counter += 1 start += 1 end += 1 if minWindow > len(s): return "" return s[head: head+minWindow]
VERIFY PREORDER SEQUENCE IN BST: Given an array of numbers, verify whether it is the correct preorder traversal sequence of a binary search tree. You may assume each number in the sequence is unique. Consider the following binary search tree: 5 / \ 2 6 / \ 1 3 Example 1: Input: [5,2,6,1,3] Output: false Example 2: Input: [5,2,1,3,6] Output: true
When on the left subtree, the number should just be decreasing. Once it starts increasing that means we're on a right subtree and we must keep track that it 's values are greater than the root it cam from. Use a stack to append left tree ancestors, when encounter and increasing number, pop off ancestors that are less than it (because they're from a left subtree) and keep track of the most recently popped off one as the minVal. If a value is less than the minVal, return False def verifyPreorder(self, preorder): from collections import deque stack = deque() minVal = float("-inf") for number in preorder: if number < minVal: return False while stack and stack[-1] < number: minVal = stack.pop() stack.append(number) return True
Implement dog class in python
class Dog: def __init__(self, name): self.name = name self.tricks = [] def add_trick(self, trick): self.tricks.append(trick)
REVERSE A LINKED LIST
def reverseList(self, head): """ :type head: ListNode :rtype: ListNode """ prev = None switch = head while switch != None: switch.next, prev, switch = prev, switch, switch.next return prev
TRIPLE STEP: A child is running up a staircase with n steps and can hop either 1 step or 2 steps at a time. Implement a method to count how many possible ways the child can run up the stairs
dynamic programming def countSteps(n): if n < 3: return n ways = [0 for x in range(n+1)] ways[1] = 1 ways[2] = 2 for i in range(3, n+1): ways[i] = ways[i - 1] + ways[i - 2] return ways[n] or fibonacci def countSteps(n): if n < 3: return n a = 1 b = 2 for i in range(3, n+1): temp = b b = a + b a = temp return b
SUBARRAY PRODUCT LESS THAN K: Your are given an array of positive integers nums. Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k. Example 1: Input: nums = [10, 5, 2, 6], k = 100 Output: 8 Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]. Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.
find biggest subarray up to index i, and the number of subarrays is i-start + 1. Do this for all indexes and increment start everytime the product is greater than k. def numSubarrayProductLessThanK(self, nums, k): """ numSubs = 0 start = 0 curProd = 1 for end in range(len(nums)): curProd *= nums[end] while curProd >= k and start <= end: curProd /= nums[start] start += 1 numSubs += end - start + 1 return numSubs
SUBARRAY SUM EQUALS K: Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose sum equals to k. Input: nums = [1,1,1], k = 2 Output: 2 Input: nums = [-1,-1,1], k = 0 Output: 1
if there were no negative numbers, could do sliding window approach.... but that's not the case Find all targetArrays ending at y. Because runningSums (0 -> i) + targetArray (i+1 -> y) = totalRunningSum Therefore, just need to find out how many subRunningSums that equal totalRunningSum - target Keep track of all running sums from first index to current index. sum(i,j)=sum(0,j)-sum(0,i), where sum(i,j) represents the sum of all the elements from index i to j-1. def subSums(nums, k): curSum = 0 result = 0 runSums = collections.defaultdict(int) for num in nums: curSum += num if curSum == k: result += 1 result += runSums[curSum - k] runSums[curSum] += 1 return result
SEARCH IN ROTATED ARRAY: Given a sorted array of n integers that has been rotated an unknown number of times, write code to find an element in the array. You may assume that the array was originally sorted in increasing order
search from middle index if leftmost is less than middle (must be in increasing order) if right most is greater than middle(must be in increasing order) depending on if target is less than or greater, recurse on right or left side in case of left or right being duplicates: if only left, then search right, if both, then have to search both halves [2, 2, 4, 2, 2, 1, 2] def search: def helper(start, end): if end < start: return -1 mid = (start + end) / 2 if nums[mid] == target: return mid midNum = nums[mid] if nums[start] < midNum: if target >= nums[start] and target < midNum: return helper(start, mid - 1) else: return helper(mid + 1, end) elif nums[end] > midNum: if target > midNum and target <= nums[end]: return helper(mid + 1, end) else: return helper(start, mid - 1) elif nums[start] == midNum: if nums[end] == midNum: result = helper(start, mid - 1) if result == -1: result = helper(mid + 1, end) return result else: return helper(mid + 1, end) return -1 return helper(0, len(nums)-1)
HOUSE ROBBER: You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night. Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police. Input: [1,2,3,1] Output: 4 Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). Total amount you can rob = 1 + 3 = 4.
the max amount you can rob at house i is M[i] = max( M[i-2] + a[i], M[i-1] ) See that this is like fibonacci and we only need to keep track of i-1 and i-2 and update. def rob(self, nums): """ :type nums: List[int] :rtype: int """ prevMax, curMax = 0, 0 for num in nums: temp = curMax curMax = max(prevMax + num, curMax) prevMax = temp return curMax
LIST OF DEPTHS: Given a binary tree, design an algorithm which creates a linked list of all the nodes at each depth (eg. if you have a tree with depth D, you'll have D linked lists)
use arraylist of linked lists 1) use DFS, recurse down and just know that the level is the prev level + 1 and append at the linked list 2) use BFS (level traversal). root is own linked list. it's children in a queue. Add the children into linked list, then explore children's children and add that to a queue. Add those to linked list. so on and so forth