Node / Angular / Java


Section A: General Coding (Algorithms)

Solve in the language of your choice (practice in both JS and Java if you can).

A1. Given an array of integers, return the two indices whose values sum to a target. Assume exactly one solution exists.

Input: nums = [2, 7, 11, 15], target = 9
Output: [0, 1]

public int[] twoSum(int[] nums, int target) {
		
		Map<Integer, Integer> seen = new HashMap<>();         // build hashmap storing value -> index
		
		for(int i=0; i < nums.length; i++){
				int complement = target - nums[i];
				
				if (seen.containsKey(complement)) {               // check if index target-nums[i] exists
						return new int[] { seen.get(complement), i };
				}
				seen.put(nums[i], i);
		}
		
		throw new IllegalArgumentException("No solution found");   // error
}

A2. Given a string, determine if it's a valid palindrome, ignoring non-alphanumeric characters and case.

Input: "A man, a plan, a canal: Panama"
Output: true

public boolean isPalindrome(String str) {
		int left = 0;     // two pointer from both ends
		int right = s.length() - 1;
		
		while (left < right){
				while (left < right && !Character.isLetterOrDigit(s.charAt(left))) left++;  // skip non-alphanumeric chars
        while (left < right && !Character.isLetterOrDigit(s.charAt(right))) right--;
        
        if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {  // compare lowercase values
            return false;
        }
        
        left++;
        right--;
        
		}
		return true;
}

A3. Given a string of parentheses ()[]{}, determine if the brackets are balanced.

Input: "([{}])"
Output: true
Input: "([)]"
Output: false

public boolean isValid(String s) {
    Deque<Character> stack = new ArrayDeque<>();   // build stack
    Map<Character, Character> pairs = Map.of(')', '(', ']', '[', '}', '{'); //build map close -> open bracket
    
    for (char c : s.toCharArray()) {

        if (pairs.containsKey(c)) {    // pop and match on closing bracket
            if (stack.isEmpty() || stack.pop() != pairs.get(c)) {
                return false;
            }
        } else {
            stack.push(c);
        }
    }
    
    return stack.isEmpty();  // all characters fit a valid pair
}

A4. Given an array, find the length of the longest subarray with no repeating elements (sliding window).

Input: [2, 1, 5, 1, 3, 2]
Output: 3   (e.g. [5,1,3])

// Sliding window with a Set or index map tracking last-seen position of each element; 
// shrink window from the left when a duplicate is found
public int longestUniqueSubarray(int[] nums) {
    Map<Integer, Integer> lastSeen = new HashMap<>();  // map element -> last seen
    int maxLen = 0, left = 0;       // sliding window
    
    for (int right = 0; right < nums.length; right++) {
        
        if (lastSeen.containsKey(nums[right]) && lastSeen.get(nums[right]) >= left) {
            left = lastSeen.get(nums[right]) + 1;
        }
        
        lastSeen.put(nums[right], right);
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

A5. Given a binary tree, return the maximum depth.

class TreeNode {
    int val;
    TreeNode left, right;
    TreeNode(int val) { this.val = val; }
}

// Recursive: 1 + max(depth(left), depth(right)), base case null returns 0
public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
}

Section B: Node.js

B1. Explain the difference between process.nextTick(), setImmediate(), and setTimeout(fn, 0). What order do they run in?

console.log('start');

setTimeout(() => console.log('setTimeout'), 0);
setImmediate(() => console.log('setImmediate'));
process.nextTick(() => console.log('nextTick'));

console.log('end');

// Output:
// start
// end
// nextTick        <- runs before the event loop continues
// setTimeout       <- order vs setImmediate isn't guaranteed here
// setImmediate

B2. Write a small piece of Express middleware that logs the request method and URL, then calls next().

app.use((req, res, next) => { console.log(req.method, req.url); next(); });

const express = require('express');
const app = express();

function logger(req, res, next) {
  console.log(`${req.method} ${req.url}`);
  next();
}

app.use(logger);

app.get('/', (req, res) => res.send('Hello'));
app.listen(3000);