Saturday, January 9, 2021

LeetCode Medium: Design Circular Queue

Every now and then I come across a LeetCode problem that has test cases which contradict the problem statement. One such problem is #622: Design Circular Queue, a medium level problem on LeetCode.


Problem Descriptionhttps://leetcode.com/problems/design-circular-queue/

Time Complexity: O(1) across all methods - enqueue, dequeue, front, rear, isEmpty, isFull.

Design:


class MyCircularQueue {
    int[] arr;
    int front;
    int rear;
    int size;

    public MyCircularQueue(int k) {
        arr = new int[k];
        front = rear = -1;
        size = k;
    }
    
    public boolean enQueue(int value) {
        if (isFull()) {
            // queue is full
            return false;
        }
        if (isEmpty()) {
            front = rear = 0;
            arr[front] = value;
        } else {
            rear = (rear+1)%size;
            arr[rear] = value;
        }
        return true;
    }
    
    public boolean deQueue() {
        if (isEmpty())
            return false;
        if (front == rear) {
            front = rear = -1;
        } else {
            rear = (rear-1)%size;
        }
        return true;
    }
    
    public int Front() {
        if (isEmpty())
            return -1;
        return arr[front];
    }
    
    public int Rear() {
        if (isEmpty())
            return -1;
        return arr[rear];
    }
    
    public boolean isEmpty() {
        if (front == rear && front == -1) {
            // queue is empty
            return true;
        }
        return false;
    }
    
    public boolean isFull() {
        if (front == (rear+1)%size)
            return true;
        return false;
    }
}

/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * MyCircularQueue obj = new MyCircularQueue(k);
 * boolean param_1 = obj.enQueue(value);
 * boolean param_2 = obj.deQueue();
 * int param_3 = obj.Front();
 * int param_4 = obj.Rear();
 * boolean param_5 = obj.isEmpty();
 * boolean param_6 = obj.isFull();
 */

Failing test case:

Input
["MyCircularQueue","enQueue","enQueue","enQueue","enQueue","deQueue","deQueue","isEmpty","isEmpty","Rear","Rear","deQueue"]
[[8],[3],[9],[5],[0],[],[],[],[],[],[],[]]
Output
[null,true,true,true,true,true,true,false,false,9,9,true]
Expected
[null,true,true,true,true,true,true,false,false,0,0,true]

Dear @LeetCode please remove these erroneous test cases from the problem's test suite.


Happy Coding meanwhile!

Sunday, January 3, 2021

LeetCode Medium: Rotate Array

Hello all,

Problem of the day: Rotate Array (rotate towards right, k times)
Link to Problem description: https://leetcode.com/problems/rotate-array/
Solution approach: multiple ways


Solution approach 1:
Brute force moving all elements by 1 position, k times. Time Complexity O(n*k). Not great! In-place, so space complexity O(1).

Solution Approach 2:
Making a temporary copy(tmp) of k rightmost elements. Move all preceding elements towards right maintaining order, by k positions i.e. towards the rightmost end. Copy all tmp elements towards k spaces created at the leftmost end.
  class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        if (n < 2)
            return;
        k = k % n;
    
        int[] tmp = Arrays.copyOfRange(nums, n-k, n); 
        for (int i=n-k; i>=1; i--)
            nums[i+k-1] = nums[i-1];
        for (int i=tmp.length-1; i>=0; i--)
            nums[i] = tmp[i];
        
    }   
  }

Time Complexity: O(n)
Space Complexity: O(k)


Solution 3:
Using in-place reverse array custom method.

class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        if (n < 2)
            return;
        k = k % n;
        
        reverse(nums, 0, n-1-k);
        reverse(nums, n-k, n-1);
        reverse(nums, 0, n-1);
    }
    
    public void reverse(int[] arr, int st, int end) {
    	int mid = (end-st+1)%2==0 ? (end+st)/2+1 : (end+st)/2;
        for (int i=st; i<mid; i++) { // < : don't reverse mid with itself on odd nElems
            arr[i] = arr[i] + arr[end-(i-st)];
            arr[end-(i-st)] = arr[i] - arr[end-(i-st)];
            arr[i] = arr[i] - arr[end-(i-st)];
        }
    }
    
}
Time Complexity: O(n)
Space: In-place; O(1).

Happy Coding!




Wednesday, December 30, 2020

LeetCode Easy(medium-ish): Subtree of Another Tree

Hello Peeps,

We're getting back in touch with problem solving after a long-long time. I was _really really_ busy with family functions in this break.

Yesterday, I solved this LeetCode problem Subtree of Another Tree categorised as easy on LeetCode. I would say medium would have been a more appropriate categorisation of this recursively solvable problem.


Problem link: https://leetcode.com/problems/subtree-of-another-tree/
Solution Approach: Recursion
Time Complexity: O(n) where n is the number of nodes in the tree s.
Space Complexity: O(h) where h is the height of the tree s.


Solution:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSubtree(TreeNode s, TreeNode t) {
        
        //Main logic
        boolean matchFound = false;
        
        //Base condition
        if (s == null && t == null)
            return true;

        if ((s!=null && t==null) || (s==null && t!=null))
            return false;

        if (s.val == t.val)
            matchFound = matches (s, t);

        if (!matchFound) {
            matchFound = isSubtree(s.left, t);
        }
        if (!matchFound) {
            matchFound = isSubtree(s.right, t);
        }

        return matchFound;
    }
    
    private boolean matches (TreeNode s, TreeNode t) {
        if (s==null && t==null)
            return true;
        if ((s!=null && t==null) || (s==null && t!=null))
            return false;
        if (s.val != t.val)
            return false;
        return matches(s.left, t.left) && matches(s.right, t.right);
    }
}

That's all for now!

Happy Coding!!

Tuesday, September 22, 2020

LeetCode Medium: Maximum Number of Vowels in a Substring of Given Length

Hello All,
 
Today’s coding problem is a Medium level LeetCode problem. Problem #1456: Maximum Number of Vowels in a Substring of Given Length
Link to Problem: https://leetcode.com/problems/maximum-number-of-vowels-in-a-substring-of-given-length/
Problem Approach: Sliding Window
Time Complexity: O(n) where n is the number of characters in the input string.
Space Complexity: O(1) extra space
 
 
Accepted Java solution using Sliding Window:
 
class Solution {
    public int maxVowels(String s, int k) {
        if (s==null || s.length()<k) {
            return 0;
        }
        
        int maxVowelCnt = 0;
        int currentVowelCnt = 0;
        for (int i=0; i<=s.length()-k; i++) {
            if (i==0) { //1st window only
                for (int j=i; j<i+k; j++) {
                    if (isVowel(s.charAt(j)))
                        currentVowelCnt++;
                }
            } else { //remaining windows
                if(isVowel(s.charAt(i+k-1)))
                    currentVowelCnt++;
                if(isVowel(s.charAt(i-1)))
                    currentVowelCnt--;
            }
            
            maxVowelCnt = Math.max(maxVowelCnt, currentVowelCnt);
        }
        
        return maxVowelCnt;
    }
    
    private boolean isVowel(char c) {
        return c=='a' || c=='e' || c=='i' || c=='o' || c=='u' ;
    }
}

 
Video Explanation:
 
 
 
Share your thoughts!
Happy Coding!
 
 
 

Monday, September 7, 2020

LeetCode Hard: Find Median from Data Stream

LeetCode Problem #295: Find Median from Data Stream
Link to Problem Description: https://leetcode.com/problems/find-median-from-data-stream/
Category: Applications of Binary Heaps (or Priority Queues)
Solution Approach: Divide elements into 2 mutually-balanced Priority Queues - one having elements smaller than the middle element(s), one having larger.
Time Complexity of Approach:
  • O(lg n) for insertion where n = number of elements seen so far.
  • O(n) for finding the median of elements seen so far. Space Complexity: O(n) 
 
This LeetCode Hard Problem is a pretty neat application of Binary Heaps, which are readily usable as PriorityQueues in Java.
I have discussed the possible approaches to dolve the problem in the adjoining youtube video link and in this blog post I present 2 solutions for the Twin-heap based solution:
 
Approach #1: Using PriorityQueue Collection Class of Java Collections Framework
 
 
class MedianFinder {

    PriorityQueue lesser;
    PriorityQueue greater;
    
    public MedianFinder() {
        lesser = new PriorityQueue<>(10, (o1, o2)->o2-o1);
        greater = new PriorityQueue<>();
    }
    
    public void addNum(int num) { // O(lg n)
        if (lesser.size() == 0 || num < lesser.peek()) {
            lesser.add(num);
        } else {
            greater.add(num);
        }
        
        //Balance the heaps
        if (Math.abs(lesser.size() - greater.size()) <= 1)
            return;
        
        if (lesser.size() < greater.size())
            lesser.add(greater.poll());
        else
            greater.add(lesser.poll());
    }
    
    public double findMedian() { // O(1)
        if (lesser.size() == greater.size())
            return ((double)lesser.peek() + greater.peek())/2;
        
        if (lesser.size() > greater.size())
            return lesser.peek();
        return greater.peek();
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */
 
 
Approach 2: Without using pre-build classes of Java - To test if you can code a Binary Heap data structure from scratch!
 
 
class MyPriorityQueue> {
    private ArrayList q;
    private Comparator comp;
    
    public MyPriorityQueue(int initialCapacity, Comparator cmp) {
        q = new ArrayList(initialCapacity);
        comp = cmp;
    }
    public MyPriorityQueue() {
        q = new ArrayList(10);
        comp = (o1, o2)->o1.compareTo(o2);
    }
    
    private int parent(int idx) {
        int pos = idx+1;
        return pos/2 - 1;
    }
    private int left(int idx) {
        int pos = idx+1;
        return (pos*2) -1;
    }
    private int right(int idx) {
        int pos = idx+1;
        return (pos*2+1) -1;
    }
    
    public void add (E e) {
        q.add(e);
        
        //bubble-up if necessary
        int currentIdx = q.size()-1;
        int parentIdx = parent(currentIdx);
        while (parentIdx >= 0 && comp.compare(e, q.get(parentIdx)) < 0) {
            q.set(currentIdx, q.get(parentIdx));
            q.set(parentIdx, e);
            currentIdx = parentIdx;
            parentIdx = parent(currentIdx);
        }
    }
    
    public int size() {
        return q.size();
    }
    
    public E peek() {
        if (q.isEmpty())
            return null;
        return q.get(0);
    }
    
    public void remove() {
        if (q.isEmpty())
            return;
        q.set(0, q.get(q.size()-1));
        q.remove(q.size()-1);
        minHeapify(0);
    }
    
    private void minHeapify(int i) {
        if (i >= q.size())
            return;
        
        int leastValIdx = i;
        if (left(i) < q.size() && comp.compare(q.get(leastValIdx), q.get(left(i))) > 0)
            leastValIdx = left(i);
        if (right(i) < q.size() && comp.compare(q.get(leastValIdx), q.get(right(i))) > 0)
            leastValIdx = right(i);
        
        if (leastValIdx != i) {
            E tmp = q.get(leastValIdx);
            q.set(leastValIdx, q.get(i));
            q.set(i, tmp);
            
            minHeapify(leastValIdx);
        }
    }
}

class MedianFinder {

    /** initialize your data structure here. */
    MyPriorityQueue lesserElementsMaxHeap;
    MyPriorityQueue greaterElementsMinHeap;
    
    public MedianFinder() {
        lesserElementsMaxHeap = new MyPriorityQueue<>(10, (o1, o2)->o2-o1);
        greaterElementsMinHeap = new MyPriorityQueue<>(); //minHeap by default
    }
    
    public void addNum(int num) {
        Integer lesserMax = lesserElementsMaxHeap.peek();
        if (lesserMax == null || lesserMax>num)
            lesserElementsMaxHeap.add(num);
        else
            greaterElementsMinHeap.add(num);
        
        
        //ensure balanced heaps
        if (Math.abs(lesserElementsMaxHeap.size() - greaterElementsMinHeap.size()) <= 1)
            return;
        
        if (lesserElementsMaxHeap.size() > greaterElementsMinHeap.size()) {
            lesserMax = lesserElementsMaxHeap.peek();
            greaterElementsMinHeap.add(lesserMax);
            lesserElementsMaxHeap.remove();
        } else {
            Integer greaterMin = greaterElementsMinHeap.peek();
            lesserElementsMaxHeap.add(greaterMin);
            greaterElementsMinHeap.remove();
        }
            
    }
    
    public double findMedian() {
        if (lesserElementsMaxHeap.size() == greaterElementsMinHeap.size())
            return ((double)lesserElementsMaxHeap.peek() + greaterElementsMinHeap.peek())/2;
        
        if (lesserElementsMaxHeap.size() > greaterElementsMinHeap.size())
            return lesserElementsMaxHeap.peek();
        else
            return greaterElementsMinHeap.peek();
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */
 
 
 Video explanation for the approach:
 
 
Share your thoughts in comments!
 
<3


 

Tuesday, September 1, 2020

LeetCode Medium: Fruit Into Baskets

Y'day I solved LeetCode medium level problem: #904: Fruit Into Baskets ()

A quick heuristics-based solution with O(n) time-complexity in Java, which has been accepted by the LeetCode judge, is :

  
  class Solution {
    public int totalFruit(int[] tree) {
        Integer[] uniqueTreeTypesIdx = new Integer[2];
        uniqueTreeTypesIdx[0] = 0;
        
        int start = 0;
        int lastConsecutiveStretchStart = 0;
        int maxStretchLength = 1;
        int i = 1; //index counter
        for (i=1; i<tree.length; i++) {
            if (tree[i] != tree[uniqueTreeTypesIdx[0]]) {
                if (uniqueTreeTypesIdx[1] == null) {
                    uniqueTreeTypesIdx[1] = i;
                    lastConsecutiveStretchStart = i;
                } else if (tree[i] != tree[uniqueTreeTypesIdx[1]]) {
                    maxStretchLength = Math.max (maxStretchLength, i-1-start+1);
                    start = lastConsecutiveStretchStart;
                    uniqueTreeTypesIdx[0] = lastConsecutiveStretchStart;
                    uniqueTreeTypesIdx[1] = i;
                    lastConsecutiveStretchStart = i;
                } else { //tree[i] != tree[uniqueTreeTypesIdx[0]] && tree[i] == tree[uniqueTreeTypesIdx[1]] 
                    if (tree[i] == tree[lastConsecutiveStretchStart])
                        ;
                    else
                        lastConsecutiveStretchStart = i;
                }
            } else {
                if (tree[i] == tree[lastConsecutiveStretchStart])
                    ;
                else
                    lastConsecutiveStretchStart = i;
            }
        }
        maxStretchLength = Math.max (maxStretchLength, i-1-start+1);
        return maxStretchLength;
    }
}
  


I would like to re-visit it in near-times, to devise a more elegant and intuitive solution approach, but this is it for now!

Stay tuned for the next one!


Monday, August 31, 2020

Announcement! Become our Patron!

 
Our very own Let’s Code_ community initiative is now having a Patreon Landing page! Just another way for you to say thanks!
 
Go: 
 

Featured Post

interviewBit Medium: Palindrome Partitioning II

Problem Name:  Palindrome Partitioning II Problem Description : https://www.interviewbit.com/problems/palindrome-partitioning-ii/ Problem Ap...