Skip to content

Instantly share code, notes, and snippets.

@anggakharisma
Created August 14, 2023 04:57
Show Gist options
  • Save anggakharisma/495876cdaf7d7129a9ba0ad02dee6628 to your computer and use it in GitHub Desktop.
Save anggakharisma/495876cdaf7d7129a9ba0ad02dee6628 to your computer and use it in GitHub Desktop.

practicing code challenge and improve typescript skill [[Leetcode/Resources|Resources]]

Grind 75

Method

  • Classic Brute force: loop through number of array and then loop through again check if first value + second value = target value, return the current index and the compared index. time complexity would be: $O(n^2)$

  • One Pass: Using hash map or in this case Object in typescript. loop through the array once, calculate the difference with target - current value, if the difference already in the hash table return that hash map value which is the nums index and the current index otherwise put it inside the hash map. time complexity would be: $O(n)$

function twoSum(nums: number[], target: number): number[] {
	let numHash = {};
	
	for(let i = 0; i < nums.length; i++) {
		let diff = target - nums[i];
	
		if (diff in numHash) {
			return [numHash[diff], i]
		}

		numHash[nums[i]] = i;
	}
	return [];
};

Method

  • Use stack. push item to stack if its open brackets. check if the corresponding open bracket is on the stack if its not return false, if it is pop the open bracket from the stack. If the stack is empty that means we already checked all the parentheses pair. if the stack is not empty that means cant find the pair. Use hash-map to find matching parentheses

$$O(n)$$

function isValid(s: string): boolean {
    const pStack = [];
    if(s.length % 2 !== 0) return false;
    for (let c of s) {
       if (c === "(" || c === "{" || c === "[") {
           pStack.push(c);
       } else {
           if(!pStack.length ||
               (c === ")" && pStack[pStack.length - 1] !== "(") ||
               (c === "}" && pStack[pStack.length - 1] !== "{") ||
               (c === "]" && pStack[pStack.length - 1] !== "[")
           ) return false
           pStack.pop();
       }
    }

    return !pStack.length;
}

more compact version, use hash-map to map the pair $$O(n)$$

function isValid(s: string): boolean {
    let pStack = [];
    const pair = {")": "(", "}": "{", "]": "["};
    if(s.length % 2 !== 0) return false;
    for (let c of s) {
        if(pair[c] !== undefined) {
            if(pStack.length && (pStack[pStack.length - 1] === pair[c])) {
                pStack.pop();
            }
            else return false
        } else pStack.push(c);
    }

    return !pStack.length;
}

Time complexity is : $O(n)$

Method

const head = new ListNode();
let curr = head;

while(list1 && list2) {
	if (list1.val < list2.val) {
		curr.next = list1;
		list1 = list1.next;	
	} else {
		curr.next = list2;
		list2 = list1.next;
	}
	curr = curr.next
}

curr.next = list1 || list2;
return head.next;

Explanation

Time complexity is : $O(n)$

function maxProfit(prices: number[]): number {
	// buy low sell high
    let left = 0; // buy
    let right = 1; // sell
    let maxProfit = 0;

    while (right < prices.length) {
        if (prices[left] < prices[right]) {
            let currentProfit = prices[right] - prices[left];
            maxProfit = Math.max(currentProfit, maxProfit);

			// or this
			// if (profit > maxProfit) maxProfit = profit;
        } else left = right

        right++;
    }

    return maxProfit;
};

Method:

  • convert string to lowercase alphanumeric then compare the converted with the reverse of converted $O(n)$

  • use two pointer

javascript doesn't have isAlphanumeric function 💀

function isAplhanumeric(code: number) {
	// ASCII https://www.ascii-code.com/characters/printable-characters#:~:text=ASCII%20printable%20characters%20are%20the,text%20and%20other%20visual%20content.
	// digits: 48 - 57
	// lowercase letters: 97 - 122
	return ((code >= 48 && code <= 57) || (code >= 97 && code <= 122));
}
function isPalindrome(s: string): boolean {
	let left = 0;
	let right = s.length - 1;
	s = s.toLowerCase();
	while(left < right) {
		let leftCode = s.charCodeAt(left);
		let rightCode = s.charCodeAt(right);

		while (!isAlphanumeric(leftCode)) {
			left++;
			if (left === right) return true;
			leftCode = s.charCodeAt(left);
		}

		while (!isAlphanumeric(rightCode)) {
			right--;
			if (left === right) return true;
			rightCode = s.charCodeAt(right);
		}

		if (lCode !== rCode) return false;

		left++;
		righ--;
	}
	return true;
}

Method:

  • Recursion
	function invertTree(root: TreeNode | null): TreeNode | null {
		if (root === null) return root

		invertTree(root.left);
		invertTree(root.right);

		const temp = root.left;
		root.left = root.right;
		root.right = temp;

		return root;
	}
function isAnagram(s: string, t: string): boolean {
	const map = {}
	if (s.length !== t.length) return false;

	for (let i = 0; i < s.length; i++) {
		map[s[i]] = (map[s[i]] ?? 0) + 1;
	}

	for (let i = 0; i < t.length; i++) {
		if (map[t]) map[t]--;
		else return false
	}
	return true
};

have two pointer at start and end. loop while start is less than or equal to end in other words not overlapping. check for mid point of the array with left + right / 2 (note; there's some stack overflow problem in some language). then if mid value is target return the mid because mid is the mid index between start and end. if the mid value is less than target move the start pointer to the right of mid otherwise (mid value is greater than target) move the end to the left of mid. the default is return -1;

function search(nums: number[], target: number): number {
	let start = 0;
	let end = nums.length - 1;

	while (start <= end) {
		const mid = ((left + right) / 2);
		if (nums[mid] === target) return mid
		else if(nums[mid] < target) start = mid + 1
		else end = mid - 1;
	}

	return -1;
}
  • return the image if the current coordinate grid is already the new colour.
  • fill function to fill the top, left, right, bottom recursively. this function is basically dfs, keep filling in one direction until no more
  • base case for fill function check for boundary top left right bottom and the current grid not equal to colour (because can only fill with the same colour)
  • then just call fill function recursively for top, left, bottom, right
function floodFill(image: number[][], sr: number, sc: number, color: number): number[][] {
	if (image[sr][sc] === color) return image;
	fill(image, sr, sc, image[sr][sc], color);
	return image;
}

function floodFill(image: number[][], sr: number, sc: number, color: number, newColor: number): number[][] {
	if (sr < 0 || sr >= image.length || sc < 0 || sc >= image[0].length || image[sr][sc] !== color) return

	image[sr][sc] = newColor;

	fill(image, sr + 1, sc, color, newColor);	
	fill(image, sr - 1, sc, color, newColor);	
	fill(image, sr, sc + 1, color, newColor);	
	fill(image, sr, sc - 1, color, newColor);	
}
function lowestCommonAcnestor(root: Treenode | null, p: Treenode | null, q: TreeNode | null) TreeNode | null {
	while (root) {
		if (p.val > root.val && q.val > root.val)
			root = root.right;
		else if (p.val < root.val && q.val < root.val)
			root = root.left;
		else break;
	}

	return root;
}

Cycle detection - Wikipedia

function hasCycle(head: ListNode | null): boolean {
	if (!head) return false;
	let walker = runner = head;

	while (runner !== null && runner.next !== null) {
		walker = walker.next;
		runner = runner.next.next;

		if (walker === runner) return true
	}

	return false;
}
funcion containsDuplicate(nums: number[]): boolean {
	const s = new Set();

	for (let n of nums) {
		if (s.has(n)) return true
		s.add(n);
	}

	return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment