UNPKG

ds-algo-study

Version:

Just experimenting with publishing a package

299 lines (259 loc) 11.3 kB
// PROBLEM 1 - Two Sum // https://leetcode.com/problems/two-sum/ // ============================================================================ // Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target. // You may assume that each input would have exactly one solution, and you may not use the same element twice. // You can return the answer in any order. // Example 1: // Input: nums = [2,7,11,15], target = 9 // Output: [0,1] // Output: Because nums[0] + nums[1] == 9, we return [0, 1]. // Example 2: // Input: nums = [3,2,4], target = 6 // Output: [1,2] // Example 3: // Input: nums = [3,3], target = 6 // Output: [0,1] // Constraints: // 2 <= nums.length <= 105 // -109 <= nums[i] <= 109 // -109 <= target <= 109 // Only one valid answer exists. // Time: O(n) // // We are only passing through the input array one time at most const twoSum = function(nums, target) { const map = {}; for (let i = 0; i < nums.length; i++) { // The complement is the value that would add up with this element to our target const complement = target - nums[i]; // If we already encountered our complement, return the index of that value // and this one, ie the pair that sums to the target. if (map[complement] !== undefined) { return [ map[complement], i ]; } // If we didn't already encounter the complement, add our value and index to // the hash. This will allow us to find the pair if we encounter it later on map[nums[i]] = i; } // If we made it all the way through the for loop, the function returns undefined }; // PROBLEM 2 - Reverse a linked list // ============================================================================ // Amazon and Microsoft ask you to show an algorithm that will reverse a singly-linked // list, that is, a list that is made of nodes between which there is a unidirectional // association as in the following image. function reverseList(list) { // A list of length <= 1 is the same reversed if (list.length <= 1) return list; // Our currentNode starts off at the head. As we iterate we want to reverse the // order, so the node that is next in the original order will have to be swapped. // We'll do that by assigning that nextNode's `next` to be our currentNode. let currentNode = list.head; let nextNode = currentNode.next; // We reverse our pointers for our `tail` and `head` properties. list.head = list.tail; list.tail = currentNode; // Since our currentNode is now the tail, its `next` should be null. currentNode.next = null; // We loop until we no longer have a nextNode. This will happen after assigning // our original tail node to point to what was originally before it in the list. // When we reassign our nextNode at the end of the loop to tempNode, it will be // null, exiting out of our loop. while (nextNode) { let tempNode = nextNode.next; nextNode.next = currentNode; currentNode = nextNode; nextNode = tempNode; } // After our loop, all of our `next` pointers have been reversed. Our `head` and // `tail` properties have already been reassigned and our new tail's `next` already // points to null. We're ready to return the list, which has been reversed. return list; } // Our function runs in O(n) time, since we only have to iterate through the list once. // We also take up O(1) space. We only create three new letiables no matter the // size of the list and do all of our reversing in place. // PROBLEM 3 - The missing value // ============================================================================ // Amazon and Microsoft ask you to derive an algorithm that will inspect an // array of of numbers that contains the values between 0 and the length of the // list, inclusive, and find the missing value. For example, you may be given an // array that of length 6 that contains // [0, 2, 3, 4, 5, 6] // It is your job to determine that the missing value from the array is 1. // O(n) function findNum(arr) { let hash = {}; // Loop through our input array and create a mapping of the value to true // This will cost us n iterations up front, but allow us to access the numbers // in constant time for future lookup. // O(n) for (let i = 0; i < arr.length; i++) { hash[arr[i]] = true; } let j = 0; // Increment from 0 to arr.length, which is all of the potential values that we // would expect in our array. // When we get to a value that was not found in our first loop, we return that // missing number. // O(n) while (j < arr.length) { if (!hash[j]) { return j; } j++; } // If we made it beyond the while loop, we found all numbers 0 to length - 1, // meaning we are missing the last value of arr.length // (This also could have been accomplished by looping up to and including the // length instead of being exclusive in the conditional.) return arr.length; } // PROBLEM 4 - Stack min // ============================================================================ // Google and Apple ask you to design a stack that, in addition to the push and // pop functions, has a function min that returns the minimum element in the stack // without removing it. All three functions push, pop, and min should operate in // O(1) time. class minStack { // We keep track of a separate array that will only get elements added to it if // they represent a new minimum value (or tie for the current value) constructor() { this.elements = []; this.mins = []; } push(val) { this.elements.push(val); const curMin = this.mins[this.mins.length - 1]; // If we don't have a minimum yet (first element pushed), or if this value is // a new minimum (or equal value), we also push it into the mins array. if (this.mins.length === 0 || val <= curMin) { this.mins.push(val); } } pop() { const popped = this.elements.pop(); const curMin = this.mins[this.mins.length - 1]; // If the element we just removed was also the current minimum, we remove it // from our mins array. The element at the end of our mins array will always // represent our current minimum. if (popped === curMin) this.mins.pop(); return popped; } min() { // Since the element at the end of mins is always our minimum, we can key // directly in to see that value no matter where it is in the stack. return this.mins[this.mins.length - 1]; } } // PROBLEM 5 - Test a retractable ballpoint pen // ============================================================================ // Facebook asks you to write the tests cases for testing a ballpoint pen. // What would you consider to be good tests for the pen? // Try to be as exhaustive as possible. // Basic Functionality // The pen has a clicking/retracting functionality // Clicking the pen from a retracted position extends the pen // Clicking the pen from an extended position retracts the pen // You are able to write from an extended position // You are not able to write from a retracted position // Additional Desired Functionality // Writing large amounts results in smooth lettering (no missing letters, lines, etc.) // Ink does not fade while writing (coloring is consisitent, compare beginning to end) // Ink does not smudge (test interacting with lettering and compare after interaction) // Ink is waterproof // The pen can write on desired surfaces (glossy, smooth, rough, etc.) // The pen lasts for at least X pages (test a new pen and make sure output is possible for X pages) // etc. // PROBLEM 6 - OOParking Lot // ============================================================================ // Amazon and Microsoft ask you to specify the classes that it would take to write // software to manage a paid parking lot. It should know where cars are parked, // be able to identify the cars, know where the keys are hanging, how many cars // are in the lot, what time the cars come and go, and how much it costs someone // when they leave the parking lot based on the following schedule: // Time -> Rate per hour // 8pm - 6am $3 // 6am - noon $10 // noon - 6pm $8 // 6pm - 8pm $6 // This is mostly pseudocode // The important aspects are being able to define the roles that you have // Possible changes: // // Using a Car class instead of a plain object to fill spaces // // Account for minimum charges or a max daily rate when calculating fees class ParkingLot { constructor(numSpaces) { // track the spaces in the lot // track the number of vacancies this.spaces = new Array(numSpaces).fill(null); this.vacancies = numSpaces; this.nextAvailableSpace = 0; } fillSpot(plateNumber, keyLocation) { // return false if !this.spotAvailable() // decrement vacancies // Add in to this.spaces[this.nextAvailableSpace] { entryTime: Date.now(), plateNumber, keyLocation } // check this.spaces at this.nextAvailableSpace+1, incrementing until a vacancy is found. Reassign this.nextAvailableSpace } spotAvailable() { // return if vacancies > 0 } calculateFee(spaceNumber) { // Get vehicle info with this.spaces[spaceNumber] // Take time of entry (vehicle.entryTime) and time of exit (Date.now()) on object // calculate based on time in each fee window const { entryTime } = this.spaces[spaceNumber]; const exitTime = Date.now(); let totalFee = 0; if (entryTime.getHours() < 6) { const hours = 6 - entryTime.getHours() - 1; const fraction = (60 - getMinutes()) / 60; // add fraction of hour totalFee += (hours + fraction) * 3; // multiply by rate } // etc. } removeVehicle(spaceNumber) { // calculateFee // increment vacancies // reassign this.spaces[spaceNumber] = null } inspectSpace(spaceNumber) { // return the vehicle at this.spaces[spaceNumber]; } findByPlate(plateNumber) { // iterate over this.spaces // if a vehicle exists, compare the plateNumber argument to the object // if it is a match, return the spaceNumber (index of this.spaces where match exists) } } // PROBLEM 7 - Valid Parentheses // https://leetcode.com/problems/valid-parentheses/ // ============================================================================ // Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', // determine if the input string is valid. // An input string is valid if: // Open brackets must be closed by the same type of brackets. // Open brackets must be closed in the correct order. const isValid = function(s) { const stack = []; const openings = { '(': ')', '{': '}', '[': ']' }; const closings = { ')': '(', '}': '{', ']': '[' }; for (let i = 0; i < s.length; i++) { // If the character is an opening, we push it on to the stack if (openings[s[i]]) { stack.push(s[i]); // If it is a closing, it has to match the top opening on the stack // If it does, pop the opening off of the stack } else if (closings[s[i]] === stack[stack.length - 1]) { stack.pop(); // The only way we get to the else is if it is a closing that does not match // In this case, we return false immediately } else { return false; } } // If we made it out of the for loop without invalid closings, we just have to // make sure all of our openings were closed. // This occurs when our stack is empty, indicating no unmatched characters. return stack.length === 0; };