Cracking the coding interview

¡Supera tus tareas y exámenes ahora con Quizwiz!

We can use PriorityQueue, create Animal class with order, and name. Implement comparable and add it into queue.

Animal Shelter: An animal shelter, which holds only dogs and cats, operates on a strictly "first in, first out" basis. People must adopt either the "oldest" (based on arrival time) of all animals at the shelter, or they can select whether they would prefer a dog or a cat (and will receive the oldest animal of that type). They cannot select which specific animal they would like. Create the data structures to maintain this system and implement operations such as enqueue, dequeueAny, dequeueDog, and dequeueCat. You may use the built-in LinkedList data structure.

/* Read through (name, frequency) pairs and initialize a mapping * of names to NameSets (equivalence classes).*/ public static HashMap<String, NameSet> constructGroups(HashMap<String, Integer> names) { HashMap<String, NameSet> groups = new HashMap<String, NameSet>(); for (Entry<String, Integer> entry : names.entrySet()) { String name = entry.getKey(); int frequency = entry.getValue(); NameSet group = new NameSet(name, frequency); groups.put(name, group); } return groups; } public static void mergeClasses(HashMap<String, NameSet> groups, String[][] synonyms) { for (String[] entry : synonyms) { String name1 = entry[0]; String name2 = entry[1]; NameSet set1 = groups.get(name1); NameSet set2 = groups.get(name2); if (set1 != set2) { /* Always merge the smaller set into the bigger one. */ NameSet smaller = set2.size() < set1.size() ? set2 : set1; NameSet bigger = set2.size() < set1.size() ? set1 : set2; /* Merge lists */ Set<String> otherNames = smaller.getNames(); int frequency = smaller.getFrequency(); bigger.copyNamesWithFrequency(otherNames, frequency); /* Update mapping */ for (String name : otherNames) { groups.put(name, bigger); } } } } public static HashMap<String, Integer> convertToMap(HashMap<String, NameSet> groups) { HashMap<String, Integer> list = new HashMap<String, Integer>(); for (NameSet group : groups.values()) { list.put(group.getRootName(), group.getFrequency()); } return list; } public static HashMap<String, Integer> trulyMostPopular(HashMap<String, Integer> names, String[][] synonyms) { HashMap<String, NameSet> groups = constructGroups(names); mergeClasses(groups, synonyms); return convertToMap(groups); } public class NameSet { private Set<String> names = new HashSet<String>(); private int frequency = 0; private String rootName; public NameSet(String name, int freq) { names.add(name); frequency = freq; rootName = name; } public Set<String> getNames() { return names; } public String getRootName() { return rootName; } public void copyNamesWithFrequency(Set<String> more, int freq) { names.addAll(more); frequency += freq; } public int getFrequency() { return frequency; } public int size() { return names.size(); } }

Baby Names: Each year, the government releases a list of the 10,000 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. EXAMPLE 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)

private static class NodePair { BiNode head; BiNode tail; public NodePair(BiNode head, BiNode tail) { this.head = head; this.tail = tail; } } public static NodePair convert(BiNode root) { if (root == null) { return null; } NodePair part1 = convert(root.node1); NodePair part2 = convert(root.node2); if (part1 != null) { concat(part1.tail, root); } if (part2 != null) { concat(root, part2.head); } return new NodePair(part1 == null ? root : part1.head, part2 == null ? root : part2.tail); } public static void concat(BiNode x, BiNode y) { x.node2 = y; y.node1 = x; }

BiNode: Consider a simple data structure called BiNode, which has pointers to two other nodes. Thedata structure BiNode could be used to represent both a binary tree (where node1 is the left node and node2 is the right node) or a doubly linked list (where node1 is the previous node and node2 is the next node). Implement a method to convert a binary search tree (implemented with BiNode) into a doubly linked list. The values should be kept in order and the operation should be performed in place (that is, on the original data structure).

public static int getHeight(TreeNode root) { if (root == null) { return -1; } return Math.max(getHeight(root.left), getHeight(root.right)) + 1; } public static boolean isBalanced(TreeNode root) { if (root == null) { return true; } int heightDiff = getHeight(root.left) - getHeight(root.right); if (Math.abs(heightDiff) > 1) { return false; } else { return isBalanced(root.left) && isBalanced(root.right); } }

Check Balanced: Implement a function to check if a binary tree is balanced. For the purposes 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.

Solution #1: Sort the strings. Solution #2: Check if the two strings have identical character counts. boolean permutation(String s, String t) { if (s.lengthO != t.lengthO) { return false ; } int[] letters = new int[128]; II Assumption char[] s_array = s.toCharArray(); for (char c : s_array) { II count number of each char i n s. letters[c]++; } for (int i = e; i < t.length(); i++) { int c = (int) t . charAt(i)j letters[c] --; if (letters[c] < 0) { return false; } } return true; }

Check Permutation: Given two strings, write a method to decide if one is a permutation of the other.

public static boolean containsTree(TreeNode t1, TreeNode t2) { if (t2 == null) { return true; // The empty tree is a subtree of every tree. } return subTree(t1, t2); } /* Checks if the binary tree rooted at r1 contains the binary tree * rooted at r2 as a subtree somewhere within it. */ public static boolean subTree(TreeNode r1, TreeNode r2) { if (r1 == null) { return false; // big tree empty & subtree still not found. } else if (r1.data == r2.data && matchTree(r1,r2)) { return true; } return subTree(r1.left, r2) || subTree(r1.right, r2); } /* Checks if the binary tree rooted at r1 contains the * binary tree rooted at r2 as a subtree starting at r1. */ public static boolean matchTree(TreeNode r1, TreeNode r2) { if (r1 == null && r2 == null) { return true; // nothing left in the subtree } else if (r1 == null || r2 == null) { return false; // exactly tree is empty, therefore trees don't match } else if (r1.data != r2.data) { return false; // data doesn't match } else { return matchTree(r1.left, r2.left) && matchTree(r1.right, r2.right); } }

Check Subtree: T1 and T2 are two very large binary trees, with T1 much bigger than T2. Create an algorithm to determine if T2 is a subtree of T1. A tree T2 is a subtree of T1 if there exists a node n in T1 such that the subtree of n is identical to T2 . That is, if you cut off the tree at node n, the two trees would be identical.

public class HtWt implements Comparable<HtWt> { private int height; private int weight; public HtWt(int h, int w) { height = h; weight = w; } public int compareTo(HtWt second) { if (this.height != second.height) { return ((Integer)this.height).compareTo(second.height); } else { return ((Integer)this.weight).compareTo(second.weight); } } public String toString() { return "(" + height + ", " + weight + ")"; } /* Returns true if "this" should be lined up before "other". Note * that it's possible that this.isBefore(other) and * other.isBefore(this) are both false. This is different from the * compareTo method, where if a < b then b > a. */ public boolean isBefore(HtWt other) { if (height < other.height && weight < other.weight) { return true; } else { return false; } } } public static ArrayList<HtWt> longestIncreasingSeq(ArrayList<HtWt> items) { Collections.sort(items); return bestSeqAtIndex(items, new ArrayList<HtWt>(), 0); } // Returns longer sequence private static ArrayList<HtWt> max(ArrayList<HtWt> seq1, ArrayList<HtWt> seq2) { if (seq1 == null) { return seq2; } else if (seq2 == null) { return seq1; } return seq1.size() > seq2.size() ? seq1 : seq2; } private static boolean canAppend(ArrayList<HtWt> solution, HtWt value) { if (solution == null) { return false; } if (solution.size() == 0) { return true; } HtWt last = solution.get(solution.size() - 1); return last.isBefore(value); } private static ArrayList<HtWt> bestSeqAtIndex(ArrayList<HtWt> array, ArrayList<HtWt> sequence, int index) { if (index >= array.size()) return sequence; HtWt value = array.get(index); ArrayList<HtWt> bestWith = null; if (canAppend(sequence, value)) { ArrayList<HtWt> sequenceWith = (ArrayList<HtWt>) sequence.clone(); sequenceWith.add(value); bestWith = bestSeqAtIndex(array, sequenceWith, index + 1); } ArrayList<HtWt> bestWithout = bestSeqAtIndex(array, sequence, index + 1); return max(bestWith, bestWithout); }

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.

public static int makeChange(int amount, int[] denoms, int index) { if (index >= denoms.length - 1) return 1; // one denom remaining -> one way to do it int denomAmount = denoms[index]; int ways = 0; for (int i = 0; i * denomAmount <= amount; i++) { int amountRemaining = amount - i * denomAmount; ways += makeChange(amountRemaining, denoms, index + 1); // go to next denom } return ways; } public static int makeChange(int amount, int[] denoms) { return makeChange(amount, denoms, 0); } public static void main(String[] args) { int[] denoms = {25, 10, 5, 1}; int ways = makeChange(300322, denoms); System.out.println(ways); }

Coins: Given an infinite number of quarters (25 cents), dimes (10 cents), nickels (5 cents), and pennies (1 cent), write code to calculate the number of ways of representing n cents.

public static int getMaxSum(int[] a) { int maxSum = 0; int runningSum = 0; for (int i = 0; i < a.length; i++) { runningSum += a[i]; if (maxSum < runningSum) { maxSum = runningSum; } else if (runningSum < 0) { runningSum = 0; } } return maxSum; }

Contiguous Sequence: You are given an array of integers (both positive and negative). Find the contiguous sequence with the largest sum. Return the sum. EXAMPLE Input 2, -8, 3, -2, 4, -10 OutputS (i.e., {3, -2, 4})

We just need to go through all unique sets of K planks (sets, not orders!). There are only K ways of picking K planks if we only have two possible types: {O of type A, K of type B}, {1 of type A, K -1 of type B}, {2 of type A, K - 2 of type B}, ... public static HashSet<Integer> allLengths(int k, int shorter, int longer) { counter++; HashSet<Integer> lengths = new HashSet<Integer>(); for (int nShorter = 0; nShorter <= k; nShorter++) { int nLonger = k - nShorter; int length = nShorter * shorter + nLonger * longer; lengths.add(length); } return lengths; }

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.

/* Check if (row1, column1) is a valid spot for a queen by checking if there * is a queen in the same column or diagonal. We don't need to check it for queens * in the same row because the calling placeQueen only attempts to place one queen at * a time. We know this row is empty. */ public static boolean checkValid(Integer[] columns, int row1, int column1) { for (int row2 = 0; row2 < row1; row2++) { int column2 = columns[row2]; /* Check if (row2, column2) invalidates (row1, column1) as a queen spot. */ /* Check if rows have a queen in the same column */ if (column1 == column2) { return false; } /* Check diagonals: if the distance between the columns equals the distance * between the rows, then they're in the same diagonal. */ int columnDistance = Math.abs(column2 - column1); int rowDistance = row1 - row2; // row1 > row2, so no need to use absolute value if (columnDistance == rowDistance) { return false; } } return true; } public static void placeQueens(int row, Integer[] columns, ArrayList<Integer[]> results) { if (row == GRID_SIZE) { // Found valid placement results.add(columns.clone()); } else { for (int col = 0; col < GRID_SIZE; col++) { if (checkValid(columns, row, col)) { columns[row] = col; // Place queen placeQueens(row + 1, columns, results); } } } }

Eight Queens: Write an algorithm to print all ways of arranging eight queens on an 8x8 chess board so that none of them share the same row, column, or diagonal. In this case, "diagonal" means all diagonals, not just the two that bisect the board.

public static String[] smalls = {"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"}; public static String[] tens = {"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}; public static String[] bigs = {"", "Thousand", "Million", "Billion"}; public static String hundred = "Hundred"; public static String negative = "Negative"; public static String convert(int num) { if (num == 0) { return smalls[0]; } else if (num < 0) { return negative + " " + convert(-1 * num); } LinkedList<String> parts = new LinkedList<String>(); int chunkCount = 0; while (num > 0) { if (num % 1000 != 0) { String chunk = convertChunk(num % 1000) + " " + bigs[chunkCount]; parts.addFirst(chunk); } num /= 1000; // shift chunk chunkCount++; } return listToString(parts); } /* Convert a linked list of strings to a string, dividing it up with spaces. */ public static String listToString(LinkedList<String> parts) { StringBuilder sb = new StringBuilder(); while (parts.size() > 1) { sb.append(parts.pop()); sb.append(" "); } sb.append(parts.pop()); return sb.toString(); } public static String convertChunk(int number) { LinkedList<String> parts = new LinkedList<String>(); /* Convert hundreds place */ if (number >= 100) { parts.addLast(smalls[number / 100]); parts.addLast(hundred); number %= 100; } /* Convert tens place */ if (number >= 10 && number <= 19) { parts.addLast(smalls[number]); } else if (number >= 20) { parts.addLast(tens[number / 10]); number %= 10; } /* Convert ones place */ if (number >= 1 && number <= 9) { parts.addLast(smalls[number]); } return listToString(parts); }

English tnt: Given any integer, print an English phrase that describes the integer (e.g ., "One Thousand, Two Hundred Thirty Four").

public TreeNode commonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(!covers(root, p) || !covers(root, q)) return null; return ancestorHelper(root, p, q); } private TreeNode ancestorHelper(TreeNode root, TreeNode p, TreeNode q) { if(root == null || root == p || root == q) return root; boolean pOnLeft = covers(root.left, p); boolean qOnLeft = covers(root.left, q); if(pOnLeft != qOnLeft) { return root; } TreeNode childSide = pOnLeft ? root.left : root.right; return ancestorHelper(childSide, p, q); } private boolean covers(TreeNode root, TreeNode p) { if(root == null) return false; if(root == p) return true; return covers(root.left, p) || covers(root.right, p); }

First Common Ancestor: Design an algorithm and write code to find the first common ancestor of two nodes in a binary tree. Avoid storing additional nodes in a data structure. NOTE: This is not necessarily a binary search tree.

public class AnagramComparator implements Comparator<String> { private String sortChars(String s) { char[] content = s.toCharArray(); Arrays.sort(content); return new String(content); } public int compare(String s1, String s2) { return sortChars(s1).compareTo(sortChars(s2)); } } Then later in the code: Arrays.sort(strings, new AnagramComparator());

Group Anagrams: Write a method to sort an array of strings so that all the anagrams are next to each other.

boolean isUniqueChars(String str) { if (str.length() > 128) return false; boolean[] char_set = new boolean[128]; for (int i = 8; i < str.length(); i++) { int val = str.charAt(i); if (char_set[val]) { // Already found this char in string return false; } char_set[val] = true; } return true; } The time complexity for this code is O( n), where n is the length of the string. The space complexity is O( 1).

Implement an algorithm to determine if a string has all unique characters. What if you cannot use additional data structures?

public static LinkedListNode findIntersection(LinkedListNode list1, LinkedListNode list2) { if (list1 == null || list2 == null) return null; /* Get tail and sizes. */ Result result1 = getTailAndSize(list1); Result result2 = getTailAndSize(list2); /* If different tail nodes, then there's no intersection. */ if (result1.tail != result2.tail) { return null; } /* Set pointers to the start of each linked list. */ LinkedListNode shorter = result1.size < result2.size ? list1 : list2; LinkedListNode longer = result1.size < result2.size ? list2 : list1; /* Advance the pointer for the longer linked list by the difference in lengths. */ longer = getKthNode(longer, Math.abs(result1.size - result2.size)); /* Move both pointers until you have a collision. */ while (shorter != longer) { shorter = shorter.next; longer = longer.next; } /* Return either one. */ return longer; }

Intersection: Given two (singly) linked lists, determine if the two lists intersect. Return the intersecting node. Note that the intersection 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) as the jth node of the second linked list, then they are intersecting.

public static ArrayList<LinkedList<TreeNode>> createLevelLinkedList(TreeNode root) { ArrayList<LinkedList<TreeNode>> result = new ArrayList<LinkedList<TreeNode>>(); /* "Visit" the root */ LinkedList<TreeNode> current = new LinkedList<TreeNode>(); if (root != null) { current.add(root); } while (current.size() > 0) { result.add(current); // Add previous level LinkedList<TreeNode> parents = current; // Go to next level current = new LinkedList<TreeNode>(); for (TreeNode parent : parents) { /* Visit the children */ if (parent.left != null) { current.add(parent.left); } if (parent.right != null) { current.add(parent.right); } } } return result; }

List of Depths: Given a binary tree, design an algorithm which creates a linked list of all the nodes at each depth (e.g., if you have a tree with depth D, you 'll have D linked lists).

We could solve this by iterating through the list, from the longest word to the shortest word. For each word, we would split it into all possible pairs and check if both the left and right side are contained in the list. public static String printLongestWord(String arr[]) { HashMap<String, Boolean> map = new HashMap<String, Boolean>(); for (String str : arr) { map.put(str, true); } Arrays.sort(arr, new LengthComparator()); // Sort by length for (String s : arr) { if (canBuildWord(s, true, map)) { System.out.println(s); return s; } } return ""; } public static boolean canBuildWord(String str, boolean isOriginalWord, HashMap<String, Boolean> map) { if (map.containsKey(str) && !isOriginalWord) { return map.get(str); } for (int i = 1; i < str.length(); i++) { String left = str.substring(0, i); String right = str.substring(i); if (map.containsKey(left) && map.get(left) == true && canBuildWord(right, false, map)) { return true; } } map.put(str, false); return false; }

Longest Word: Given a list of words, write a program to find the longest word made of other words in the list.

public static LinkedListNode FindBeginning(LinkedListNode head) { LinkedListNode slow = head; LinkedListNode fast = head; // Find meeting point while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) { break; } } // Error check - there is no meeting point, and therefore no loop if (fast == null || fast.next == null) { return null; } /* Move slow to Head. Keep fast at Meeting Point. Each are k steps /* from the Loop Start. If they move at the same pace, they must * meet at Loop Start. */ slow = head; while (slow != fast) { slow = slow.next; fast = fast.next; } // Both now point to the start of the loop. return fast; }

Loop Detection: Given a circular linked list, implement an algorithm that returns the node at the beginning of the loop. DEFINITION Circular linked list: A (corrupt) linked list in which a node's next pointer points to an earlier node, so as to make a loop in the linked list. EXAMPLE Input: A -> B -> C - > D -> E -> C [the same C as earlier) Output: C

public static int magicFast(int[] array, int start, int end) { if (end < start) { return -1; } int mid = (start + end) / 2; if (array[mid] == mid) { return mid; } else if (array[mid] > mid){ return magicFast(array, start, mid - 1); } else { return magicFast(array, mid + 1, end); } } public static int magicFast(int[] array) { return magicFast(array, 0, array.length - 1); } Follow up public static int magicFast(int[] array, int start, int end) { if (end < start) { return -1; } int midIndex = (start + end) / 2; int midValue = array[midIndex]; if (midValue == midIndex) { return midIndex; } /* Search left */ int leftIndex = Math.min(midIndex - 1, midValue); int left = magicFast(array, start, leftIndex); if (left >= 0) { return left; } /* Search right */ int rightIndex = Math.max(midIndex + 1, midValue); int right = magicFast(array, rightIndex, end); return right; } public static int magicFast(int[] array) { return magicFast(array, 0, array.length - 1); }

Magic Index: A magic index in an array A [1. .. 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?

public static int getCandidate(int[] array) { int majority = 0; int count = 0; for (int n : array) { if (count == 0) { majority = n; } if (n == majority) { count++; } else { count--; } } return majority; } public static boolean validate(int[] array, int majority) { int count = 0; for (int n : array) { if (n == majority) { count++; } } return count > array.length / 2; } public static int findMajorityElement(int[] array) { int candidate = getCandidate(array); return validate(array, candidate) ? candidate : -1; }

Majority Element: A majority element is an element that makes up more than half of the items in an array. Given a positive integers array, find the majority element. If there is no majority element, return -1. Do this in O( N) time and O( 1) space. Input: 1 2 5 9 5 9 5 5 5 Output: 5

public static class Result { public int hits; public int pseudoHits; public Result(int h, int p) { hits = h; pseudoHits = p; } public Result() { } public String toString() { return "(" + hits + ", " + pseudoHits + ")"; } }; public static int code(char c) { switch (c) { case 'B': return 0; case 'G': return 1; case 'R': return 2; case 'Y': return 3; default: return -1; } } public static int MAX_COLORS = 4; public static Result estimate(String guess, String solution) { if (guess.length() != solution.length()) return null; Result res = new Result(); int[] frequencies = new int[MAX_COLORS]; /* Compute hits and built frequency table */ for (int i = 0; i < guess.length(); i++) { if (guess.charAt(i) == solution.charAt(i)) { res.hits++; } else { /* Only increment the frequency table (which will be used for pseudo-hits) if * it's not a hit. If it's a hit, the slot has already been "used." */ int code = code(solution.charAt(i)); if (code >= 0) { frequencies[code]++; } } } /* Compute pseudo-hits */ for (int i = 0; i < guess.length(); i++) { int code = code(guess.charAt(i)); if (code >= 0 && frequencies[code] > 0 && guess.charAt(i) != solution.charAt(i)) { res.pseudoHits++; frequencies[code]--; } } return res; }

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 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 pseudohit. Write a method that, given a guess and a solution, returns the number of hits and pseudo-hits.

The algorithm is as follows: 1. Insert into the tree the middle element of the array. 2. Insert (into the left subtree) the left subarray elements. 3. Insert (into the right subtree) the right subarray elements. 4. Recurse. public TreeNode createMinimalBST(int array[]) { return createMinimalBST(array, 0, array.length - 1); } private TreeNode createMinimalBST(int arr[], int start, int end){ if (end < start) { return null; } int mid = (start + end) / 2; TreeNode n = new TreeNode(arr[mid]); n.left = createMinimalBST(arr, start, mid - 1); n. right = createMinimalBST(arr, mid + 1, end); return n; }

Minimal Tree: Given a sorted (increasing order) array with unique integer elements, write an algorithm to create a binary search tree with minimal height.

Let's start with an example: T = {"is", "ppi", "hi", "sis", "i", "ssippi"} b = "mississippi" Note that in our example, we made sure to have some strings (like "is") that appear multiple times in b. The naive solution is reasonably straightforward. Just search through the bigger string for each instance of the smaller string. public static HashMapList<String, Integer> searchAll(String big, String[] smalls) { HashMapList<String, Integer> lookup = new HashMapList<String, Integer>(); for (String small : smalls) { ArrayList<Integer> locations = search(big, small); lookup.put(small, locations); } return lookup; } public static ArrayList<Integer> search(String big, String small) { ArrayList<Integer> locations = new ArrayList<Integer>(); for (int i = 0; i < big.length() - small.length() + 1; i++) { if (isSubstringAtLocation(big, small, i)) { locations.add(i); } } return locations; } public static boolean isSubstringAtLocation(String big, String small, int offset) { for (int i = 0; i < small.length(); i++) { if (big.charAt(offset + i) != small.charAt(i)) { return false; } } return true; } // Optimized solution Alternatively, we can add all the smaller strings into a trie. Now, when we want to find all words in mississippi, we search through this trie starting with each word. This algorithm takes 0 (kt) time to create the trie and O( bk) time to search for all the strings.

Multi Search: Given a string b and an array of smaller strings T, design a method to search b for each small string in T.

This is one of those problems where it's helpful to think about the "meaning" of each of these operations. What does it mean for two strings to be one insertion, replacement, or removal away from each other? Replacement: Consider two strings, such as bale and pale, that are one replacement away. Yes, that does mean that you could replace a character in bale to make pale. But more precisely, it means that they are different only in one place. Insertion: The strings apple and aple are one insertion away. This means that if you compared the strings, they would be identical-except for a shift at some point in the strings. Removal: The strings apple and aple are also one removal away, since removal is just the inverse of insertion. We'll merge the insertion and removal check into one step, and check the replacement step separately. Observe that you don't need to check the strings for insertion, removal, and replacement edits. The lengths of the strings will indicate which of these you need to check. public static boolean oneEditReplace(String s1, String s2) { boolean foundDifference = false; for (int i = 0; i < s1.length(); i++) { if (s1.charAt(i) != s2.charAt(i)) { if (foundDifference) { return false; } foundDifference = true; } } return true; } /* Check if you can insert a character into s1 to make s2. */ public static boolean oneEditInsert(String s1, String s2) { int index1 = 0; int index2 = 0; while (index2 < s2.length() && index1 < s1.length()) { if (s1.charAt(index1) != s2.charAt(index2)) { if (index1 != index2) { return false; } index2++; } else { index1++; index2++; } } return true; } public static boolean oneEditAway(String first, String second) { if (first.length() == second.length()) { return oneEditReplace(first, second); } else if (first.length() + 1 == second.length()) { return oneEditInsert(first, second); } else if (first.length() - 1 == second.length()) { return oneEditInsert(second, first); } return false; }

One Away: There are three types of edits that can be performed on strings: insert a character, remove a character, or replace a character. Given two strings, write a function to check if they are one edit (or zero edits) away. EXAMPLE pale, ple -> true pales, pale -> true pale, bale -> true pale, bae -> false

public enum Color { Black, White, Red, Yellow, Green } public static boolean PaintFill(Color[][] screen, int r, int c, Color ocolor, Color ncolor) { if (r < 0 || r >= screen.length || c < 0 || c >= screen[0].length) { return false; } if (screen[r][c] == ocolor) { screen[r][c] = ncolor; PaintFill(screen, r - 1, c, ocolor, ncolor); // up PaintFill(screen, r + 1, c, ocolor, ncolor); // down PaintFill(screen, r, c - 1, ocolor, ncolor); // left PaintFill(screen, r, c + 1, ocolor, ncolor); // right } return true; } public static boolean PaintFill(Color[][] screen, int r, int c, Color ncolor) { if (screen[r][c] == ncolor) return false; return PaintFill(screen, r, c, screen[r][c], ncolor); }

Paint Fill: Implement the "paint fill" function that one might see on many image editing programs. That is, given a screen (represented by a two-dimensional array of colors), a point, and a new color, fill in the surrounding area until the color changes from the original color.

Implementing this algorithm is fairly straightforward. We use a hash table to count how many times each character appears. Then, we iterate through the hash table and ensure that no more than one character has an odd count. This algorithm takes O(N) time, where N is the length of the string.

Palindrome Permutation: Given a string, write a function to check if it is a permutation of a palindrome. A palindrome is a word or phrase that is the same forwards and backwards. A permutation is a rearrangement of letters. The palindrome does not need to be limited to just dictionary words. EXAMPLE Input: Tact Coa Output: True (permutations:"taco cat'; "atco cta'; etc.)

public static ArrayList<String> generateParens(int count) { char[] str = new char[count*2]; ArrayList<String> list = new ArrayList<String>(); addParen(list, count, count, str, 0); return list; } public static void addParen(ArrayList<String> list, int leftRem, int rightRem, char[] str, int index) { if (leftRem < 0 || rightRem < leftRem) return; // invalid state if (leftRem == 0 && rightRem == 0) { /* all out of left and right parentheses */ list.add(String.copyValueOf(str)); } else { str[index] = '('; // Add left and recurse addParen(list, leftRem - 1, rightRem, str, index + 1); str[index] = ')'; // Add right and recurse addParen(list, leftRem, rightRem - 1, str, index + 1); } }

Parens: Implement an algorithm to print all valid (Le., properly opened and closed) combinations of n pairs of parentheses. EXAMPLE Input: 3 Output: ((())), (()()), (())(), ()(()), ()()()

// This algorithm takes 0 (n) time. public static void swap(int[] array, int left, int right) { int temp = array[left]; array[left] = array[right]; array[right] = temp; } public static void sortValleyPeak(int[] array) { for (int i = 1; i < array.length; i += 2) { if (array[i - 1] < array[i]) { swap(array, i - 1, i); } if (i + 1 < array.length && array[i + 1] < array[i]) { swap(array, i + 1, i); } } }

Peaks and Valleys: In an array of integers, a "peak" is an element which is greater than or equal to the adjacent integers and a "valley" is an element which is less than or equal to the adjacent integers. For example, in the array {S, 8, 6, 2, 3, 4, 6}, {8, 6} are peaks and {S, 2} are valleys. Given an array of integers, sort the array into an alternating sequence of peaks and valleys. EXAMPLE Input: {S, 3, 1,2, 3} Output: {S, 1,3,2, 3}

public class MyQueue<T> { Stack<T> stackNewest, stackOldest; public MyQueue() { stackNewest = new Stack<T>(); stackOldest = new Stack<T>(); } public int size() { return stackNewest.size() + stackOldest.size(); } public void add(T value) { // Push onto stack1 stackNewest.push(value); } /* Move elements from stackNewest into stackOldest. This is usually done so that we can * do operations on stackOldest. */ private void shiftStacks() { if (stackOldest.isEmpty()) { while (!stackNewest.isEmpty()) { stackOldest.push(stackNewest.pop()); } } } public T peek() { shiftStacks(); return stackOldest.peek(); // retrieve the oldest item. } public T remove() { shiftStacks(); return stackOldest.pop(); // pop the oldest item. } }

Queue via Stacks: Implement a MyQueue class which implements a queue using two stacks.

We can first pull a random set of size m from the first n - 1 elements. Then, we just need to decide if array [n] should be inserted into our subset (which would require pulling out a random element from it). An easy way to do this is to pick a random number k from e through n. lf k < m, then insert array [n] into subset [k] . This will both "fairly" (i.e., with proportional probability) insert array [n] into the subset and "fairly" remove a random element from the subset. /* Random number between lower and higher, inclusive */ public static int rand(int lower, int higher) { return lower + (int)(Math.random() * (higher - lower + 1)); } /* pick M elements from original array.*/ public static int[] pickMIteratively(int[] original, int m) { int[] subset = new int[m]; /* Fill in subset array with first part of original array */ for (int i = 0; i < m ; i++) { subset[i] = original[i]; } /* Go through rest of original array. */ for (int i = m; i < original.length; i++) { int k = rand(0, i); if (k < m) { subset[k] = original[i]; } } return subset; }

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.

public class ParseResult { public int invalid = Integer.MAX_VALUE; public String parsed = ""; public ParseResult(int inv, String p) { invalid = inv; parsed = p; } public ParseResult clone() { return new ParseResult(this.invalid, this.parsed); } public static ParseResult min(ParseResult r1, ParseResult r2) { if (r1 == null) { return r2; } else if (r2 == null) { return r1; } return r2.invalid < r1.invalid ? r2 : r1; } } public static String bestSplit(HashSet<String> dictionary, String sentence) { ParseResult r = split(dictionary, sentence, 0); return r == null ? null : r.parsed; } public static ParseResult split(HashSet<String> dictionary, String sentence, int start) { if (start >= sentence.length()) { return new ParseResult(0, ""); } int bestInvalid = Integer.MAX_VALUE; String bestParsing = null; String partial = ""; int index = start; while (index < sentence.length()) { char c = sentence.charAt(index); partial += c; int invalid = dictionary.contains(partial) ? 0 : partial.length(); if (invalid < bestInvalid) { // Short circuit /* Recurse, putting a space after this character. If this * is better than the current best option, replace the best * option. */ ParseResult result = split(dictionary, sentence, index + 1); if (invalid + result.invalid < bestInvalid) { bestInvalid = invalid + result.invalid; bestParsing = partial + " " + result.parsed; if (bestInvalid == 0) break; } } index++; } return new ParseResult(bestInvalid, bestParsing); }

Re-Space: Oh, no! You have accidentally removed all spaces, punctuation, and capitalization in a lengthy document. A sentence like "I reset the computer. It still didn't boot!" became "iresetthecomputeritstilldidntboot". You'll deal with the punctuation and capitalization later; right now you need to re-insert the spaces. Most of the words are in a dictionary but a few are not. Given a dictionary (a list of strings) and the document (a string), design an algorithm to unconcatenate the document in a way that minimizes the number of unrecognized characters. EXAMPLE Input: jesslookedjustliketimherbrother Output: jess looked just like tim her brother (7 unrecognized characters)

public static void deleteDups(LinkedListNode n) { HashSet<Integer> set = new HashSet<Integer>(); LinkedListNode previous = null; while (n != null) { if (set.contains(n.data)) { previous.next = n.next; } else { set.add(n.data); previous = n; } n = n.next; } } Follow up public static void deleteDups(LinkedListNode head) { LinkedListNode current = head; while (current != null) { /* Remove all future nodes that have the same value */ LinkedListNode runner = current; while (runner.next != null) { if (runner.next.data == current.data) { runner.next = runner.next.next; } else { runner = runner.next; } } current = current.next; } }

Remove Dups: Write code to remove duplicates from an unsorted linked list. FOLLOW UP How would you solve this problem if a temporary buffer is not allowed?

If we picture this grid, the only way to move to spot (r, c) is by moving to one of the adjacent spots: ( r -1, c) or ( r, c -1). So, we need to find a path to either (r - 1, c) or ( r, c - 1) . How do we find a path to those spots?To find a path to (r-1, c) or (r, c -1), we need to move to one of its adjacent cells. So, we need to find a path to a spot adjacent to (r -1, c), which are coordinates (r-2,c) and (r-1,c -1),ora spot adjacent to (r,c-1),which are spots (r - 1,c-1) and (r,c-2) . Observe that we list the point (r -1, c -1) twice; we'll discuss that issue later. // 0 (2r+( ), since each path has r+c steps and there are two choices we can make at each step. public static ArrayList<Point> getPath(boolean[][] maze) { if (maze == null || maze.length == 0) return null; ArrayList<Point> path = new ArrayList<Point>(); if (getPath(maze, maze.length - 1, maze[0].length - 1, path)) { return path; } return null; } public static boolean getPath(boolean[][] maze, int row, int col, ArrayList<Point> path) { // If out of bounds or not available, return. if (col < 0 || row < 0 || !maze[row][col]) { return false; } boolean isAtOrigin = (row == 0) && (col == 0); // If there's a path from the start to my current location, add my location. if (isAtOrigin || getPath(maze, row, col - 1, path) || getPath(maze, row - 1, col, path)) { Point p = new Point(row, col); path.add(p); return true; } return false; } //The algorithm will now take O(XY) time because we hit each cell just once. public static ArrayList<Point> getPath(boolean[][] maze) { if (maze == null || maze.length == 0) return null; ArrayList<Point> path = new ArrayList<Point>(); HashSet<Point> failedPoints = new HashSet<Point>(); if (getPath(maze, maze.length - 1, maze[0].length - 1, path, failedPoints)) { return path; } return null; } public static boolean getPath(boolean[][] maze, int row, int col, ArrayList<Point> path, HashSet<Point> failedPoints) { /* If out of bounds or not available, return.*/ if (col < 0 || row < 0 || !maze[row][col]) { return false; } Point p = new Point(row, col); /* If we've already visited this cell, return. */ if (failedPoints.contains(p)) { return false; } boolean isAtOrigin = (row == 0) && (col == 0); /* If there's a path from the start to my current location, add my location.*/ if (isAtOrigin || getPath(maze, row, col - 1, path, failedPoints) || getPath(maze, row - 1, col, path, failedPoints)) { path.add(p); return true; } failedPoints.add(p); // Cache result return false; }

Robot in a Grid: Imagine a robot sitting on the upper left corner of grid with r rows and c columns. The robot can only move in two directions, right and down, but certain cells are "off limits" such that the robot cannot step on them. Design an algorithm to find a path for the robot from the top left to the bottom right.

This algorithm is O( N2 ), which is the best we can do since any algorithm must touch all N2 elements. public static boolean rotate(int[][] matrix) { if (matrix.length == 0 || matrix.length != matrix[0].length) return false; // Not a square int n = matrix.length; for (int layer = 0; layer < n / 2; layer++) { int first = layer; int last = n - 1 - layer; for(int i = first; i < last; i++) { int offset = i - first; int top = matrix[first][i]; // save top // left -> top matrix[first][i] = matrix[last-offset][first]; // bottom -> left matrix[last-offset][first] = matrix[last][last - offset]; // right -> bottom matrix[last][last - offset] = matrix[i][last]; // top -> right matrix[i][last] = top; // right <- saved top } } return true; }

Rotate Matrix: Given an image represented by an NxN matrix, where each pixel in the image is 4 bytes, write a method to rotate the image by 90 degrees. Can you do this in place?

This problem can be solved by just simple graph traversal, such as depth-first search or breadth-first search. We start with one of the two nodes and, during traversal, check if the other node is found. We should mark any node found in the course of the algorithm as "already visited" to avoid cycles and repetition of the nodes.

Route Between Nodes: Given a directed graph, design an algorithm to find out whether there is a route between two nodes.

adsfsadf

Shortest Supersequence: You are given two arrays, one shorter (with all distinct elements) and one longer. Find the shortest subarray in the longer array that contains all the elements in the shorter array. The items can appear in any order. EXAMPLE Input: {1, 5, 9} {7, 5, 9, 8, 2, 1, 3, 5, 7, 9, 1, 1, 5, 8, 8, 9, 7} Output: [7, 10] (the underlined portion above)

/* Random number between lower and higher, inclusive */ public static int rand(int lower, int higher) { return lower + (int)(Math.random() * (higher - lower + 1)); } public static void shuffleArrayIteratively(int[] cards) { for (int i = 0; i < cards.length; i++) { int k = rand(0, i); int temp = cards[k]; cards[k] = cards[i]; cards[i] = temp; } }

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. pg

public static int findSmallestDifference(int[] array1, int[] array2) { Arrays.sort(array1); Arrays.sort(array2); int a = 0; int b = 0; int difference = Integer.MAX_VALUE; while (a < array1.length && b < array2.length) { if (Math.abs(array1[a] - array2[b]) < difference) { difference = Math.abs(array1[a] - array2[b]); if (difference == 0) return difference; } if (array1[a] < array2[b]) { a++; } else { b++; } } return difference; }

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. EXAMPLE Input{1,3,15,11,2h{2~12~235,1~8} Output 3. That is, the pair (11, 8).

public static class MaxHeapComparator implements Comparator<Integer> { public int compare(Integer x, Integer y) { return y - x; } } public static int[] smallestK(int[] array, int k) { if (k <= 0 || k > array.length) { throw new IllegalArgumentException(); } PriorityQueue<Integer> heap = getKMaxHeap(array, k); return heapToIntArray(heap); } /* Convert heap to int array. */ public static int[] heapToIntArray(PriorityQueue<Integer> heap) { int[] array = new int[heap.size()]; while (!heap.isEmpty()) { array[heap.size() - 1] = heap.poll(); } return array; } /* Create max heap of smallest k elements. */ public static PriorityQueue<Integer> getKMaxHeap(int[] array, int k) { PriorityQueue<Integer> heap = new PriorityQueue<Integer>(k, new MaxHeapComparator()); for (int a : array) { if (heap.size() < k) { // If space remaining heap.add(a); } else if (a < heap.peek()) { // If full and top is small heap.poll(); // remove highest heap.add(a); // insert new element } } return heap; }

Smallest K: Design an algorithm to find the smallest K numbers in an array.

When an interviewer gives a size limit of 20 gigabytes, it should tell you something. In this case, it suggests that they don't want you to bring all the data into memory. So what do we do? We only bring part of the data into memory. We'll divide the file into chunks, which are x megabytes each, where x is the amount of memory we have available. Each chunk is sorted separately and then saved back to the file system. Once all the chunks are sorted, we merge the chunks, one by one. At the end, we have a fully sorted file. This algorithm is known as external sort.

Sort Big File: Imagine you have a 20 GB file with one string per line. Explain how you would sort the file.

public static void sort(Stack<Integer> s) { Stack<Integer> r = new Stack<Integer>(); while(!s.isEmpty()) { /* Insert each element in s in sorted order into r. */ int tmp = s.pop(); while(!r.isEmpty() && r.peek() > tmp) { s.push(r.pop()); } r.push(tmp); } /* Copy the elements back. */ while (!r.isEmpty()) { s.push(r.pop()); } }

Sort Stack: Write a program to sort a stack such that the smallest items are on the top. You can use an additional temporary stack, but you may not copy the elements into any other data structure (such as an array). The stack supports the following operations: push, pop, peek, and isEmpty.

public class Coordinate implements Cloneable { public int row; public int column; public Coordinate(int r, int c) { row = r; column = c; } public boolean inbounds(int[][] matrix) { return row >= 0 && column >= 0 && row < matrix.length && column < matrix[0].length; } public boolean isBefore(Coordinate p) { return row <= p.row && column <= p.column; } public Object clone() { return new Coordinate(row, column); } public void moveDownRight() { row++; column++; } public void setToAverage(Coordinate min, Coordinate max) { row = (min.row + max.row) / 2; column = (min.column + max.column) / 2; } } public static Coordinate partitionAndSearch(int[][] matrix, Coordinate origin, Coordinate dest, Coordinate pivot, int x) { Coordinate lowerLeftOrigin = new Coordinate(pivot.row, origin.column); Coordinate lowerLeftDest = new Coordinate(dest.row, pivot.column - 1); Coordinate upperRightOrigin = new Coordinate(origin.row, pivot.column); Coordinate upperRightDest = new Coordinate(pivot.row - 1, dest.column); Coordinate lowerLeft = findElement(matrix, lowerLeftOrigin, lowerLeftDest, x); if (lowerLeft == null) { return findElement(matrix, upperRightOrigin, upperRightDest, x); } return lowerLeft; } public static Coordinate findElement(int[][] matrix, Coordinate origin, Coordinate dest, int x) { if (!origin.inbounds(matrix) || !dest.inbounds(matrix)) { return null; } if (matrix[origin.row][origin.column] == x) { return origin; } else if (!origin.isBefore(dest)) { return null; } /* Set start to start of diagonal and end to the end of the diagonal. Since * the grid may not be square, the end of the diagonal may not equal dest. */ Coordinate start = (Coordinate) origin.clone(); int diagDist = Math.min(dest.row - origin.row, dest.column - origin.column); Coordinate end = new Coordinate(start.row + diagDist, start.column + diagDist); Coordinate p = new Coordinate(0, 0); /* Do binary search on the diagonal, looking for the first element greater than x */ while (start.isBefore(end)) { p.setToAverage(start, end); if (x > matrix[p.row][p.column]) { start.row = p.row + 1; start.column = p.column + 1; } else { end.row = p.row - 1; end.column = p.column - 1; } } /* Split the grid into quadrants. Search the bottom left and the top right. */ return partitionAndSearch(matrix, origin, dest, start, x); } public static Coordinate findElement(int[][] matrix, int x) { Coordinate origin = new Coordinate(0, 0); Coordinate dest = new Coordinate(matrix.length - 1, matrix[0].length - 1); return findElement(matrix, origin, dest, x); }

Sorted Matrix Search: Given an M x N matrix in which each row and each column is sorted in ascending order, write a method to find an element.

public static void merge(int[] a, int[] b, int lastA, int lastB) { int indexMerged = lastB + lastA - 1; /* Index of last location of merged array */ int indexA = lastA - 1; /* Index of last element in array b */ int indexB = lastB - 1; /* Index of last element in array a */ /* Merge a and b, starting from the last element in each */ while (indexB >= 0) { if (indexA >= 0 && a[indexA] > b[indexB]) { /* end of a is bigger than end of b */ a[indexMerged] = a[indexA]; // copy element indexA--; } else { a[indexMerged] = b[indexB]; // copy element indexB--; } indexMerged--; // move indices } }

Sorted Merge: You are given two sorted arrays, A and B, where A has a large enough buffer at the end to hold B. Write a method to merge B into A in sorted order.

Are numbers sorted? public static int search(Listy list, int value) { int index = 1; while (list.elementAt(index) != -1 && list.elementAt(index) < value) { index *= 2; } return binarySearch(list, value, index / 2, index); } public static int binarySearch(Listy list, int value, int low, int high) { int mid; while (low <= high) { mid = (low + high) / 2; int middle = list.elementAt(mid); if (middle > value || middle == -1) { high = mid - 1; } else if (middle < value) { low = mid + 1; } else { return mid; } } return -1; } // find size = O(log n), search O(log n), total O(log n)

Sorted Search, No Size: You are given an array-like data structure Listy which lacks a size method. It does, however, have an e lementAt (i) method that returns the element at index i in 0(1) time. If i is beyond the bounds of the data structure, it returns - 1. (For this reason, the data structure only supports positive integers.) Given a Listy which contains sorted, positive integers, find the index at which an element x occurs. If x occurs multiple times, you may return any index.

With empty strings interspersed, we can implement a simple modification of binary search. All we need to do is fix the comparison against mid, in case mid is an empty string. We simply move mid to the closest non-empty string. The worst-case runtime for this algorithm is 0 (n). In fact, it's impossible to have an algorithm for this problem that is better than O(n) in the worst case. After all, you could have an array of all empty strings except for one non-empty string. There is no "smart" way to find this non-empty string. In the worst case, you will need to look at every element in the array. public static int search(String[] strings, String str, int first, int last) { if (first > last) { return -1; } /* Move mid to the middle */ int mid = (last + first) / 2; /* If mid is empty, find closest non-empty string. */ if (strings[mid].isEmpty()) { int left = mid - 1; int right = mid + 1; while (true) { if (left < first && right > last) { return -1; } else if (right <= last && !strings[right].isEmpty()) { mid = right; break; } else if (left >= first && !strings[left].isEmpty()) { mid = left; break; } right++; left--; } } /* Check for string, and recurse if necessary */ if (str.equals(strings[mid])) { // Found it! return mid; } else if (strings[mid].compareTo(str) < 0) { // Search right return search(strings, str, mid + 1, last); } else { // Search left return search(strings, str, first, mid - 1); } } public static int search(String[] strings, String str) { if (strings == null || str == null || str.isEmpty()) { return -1; } return search(strings, str, 0, strings.length - 1); }

Sparse Search: Given a sorted array of strings that is interspersed with empty strings, write a method to find the location of a given string. EXAMPLE Input: ball, {"at", "", "", "", "ball", "", "", "car", "", "", "dad", "", ""} Output: 4

public class StackWithMin extends Stack<NodeWithMin> { public void push(int value) { int newMin = Math.min(value, min()); super.push(new NodeWithMin(value, newMin)); } public int min() { if (this.isEmpty()) { return Integer.MAX_VALUE; } else { return peek().min; } } }

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 0(1) time.

public class SetOfStacks { ArrayList<Stack> stacks = new ArrayList<Stack>(); public int capacity; public SetOfStacks(int capacity) { this.capacity = capacity; } public Stack getLastStack() { if (stacks.size() == 0) { return null; } return stacks.get(stacks.size() - 1); } public void push(int v) { Stack last = getLastStack(); if (last != null && !last.isFull()) { // add to last last.push(v); } else { // must create new stack Stack stack = new Stack(capacity); stack.push(v); stacks.add(stack); } } public int pop() { Stack last = getLastStack(); if (last == null) throw new EmptyStackException(); int v = last.pop(); if (last.size == 0) { stacks.remove(stacks.size() - 1); } return v; } public int popAt(int index) { return leftShift(index, true); } public int leftShift(int index, boolean removeTop) { Stack stack = stacks.get(index); int removed_item; if (removeTop) removed_item = stack.pop(); else removed_item = stack.removeBottom(); if (stack.isEmpty()) { stacks.remove(index); } else if (stacks.size() > index + 1) { int v = leftShift(index + 1, false); stack.push(v); } return removed_item; } public boolean isEmpty() { Stack last = getLastStack(); return last == null || last.isEmpty(); } }

Stack of Plates: Imagine a (literal) stack of plates. If the stack gets too high, it might topple. Therefore, in real life, we would likely start a new stack when the previous stack exceeds some threshold. Implement a data structure SetOfStacks that mimics this. SetOfStacks should be composed of several stacks and should create a new stack once the previous one exceeds capacity. SetOfStacks. push () and SetOfStacks. pop() should behave identically to a single stack (that is, pop ( ) should return the same values as it would if there were just a single stack). FOLLOW UP Implement a function popAt (int index) which performs a pop operation on a specific substack.

public static String compress(String str) { StringBuilder compressed = new StringBuilder(); int countConsecutive = 0; for (int i = 0; i < str.length(); i++) { countConsecutive++; /* If next character is different than current, append this char to result.*/ if (i + 1 >= str.length() || str.charAt(i) != str.charAt(i + 1)) { compressed.append(str.charAt(i)); compressed.append(countConsecutive); countConsecutive = 0; } } return compressed.length() < str.length() ? compressed.toString() : str; }

String Compression: Implement a method to perform basic string compression using the counts of repeated characters. For example, the string aabcccccaaa would become a2blc5a3. 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 uppercase and lowercase letters (a - z).

public static boolean isRotation(String s1, String s2) { int len = s1.length(); /* check that s1 and s2 are equal length and not empty */ if (len == s2.length() && len > 0) { /* concatenate s1 and s1 within new buffer */ String s1s1 = s1 + s1; return isSubstring(s1s1, s2); } return false; }

String Rotation: Assume you have a method isSubstring which checks if one word is a substring of another. Given two strings, s1 and s2, write code to check if s2 is a rotation of s1 using only one call to isSubstring (e.g., "waterbottle" is a rotation of "erbottlewat" ).

public static TreeNode inorderSucc(TreeNode n) { if (n == null) return null; // Found right children -> return left most node of right subtree if (n.parent == null || n.right != null) { return leftMostChild(n.right); } else { TreeNode q = n; TreeNode x = q.parent; // Go up until we're on left instead of right while (x != null && x.left != q) { q = x; x = x.parent; } return x; } } public static TreeNode leftMostChild(TreeNode n) { if (n == null) { return null; } while (n.left != null) { n = n.left; } return n; }

Successor: Write an algorithm to find the "next" node (i.e., in-order successor) of a given node in a binary search tree. You may assume that each node has a link to its parent.

// recursion - O(2^n) public static int maxMinutes(int[] massages) { return maxMinutes(massages, 0); } public static int maxMinutes(int[] massages, int index) { if (index >= massages.length) { // Out of bounds return 0; } /* Best with this reservation. */ int bestWith = massages[index] + maxMinutes(massages, index + 2); /* Best without this reservation. */ int bestWithout = maxMinutes(massages, index + 1); /* Return best of this subarray, starting from index. */ return Math.max(bestWith, bestWithout); } // recursion + memoization public static int maxMinutes(int[] massages) { int[] memo = new int[massages.length]; return maxMinutes(massages, 0, memo); } public static int maxMinutes(int[] massages, int index, int[] memo) { if (index >= massages.length) { return 0; } if (memo[index] == 0) { int bestWith = massages[index] + maxMinutes(massages, index + 2, memo); int bestWithout = maxMinutes(massages, index + 1, memo); memo[index] = Math.max(bestWith, bestWithout); } return memo[index]; }

The Masseuse: A popular masseuse receives a sequence of back-to-back appointment requests and is debating which ones to accept. She needs a 15-minute break between appointments and therefore she cannot accept any adjacent requests. Given a sequence of back-to-back appointment requests (all multiples of 15 minutes, none overlap, and none can be moved), find the optimal (highest total booked minutes) set the masseuse can honor. Return the number of minutes. EXAMPLE Input: {3e, 15, 6e, 75, 45, 15, 15, 45} Output: 18e minutes ({30, 6e, 45, 45}).

moveDisks(int n, Tower origin, Tower destination, Tower buffer) { /* Base case */ if (n <= 0) return; /* move top n - 1 disks from orIgIn to buffer, using destination as a buffer. */ moveDisks(n - 1, origin, buffer, destination); /* move top from origin to destination moveTop(origin, destination); / * move top n - 1 disks from buffer to destination, us i ng origin as a buffer. */ moveDisks(n - 1, buffer, destination, origin); }

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 (Le., 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.

// recursion public static int countWays(int n) { if (n < 0) { return 0; } else if (n == 0) { return 1; } else { return countWays(n - 1) + countWays(n - 2) + countWays(n - 3); } } // DP public static int countWays(int n) { int[] map = new int[n + 1]; Arrays.fill(map, -1); return countWays(n, map); } public static int countWays(int n, int[] memo) { if (n < 0) { return 0; } else if (n == 0) { return 1; } else if (memo[n] > -1) { return memo[n]; } else { memo[n] = countWays(n - 1, memo) + countWays(n - 2, memo) + countWays(n - 3, memo); return memo[n]; } }

Triple Step: A child is running up a staircase with n steps and can hop either 1 step, 2 steps, or 3 steps at a time. Implement a method to count how many possible ways the child can run up the stairs.

public static HashMapList<String, Integer> getWordLocations(String[] words) { HashMapList<String, Integer> locations = new HashMapList<String, Integer>(); for (int i = 0; i < words.length; i++) { locations.put(words[i], i); } return locations; } public static LocationPair findMinDistancePair(ArrayList<Integer> array1, ArrayList<Integer> array2) { if (array1 == null || array2 == null || array1.size() == 0 || array2.size() == 0) { return null; } int index1 = 0; int index2 = 0; LocationPair best = new LocationPair(array1.get(0), array2.get(0)); LocationPair current = new LocationPair(array1.get(0), array2.get(0)); while (index1 < array1.size() && index2 < array2.size()) { current.setLocations(array1.get(index1), array2.get(index2)); best.updateWithMin(current); if (current.location1 < current.location2) { index1++; } else { index2++; } } return best; } public static LocationPair findClosest(String word1, String word2, HashMapList<String, Integer> locations) { ArrayList<Integer> locations1 = locations.get(word1); ArrayList<Integer> locations2 = locations.get(word2); return findMinDistancePair(locations1, locations2); }

Word Distance: You have a large text file containing words. Given any two words, find the shortest distance (in terms of number of words) between them in the file. If the operation will be repeated many times for the same file (but different pairs of words), can you optimize your solution?

public static HashMap<String, Integer> setupDictionary(String[] book) { HashMap<String, Integer> table = new HashMap<String, Integer>(); for (String word : book) { word = word.toLowerCase(); if (word.trim() != "") { if (!table.containsKey(word)) { table.put(word, 0); } table.put(word, table.get(word) + 1); } } return table; } public static int getFrequency(HashMap<String, Integer> table, String word) { if (table == null || word == null) { return -1; } word = word.toLowerCase(); if (table.containsKey(word)) { return table.get(word); } return 0; }

Word Frequencies: Design a method to find the frequency of occurrences of any given word in a book. What if we were running this algorithm mUltiple times?

One way around this is to keep a second matrix which flags the zero locations. We would then do a second pass through the matrix to set the zeros. This would ta ke 0 (MN) space.

Zero Matrix: Write an algorithm such that if an element in an MxN matrix is 0, its entire row and column are set to 0.


Conjuntos de estudio relacionados

Unit 3: What are the benefits of physical activity?

View Set

BUS1B Managerial Accounting Chapter 3

View Set

Chapter 02: Developmental Tasks and Health Promotion Across the Life Cycle

View Set

ET2560 Introduction to C Programming Chapter 3

View Set

S1 AP Lang Final : Choosing the Right Word

View Set