Posted on

2467. Most Profitable Path in a Tree

There is an undirected tree with n nodes labeled from 0 to n - 1, rooted at node 0. You are given a 2D integer array edges of length n - 1 where edges[i] = [a<sub>i</sub>, b<sub>i</sub>] indicates that there is an edge between nodes a<sub>i</sub> and b<sub>i</sub> in the tree.

At every node i, there is a gate. You are also given an array of even integers amount, where amount[i] represents:

  • the price needed to open the gate at node i, if amount[i] is negative, or,
  • the cash reward obtained on opening the gate at node i, otherwise.

The game goes on as follows:

  • Initially, Alice is at node 0 and Bob is at node bob.
  • At every second, Alice and Bob each move to an adjacent node. Alice moves towards some leaf node, while Bob moves towards node 0.
  • For every node along their path, Alice and Bob either spend money to open the gate at that node, or accept the reward. Note that:
    • If the gate is already open, no price will be required, nor will there be any cash reward.
    • If Alice and Bob reach the node simultaneously, they share the price/reward for opening the gate there. In other words, if the price to open the gate is c, then both Alice and Bob pay c / 2 each. Similarly, if the reward at the gate is c, both of them receive c / 2 each.
  • If Alice reaches a leaf node, she stops moving. Similarly, if Bob reaches node 0, he stops moving. Note that these events are independent of each other.

Return the maximum net income Alice can have if she travels towards the optimal leaf node.

Example 1:

Input: edges = [[0,1],[1,2],[1,3],[3,4]], bob = 3, amount = [-2,4,2,-4,6]
Output: 6
Explanation: 
The above diagram represents the given tree. The game goes as follows:
- Alice is initially on node 0, Bob on node 3. They open the gates of their respective nodes.
  Alice's net income is now -2.
- Both Alice and Bob move to node 1. 
  Since they reach here simultaneously, they open the gate together and share the reward.
  Alice's net income becomes -2 + (4 / 2) = 0.
- Alice moves on to node 3. Since Bob already opened its gate, Alice's income remains unchanged.
  Bob moves on to node 0, and stops moving.
- Alice moves on to node 4 and opens the gate there. Her net income becomes 0 + 6 = 6.
Now, neither Alice nor Bob can make any further moves, and the game ends.
It is not possible for Alice to get a higher net income.

Example 2:

Input: edges = [[0,1]], bob = 1, amount = [-7280,2350]
Output: -7280
Explanation: 
Alice follows the path 0->1 whereas Bob follows the path 1->0.
Thus, Alice opens the gate at node 0 only. Hence, her net income is -7280. 

Constraints:

  • 2 <= n <= 10<sup>5</sup>
  • edges.length == n - 1
  • edges[i].length == 2
  • 0 <= a<sub>i</sub>, b<sub>i</sub> < n
  • a<sub>i</sub> != b<sub>i</sub>
  • edges represents a valid tree.
  • 1 <= bob < n
  • amount.length == n
  • amount[i] is an even integer in the range [-10<sup>4</sup>, 10<sup>4</sup>].

#include <vector>
#include <climits>
using namespace std;

class Solution {
public:
    int mostProfitablePath(vector<vector<int>>& edges, int bob, vector<int>& amount) {
        int n = amount.size();
        
        // Build adjacency list
        vector<vector<int>> graph(n);
        for (auto& edge : edges) {
            graph[edge[0]].push_back(edge[1]);
            graph[edge[1]].push_back(edge[0]);
        }
        
        // Find Bob's path to root
        vector<int> bobPath;
        vector<bool> visited(n, false);
        findPath(graph, bob, 0, visited, bobPath);
        
        // Set Bob's visitation times
        vector<int> bobTime(n, -1);
        for (int i = 0; i < bobPath.size(); i++) {
            bobTime[bobPath[i]] = i;
        }
        
        // Reset visited and run DFS for Alice
        visited.assign(n, false);
        return dfs(graph, 0, 0, bobTime, amount, visited);
    }
    
private:
    // DFS to find path from start to target
    bool findPath(vector<vector<int>>& graph, int start, int target, 
                  vector<bool>& visited, vector<int>& path) {
        visited[start] = true;
        path.push_back(start);
        
        if (start == target) return true;
        
        for (int next : graph[start]) {
            if (!visited[next]) {
                if (findPath(graph, next, target, visited, path)) {
                    return true;
                }
            }
        }
        
        path.pop_back();
        return false;
    }
    
    // DFS to compute Alice's maximum income
    int dfs(vector<vector<int>>& graph, int node, int time, 
            vector<int>& bobTime, vector<int>& amount, vector<bool>& visited) {
        visited[node] = true;
        
        // Calculate income at current node
        int income;
        if (bobTime[node] == -1 || bobTime[node] > time) {
            income = amount[node];  // Bob arrives after or never
        } else if (bobTime[node] == time) {
            income = amount[node] / 2;  // Simultaneous arrival
        } else {
            income = 0;  // Bob arrives before
        }
        
        // Check if leaf node
        bool isLeaf = true;
        for (int next : graph[node]) {
            if (!visited[next]) {
                isLeaf = false;
                break;
            }
        }
        
        if (isLeaf) {
            return income;
        }
        
        // Explore children and find maximum path income
        int maxChildIncome = INT_MIN;
        for (int next : graph[node]) {
            if (!visited[next]) {
                int childIncome = dfs(graph, next, time + 1, bobTime, amount, visited);
                maxChildIncome = max(maxChildIncome, childIncome);
            }
        }
        
        // If no children were explored (shouldn't happen in a valid tree from root),
        // but handle it safely
        if (maxChildIncome == INT_MIN) {
            return income;  // Should not occur as root has children
        }
        
        return income + maxChildIncome;
    }
};
Posted on

Construct the Smallest Number

Developers flex on each with the strangest of ways. How green is your github commit history. Have you submitted a PR to a open source project. How well can you solve the silliest questions on leetcode / geeksforgeeks / hackerrank?
While normies use money and status as a measure of success. Coders have incelled their way into a paradise where the glow of the monitor is all you need.
Pray for death all you want, it’s not coming. Man up and start grinding.

You are given a 0-indexed string pattern of length n consisting of the characters 'I' meaning increasing and 'D' meaning decreasing.

0-indexed string num of length n + 1 is created using the following conditions:

  • num consists of the digits '1' to '9', where each digit is used at most once.
  • If pattern[i] == 'I', then num[i] < num[i + 1].
  • If pattern[i] == 'D', then num[i] > num[i + 1].

Return the lexicographically smallest possible string num that meets the conditions.

Example 1:

Input: pattern = "IIIDIDDD"
Output: "123549876"
Explanation:
At indices 0, 1, 2, and 4 we must have that num[i] < num[i+1].
At indices 3, 5, 6, and 7 we must have that num[i] > num[i+1].
Some possible values of num are "245639871", "135749862", and "123849765".
It can be proven that "123549876" is the smallest possible num that meets the conditions.
Note that "123414321" is not possible because the digit '1' is used more than once.

Example 2:

Input: pattern = "DDD"
Output: "4321"
Explanation:
Some possible values of num are "9876", "7321", and "8742".
It can be proven that "4321" is the smallest possible num that meets the conditions.

Constraints:

  • 1 <= pattern.length <= 8
  • pattern consists of only the letters 'I' and 'D'.

class Solution {
public:
    string smallestNumber(string pattern) {
        string result;
        stack<int> st;
        for( int i = 0; i<= pattern.size(); i++ ){
            st.push(i+1);
             if ( i == pattern.length() || pattern[i] == 'I' )
                while(!st.empty()){
                    result+=to_string( st.top() );
                    st.pop();        
                }
                
        }
        return result;
    }
};
Posted on

Generating Subsets using Backtracking

1863. Sum of All Subset XOR Totals
This is a good problem to grasp basics of backtracking

The XOR total of an array is defined as the bitwise XOR of all its elements, or 0 if the array is empty.

  • For example, the XOR total of the array [2,5,6] is 2 XOR 5 XOR 6 = 1.

Given an array nums, return the sum of all XOR totals for every subset of nums

Note: Subsets with the same elements should be counted multiple times.

An array a is a subset of an array b if a can be obtained from b by deleting some (possibly zero) elements of b.

Example 1:

Input: nums = [1,3]
Output: 6
Explanation: The 4 subsets of [1,3] are:
- The empty subset has an XOR total of 0.
- [1] has an XOR total of 1.
- [3] has an XOR total of 3.
- [1,3] has an XOR total of 1 XOR 3 = 2.
0 + 1 + 3 + 2 = 6

Example 2:

Input: nums = [5,1,6]
Output: 28
Explanation: The 8 subsets of [5,1,6] are:
- The empty subset has an XOR total of 0.
- [5] has an XOR total of 5.
- [1] has an XOR total of 1.
- [6] has an XOR total of 6.
- [5,1] has an XOR total of 5 XOR 1 = 4.
- [5,6] has an XOR total of 5 XOR 6 = 3.
- [1,6] has an XOR total of 1 XOR 6 = 7.
- [5,1,6] has an XOR total of 5 XOR 1 XOR 6 = 2.
0 + 5 + 1 + 6 + 4 + 3 + 7 + 2 = 28

Example 3:

Input: nums = [3,4,5,6,7,8]
Output: 480
Explanation: The sum of all XOR totals for every subset is 480.

class Solution {
    vector<vector<int>> subset;
    void backtrack(vector<int> &nums,vector<int> &current,int index){
        subset.push_back(current);
        for(int i = index; i < nums.size(); i++ ){
            current.push_back(nums[i]);
            backtrack( nums,  current, i+1);
            current.pop_back();
        }
    }
public:
    
    int subsetXORSum(vector<int>& nums) {
        vector<int> current;
        backtrack(nums,current,0);
        
        int total_sum = 0;
        for (const auto& sub : subset) {
            int xor_sum = 0;
            for (int num : sub) {
                //std::cout<<num<<" ";
                xor_sum ^= num;
            }
            //std::cout<<std::endl;
            total_sum += xor_sum;
        }
        
        return total_sum;
    }
};
Posted on

1079. Letter Tile Possibilities

You have n  tiles, where each tile has one letter tiles[i] printed on it.

Return the number of possible non-empty sequences of letters you can make using the letters printed on those tiles.

Example 1:

Input: tiles = "AAB"
Output: 8
Explanation: The possible sequences are "A", "B", "AA", "AB", "BA", "AAB", "ABA", "BAA".

Example 2:

Input: tiles = "AAABBC"
Output: 188

Example 3:

Input: tiles = "V"
Output: 1

Depth First Search Solution, which is more performant with time complexity of O(N!) and space complexity of O(N).

class Solution {
public:
    int numTilePossibilities(string tiles) {
        unordered_map<char, int> count;
        for (char c : tiles) {
            count[c]++;
        }
        return dfs(count);
    }
    
private:
    int dfs(unordered_map<char, int>& count) {
        int sum = 0;
        for (auto& [tile, cnt] : count) {
            if (cnt == 0) continue;
            sum++;
            count[tile]--;
            sum += dfs(count);
            count[tile]++;
        }
        return sum;
    }
};

Backtracking Solution:

class Solution {
private: 
    set<string> seq;
    void backtrack(const string& tiles, string& current, vector<bool>& used){
        if( !current.empty() )
            seq.insert( current );
        for( int i =0; i<tiles.length();i++){
            if(used[i]) continue;
            used[i]=true;
            current.push_back(tiles[i]);
            backtrack(tiles, current, used);
            current.pop_back();
            used[i]=false;
        }
    }
public:
    
    int numTilePossibilities(string tiles) {
        vector<bool> used(tiles.length(), false);
        string current = "";        
        backtrack(tiles, current, used);
        return seq.size();
    }
};

Optimized Backtracking solution:


class Solution {
public:
void backtrack(unordered_map<char,int>&mapi,int &count){
    for(auto&entry:mapi){
    if(entry.second>0){
        entry.second--;
        count++;
        backtrack(mapi,count);
        entry.second++;
    }
    }
}
    int numTilePossibilities(string tiles) {
        unordered_map<char,int>mapi;
        for(int i=0;i<tiles.size();i++){
            mapi[tiles[i]]++;
        }
        int count=0;
         backtrack(mapi,count);
         return count;
    }
};

Posted on

LeetCode 1718. Construct the Lexicographically Largest Valid Sequence

Solution is a greedy recursion. Iterate in reverse order to make sure to get the largest solution first.


function constructDistancedSequence(n: number): number[] {
    const size = 2 * n - 1;
    const result: number[] = new Array(size).fill(0);
    const used: boolean[] = new Array(n + 1).fill(false);
    function backtrack(index: number): boolean {
        if (index === size) return true; // If we filled the array, return success
        if (result[index] !== 0) return backtrack(index + 1); // Skip filled positions
        for (let num = n; num >= 1; num--) { // Try from largest to smallest
            if (used[num]) continue;
            if (num === 1) {
                // Place 1 (only once)
                result[index] = 1;
                used[1] = true;
                if (backtrack(index + 1)) return true;
                used[1] = false;
                result[index] = 0;
            } else {
                // Place num at index and index + num (if valid)
                if (index + num < size && result[index + num] === 0) {
                    result[index] = result[index + num] = num;
                    used[num] = true;
                    if (backtrack(index + 1)) return true;
                    used[num] = false;
                    result[index] = result[index + num] = 0;
                }
            }
        }
        return false;
    }
    backtrack(0);
    return result;
}
Posted on

3174. Clear Digits

You are given a string s. Your task is to remove all digits by doing this operation repeatedly: Delete the first digit and the closest non-digit character to its left. Return the resulting string after removing all digits.

Example 1:

Input: s = “abc”
Output: “abc”

Explanation:

There is no digit in the string.

Example 2:

Input: s = “cb34”
Output: “”

Explanation:

First, we apply the operation on s[2], and s becomes "c4".
Then we apply the operation on s[1], and s becomes "".

Constraints:

  • 1 <= s.length <= 100
  • s consists only of lowercase English letters and digits.
  • The input is generated such that it is possible to delete all digits.

    string clearDigits(string s) {
        stack<char> sc;
        string result = "";
        for( char c : s ){
            if( c >= 48 && c <=57 ){
                sc.pop();
            } else
                sc.push(c);
        }
        while( !sc.empty() ){
            result+= sc.top();
            sc.pop();
        }
        reverse( result.begin(), result.end());
        return result;
    }
Posted on

Find the Number of Distinct Colors Among the Balls

You are given an integer limit and a 2D array queries of size n x 2.

There are limit + 1 balls with distinct labels in the range [0, limit]. Initially, all balls are uncolored. For every query in queries that is of the form [x, y], you mark ball x with the color y. After each query, you need to find the number of distinct colors among the balls.

Return an array result of length n, where result[i] denotes the number of distinct colors after i<sup>th</sup> query.

Note that when answering a query, lack of a color will not be considered as a color.

Example 1:

Input: limit = 4, queries = [[1,4],[2,5],[1,3],[3,4]]

Output: [1,2,2,3]

Explanation:

  • After query 0, ball 1 has color 4.
  • After query 1, ball 1 has color 4, and ball 2 has color 5.
  • After query 2, ball 1 has color 3, and ball 2 has color 5.
  • After query 3, ball 1 has color 3, ball 2 has color 5, and ball 3 has color 4.

Example 2:

Input: limit = 4, queries = [[0,1],[1,2],[2,2],[3,4],[4,5]]

Output: [1,2,2,3,4]

Explanation:

  • After query 0, ball 0 has color 1.
  • After query 1, ball 0 has color 1, and ball 1 has color 2.
  • After query 2, ball 0 has color 1, and balls 1 and 2 have color 2.
  • After query 3, ball 0 has color 1, balls 1 and 2 have color 2, and ball 3 has color 4.
  • After query 4, ball 0 has color 1, balls 1 and 2 have color 2, ball 3 has color 4, and ball 4 has color 5.

class Solution {
    public int[] queryResults(int limit, int[][] queries) {
        int[] result = new int[queries.length];
        HashMap<Integer, Integer> ballMap = new HashMap<>();
        HashMap<Integer, Integer> colorMap = new HashMap<>();
        for( int i = 0; i < queries.length; i++ ) {
            int[] q =  queries[i];
            int ball = q[0];
            int color = q[1];
            if( ballMap.containsKey( ball )){
                
                int prevColor = ballMap.get( ball );
                colorMap.put( prevColor, colorMap.get(prevColor)-1);
                
                if( colorMap.get( prevColor) == 0 )
                    colorMap.remove(prevColor);
                
            }
            
            ballMap.put(ball, color);
            colorMap.put( color , colorMap.getOrDefault(color, 0) + 1);
            result[i] = colorMap.size();
            
        }
        return result;
    }
}

Posted on

Tuple with Same Product

Given an array nums of distinct positive integers, return the number of tuples (a, b, c, d) such that a * b = c * d where abc, and d are elements of nums, and a != b != c != d.

Example 1:

Input: nums = [2,3,4,6]
Output: 8
Explanation: There are 8 valid tuples:
(2,6,3,4) , (2,6,4,3) , (6,2,3,4) , (6,2,4,3)
(3,4,2,6) , (4,3,2,6) , (3,4,6,2) , (4,3,6,2)

Example 2:

Input: nums = [1,2,4,5,10]
Output: 16
Explanation: There are 16 valid tuples:
(1,10,2,5) , (1,10,5,2) , (10,1,2,5) , (10,1,5,2)
(2,5,1,10) , (2,5,10,1) , (5,2,1,10) , (5,2,10,1)
(2,10,4,5) , (2,10,5,4) , (10,2,4,5) , (10,2,5,4)
(4,5,2,10) , (4,5,10,2) , (5,4,2,10) , (5,4,10,2)

Constraints:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 10<sup>4</sup>
  • All elements in nums are distinct.
class Solution {
public:
    int tupleSameProduct(vector<int>& nums) {
        uint size = nums.size();
        unordered_map<int, int> mp;

        for( int i = 0; i < size; i++ )
            for( int j = i +1; j< size; j++){
                int prod  = nums[i] * nums[j];
                mp[prod]++;
            }
        
        int res = 0;
        for( auto& [prod, cnt] : mp ){
            int pairs = (cnt *(cnt-1)) / 2;
            res += 8 * pairs;
        }

        return res;
    }
};
Posted on

1790. Check if One String Swap Can Make Strings Equal

You are given two strings s1 and s2 of equal length. A string swap is an operation where you choose two indices in a string (not necessarily different) and swap the characters at these indices.

Return true if it is possible to make both strings equal by performing at most one string swap on exactly one of the strings. Otherwise, return false.

Example 1:

Input: s1 = "bank", s2 = "kanb"
Output: true
Explanation: For example, swap the first character with the last character of s2 to make "bank".

Example 2:

Input: s1 = "attack", s2 = "defend"
Output: false
Explanation: It is impossible to make them equal with one string swap.

Example 3:

Input: s1 = "kelb", s2 = "kelb"
Output: true
Explanation: The two strings are already equal, so no string swap operation is required.

Constraints:

  • 1 <= s1.length, s2.length <= 100
  • s1.length == s2.length
  • s1 and s2 consist of only lowercase English letters.
class Solution {
public:
    bool areAlmostEqual(string s1, string s2) {
        vector<int> index;
        for( uint8_t i = 0; i < s1.length(); i++ ){
            if( s1[i] != s2[i] )
                index.push_back(i);
            if( index.size() > 2)
                return false;

        }
        if( index.size() == 2 ){
            int i = index[0];
            int j = index[1];
            if( s1[i] == s2[j] && s1[j] == s2[i] ) return true;
        }
    
        return index.size() == 0;
    }
};
Posted on

Removing the Nth Node from a list.

https://leetcode.com/problems/remove-nth-node-from-end-of-list

Given the head of a linked list, remove the n<sup>th</sup> node from the end of the list and return its head.

Example 1:

Input: head = [1,2,3,4,5], n = 2
Output: [1,2,3,5]

Example 2:

Input: head = [1], n = 1
Output: []

Example 3:

Input: head = [1,2], n = 1
Output: [1]

Constraints:

  • The number of nodes in the list is sz.
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz

Follow up: Could you do this in one pass?

#include <iostream>
using namespace std;

struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode* next) : val(x), next(next) {}
};

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode dummy(0, head);
        ListNode* fast = &dummy;
        ListNode* slow = &dummy;

        // Move fast n+1 steps ahead
        for (int i = 0; i <= n; i++) {
            fast = fast->next;
        }

        // Move both pointers
        while (fast) {
            fast = fast->next;
            slow = slow->next;
        }

        // Remove the nth node
        slow->next = slow->next->next;

        return dummy.next;
    }
};

// Function to create a linked list from an array
ListNode* createLinkedList(int arr[], int size) {
    if (size == 0) return nullptr;
    ListNode* head = new ListNode(arr[0]);
    ListNode* current = head;
    for (int i = 1; i < size; i++) {
        current->next = new ListNode(arr[i]);
        current = current->next;
    }
    return head;
}

// Function to print a linked list
void printLinkedList(ListNode* head) {
    while (head) {
        cout << head->val << " -> ";
        head = head->next;
    }
    cout << "NULL" << endl;
}

// Main function for testing
int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);
    int n = 2;  // Remove the 2nd node from the end

    // Create linked list
    ListNode* head = createLinkedList(arr, size);

    cout << "Original List: ";
    printLinkedList(head);

    // Call removeNthFromEnd function
    Solution solution;
    head = solution.removeNthFromEnd(head, n);

    cout << "Updated List: ";
    printLinkedList(head);

    return 0;
}