Skip to main content

Command Palette

Search for a command to run...

Day 15 – Unique Paths, Reverse Pairs, Longest Substring Without Repeating Characters, and Starting Linked Lists

Published
5 min read

Leetcode 62 – Unique Paths

Problem: From top-left of an m x n grid, reach the bottom-right using only right/down moves.


1. Brute Force (Recursion)

Intuition: Try all paths recursively.

int count(int i, int j, int m, int n) {
    if (i >= m || j >= n) return 0;
    if (i == m - 1 && j == n - 1) return 1;
    return count(i + 1, j, m, n) + count(i, j + 1, m, n);
}
int uniquePaths(int m, int n) {
    return count(0, 0, m, n);
}
// TC: O(2^(m+n))
// SC: O(m + n)

2. DP (Memoization)

Intuition: Store results of subproblems to avoid recomputation.

int dp[101][101];
int count(int i, int j, int m, int n) {
    if (i >= m || j >= n) return 0;
    if (i == m - 1 && j == n - 1) return 1;
    if (dp[i][j] != -1) return dp[i][j];
    return dp[i][j] = count(i + 1, j, m, n) + count(i, j + 1, m, n);
}
int uniquePaths(int m, int n) {
    memset(dp, -1, sizeof(dp));
    return count(0, 0, m, n);
}
// TC: O(m*n)
// SC: O(m*n) + stack space

3. Optimal – Combinatorics

Intuition: The total moves = (m-1 + n-1), choose (m-1) downs out of total.

int uniquePaths(int m, int n) {
    int N = m + n - 2, r = m - 1;
    double res = 1;
    for (int i = 1; i <= r; i++) {
        res = res * (N - r + i) / i;
    }
    return (int)res;
}
// TC: O(min(m, n))
// SC: O(1)

Leetcode 493 – Reverse Pairs

Problem: Count pairs i < j such that nums[i] > 2 * nums[j]


1. Brute Force

int reversePairs(vector<int>& nums) {
    int count = 0;
    for (int i = 0; i < nums.size(); i++)
        for (int j = i + 1; j < nums.size(); j++)
            if ((long long)nums[i] > 2LL * nums[j]) count++;
    return count;
}
// TC: O(n²)
// SC: O(1)

2. Optimal – Modified Merge Sort

Intuition: Same as counting inversions. Count while merging.

int merge(vector<int>& nums, int low, int mid, int high) {
    int cnt = 0, j = mid + 1;
    for (int i = low; i <= mid; i++) {
        while (j <= high && (long long)nums[i] > 2LL * nums[j]) j++;
        cnt += (j - (mid + 1));
    }

    vector<int> temp;
    int left = low, right = mid + 1;
    while (left <= mid && right <= high) {
        if (nums[left] <= nums[right]) temp.push_back(nums[left++]);
        else temp.push_back(nums[right++]);
    }
    while (left <= mid) temp.push_back(nums[left++]);
    while (right <= high) temp.push_back(nums[right++]);
    for (int i = low; i <= high; i++) nums[i] = temp[i - low];
    return cnt;
}

int mergeSort(vector<int>& nums, int low, int high) {
    if (low >= high) return 0;
    int mid = (low + high) / 2;
    int inv = mergeSort(nums, low, mid);
    inv += mergeSort(nums, mid + 1, high);
    inv += merge(nums, low, mid, high);
    return inv;
}

int reversePairs(vector<int>& nums) {
    return mergeSort(nums, 0, nums.size() - 1);
}
// TC: O(n log n)
// SC: O(n)

Leetcode 3 – Longest Substring Without Repeating Characters


1. Brute Force

Intuition: Check all substrings.

int lengthOfLongestSubstring(string s) {
    int maxLen = 0;
    for (int i = 0; i < s.size(); i++) {
        set<char> st;
        for (int j = i; j < s.size(); j++) {
            if (st.count(s[j])) break;
            st.insert(s[j]);
            maxLen = max(maxLen, j - i + 1);
        }
    }
    return maxLen;
}
// TC: O(n²)
// SC: O(n)

2. Optimal – Sliding Window with Map

Intuition: Use map to track last seen indices.

int lengthOfLongestSubstring(string s) {
    unordered_map<char, int> mp;
    int l = 0, r = 0, maxLen = 0;
    while (r < s.size()) {
        if (mp.count(s[r])) l = max(mp[s[r]] + 1, l);
        mp[s[r]] = r;
        maxLen = max(maxLen, r - l + 1);
        r++;
    }
    return maxLen;
}
// TC: O(n)
// SC: O(n)

Linked List Basics


➤ Definition using Struct

struct Node {
    int data;
    Node* next;
    Node(int val) {
        data = val;
        next = NULL;
    }
};

➤ Using Class

class Node {
public:
    int data;
    Node* next;
    Node(int val) {
        data = val;
        next = NULL;
    }
};

Convert Array to Linked List

Node* convert(vector<int>& arr) {
    Node* head = new Node(arr[0]);
    Node* temp = head;
    for (int i = 1; i < arr.size(); i++) {
        temp->next = new Node(arr[i]);
        temp = temp->next;
    }
    return head;
}

Linked List Operations


➤ Traversal and Count

int countNodes(Node* head) {
    int cnt = 0;
    while (head != NULL) {
        cnt++;
        head = head->next;
    }
    return cnt;
}

bool search(Node* head, int val) {
    while (head != NULL) {
        if (head->data == val) return true;
        head = head->next;
    }
    return false;
}

➤ Delete Head

Node* deleteHead(Node* head) {
    if (head == NULL) return NULL;
    Node* temp = head;
    head = head->next;
    delete temp;
    return head;
}

➤ Delete Tail

Node* deleteTail(Node* head) {
    if (head == NULL || head->next == NULL) return NULL;
    Node* temp = head;
    while (temp->next->next != NULL) temp = temp->next;
    delete temp->next;
    temp->next = NULL;
    return head;
}

➤ Delete kth Node (1-based index)

Node* deleteK(Node* head, int k) {
    if (k == 1) return deleteHead(head);
    Node* temp = head;
    for (int i = 1; i < k - 1; i++) {
        if (temp == NULL) return head;
        temp = temp->next;
    }
    if (temp == NULL || temp->next == NULL) return head;
    Node* del = temp->next;
    temp->next = temp->next->next;
    delete del;
    return head;
}

➤ Delete Node by Value

Node* deleteVal(Node* head, int val) {
    if (head == NULL) return NULL;
    if (head->data == val) return deleteHead(head);
    Node* temp = head;
    while (temp->next != NULL && temp->next->data != val) {
        temp = temp->next;
    }
    if (temp->next != NULL) {
        Node* del = temp->next;
        temp->next = temp->next->next;
        delete del;
    }
    return head;
}

Important Note

Always check edge cases in Linked Lists:

  • Deleting head/tail of single-element list

  • NULL pointer accesses

  • kth node exceeding length

  • Empty list checks