amt

FBDS

amt
Mar 22nd, 2025 (edited)
643
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* 314 binary-tree-vertical-order-traversal M
  2. Given the root of a binary tree, return the vertical order traversal of its nodes' values. (i.e., from top to bottom, column by column).
  3.  
  4. If two nodes are in the same row and column, the order should be from left to right.
  5.  
  6. Example 1:
  7.  
  8.       3
  9.      / \
  10.     9   20
  11.        /  \
  12.       15   7
  13.  
  14. Input: root = [3,9,20,null,null,15,7]
  15. Output: [[9],[3,15],[20],[7]]
  16.  
  17. Example 2:
  18.  
  19.       3
  20.      / \
  21.     9   8
  22.    / \  / \
  23.   4   0 1  7
  24.  
  25. Input: root = [3,9,8,4,0,1,7]
  26. Output: [[4],[9],[3,0,1],[8],[7]]
  27.  
  28. Example 3:
  29.  
  30.         1
  31.        / \
  32.       2   3
  33.      / \  / \
  34.     4  10 9  11
  35.      \  
  36.       5
  37.        \
  38.         6
  39.  
  40. Input: root = [1,2,3,4,10,9,11,null,5,null,null,null,null,null,null,null,6]
  41. Output: [[4],[2,5],[1,10,9,6],[3],[11]]
  42.  
  43. Constraints:
  44.  
  45. The number of nodes in the tree is in the range [0, 100].
  46. -100 <= Node.val <= 100
  47.  
  48. Approach:
  49.  
  50. The approach is the same as the previous solution, using Breadth-First Search (BFS) combined with a hash map (Map in JavaScript) to store nodes based on their column index. The only change is in how we process the queue to avoid using the .shift() method.
  51.  
  52. Handle Empty Tree:
  53.  
  54. If the root is null, return an empty array.
  55. Initialization:
  56.  
  57. Create a columnMap (a Map) to store nodes' values for each column. The key is the column index, and the value is an array of node values.
  58. Initialize a queue for BFS. Each element in the queue is an array [node, column], where column is the horizontal distance of the node from the root (0 for the root).
  59. Initialize queueFront to 0. This variable will track the index of the next element to be processed in the queue.
  60. Initialize minColumn and maxColumn to 0 to keep track of the range of column indices.
  61. Breadth-First Search:
  62.  
  63. While queueFront is less than queue.length:
  64. Get the element at the front of the queue using queue[queueFront].
  65. Increment queueFront to move the "dequeue" pointer. We are effectively moving through the queue without modifying the array itself.
  66. Update minColumn and maxColumn to track the column range.
  67. Store the node's value in the columnMap for the corresponding column.
  68. Enqueue the left and right children (if they exist) with their respective column indices (column - 1 for left, column + 1 for right).
  69. Construct Result:
  70.  
  71. Create a result array.
  72. Iterate from minColumn to maxColumn.
  73. For each column index, retrieve the list of node values from columnMap and add it to the result array.
  74. Return Result:
  75.  
  76. Return the result array, which contains the vertical order traversal.
  77. Time Complexity:
  78.  
  79. BFS visits each node once, so the time taken is O(N), where N is the number of nodes in the tree.
  80. Operations within the loop (map access, push, incrementing queueFront) are O(1) on average.
  81. Constructing the result array iterates through the columns, which is at most O(W), where W is the width of the tree. In the worst case, W can be N, but it's often less.
  82. Therefore, the overall time complexity is O(N).
  83. Space Complexity:
  84.  
  85. The columnMap stores the node values for each column. In the worst case, it might store all nodes, so its space complexity is O(N).
  86. The queue can also hold up to all nodes in the worst case (for a wide tree), so its space complexity is O(N).
  87. queueFront, minColumn, and maxColumn take O(1) space.
  88. The result array stores the vertical order traversal, which is also O(N).
  89. Therefore, the overall space complexity is O(N).
  90.  
  91.  
  92. */
  93.  
  94. /**
  95.  * Definition for a binary tree node.
  96.  * function TreeNode(val, left, right) {
  97.  * this.val = (val===undefined ? 0 : val)
  98.  * this.left = (left===undefined ? null : left)
  99.  * this.right = (right===undefined ? null : right)
  100.  * }
  101.  */
  102. /**
  103.  * @param {TreeNode} root
  104.  * @return {number[][]}
  105.  */
  106.  
  107. function verticalOrder(root) {
  108.     if (!root) {
  109.         return [];
  110.     }
  111.  
  112.     const columnMap = new Map(); // Map to store nodes by column
  113.     const queue = [[root, 0]];    // Queue for BFS, storing [node, column]
  114.     let queueFront = 0; // Index to track the front of the queue
  115.     let minColumn = 0;
  116.     let maxColumn = 0;
  117.  
  118.     while (queueFront < queue.length) {
  119.         const [node, column] = queue[queueFront];
  120.         queueFront++; // Increment queueFront instead of shifting
  121.  
  122.         minColumn = Math.min(minColumn, column);
  123.         maxColumn = Math.max(maxColumn, column);
  124.  
  125.         if (!columnMap.has(column)) {
  126.             columnMap.set(column, []);
  127.         }
  128.         columnMap.get(column).push(node.val);
  129.  
  130.         if (node.left) {
  131.             queue.push([node.left, column - 1]);
  132.         }
  133.         if (node.right) {
  134.             queue.push([node.right, column + 1]);
  135.         }
  136.     }
  137.  
  138.     const result = [];
  139.     for (let i = minColumn; i <= maxColumn; i++) {
  140.         result.push(columnMap.get(i));
  141.     }
  142.     return result;
  143. }
  144.  
  145. // Helper function to create a TreeNode (for testing)
  146. function TreeNode(val, left, right) {
  147.     this.val = val === undefined ? 0 : val;
  148.     this.left = left === undefined ? null : left;
  149.     this.right = right === undefined ? null : right;
  150. }
  151.  
  152. // Example 1:
  153. const root1 = new TreeNode(3);
  154. root1.left = new TreeNode(9);
  155. root1.right = new TreeNode(20);
  156. root1.right.left = new TreeNode(15);
  157. root1.right.right = new TreeNode(7);
  158. console.log("Example 1:", verticalOrder(root1));
  159.  
  160. // Example 2:
  161. const root2 = new TreeNode(3);
  162. root2.left = new TreeNode(9);
  163. root2.right = new TreeNode(8);
  164. root2.left.left = new TreeNode(4);
  165. root2.left.right = new TreeNode(0);
  166. root2.right.left = new TreeNode(1);
  167. root2.right.right = new TreeNode(7);
  168. console.log("Example 2:", verticalOrder(root2));
  169.  
  170. // Example 3: (Corrected Tree Construction)
  171. let root3 = new TreeNode(1,
  172.     new TreeNode(2,
  173.         new TreeNode(4, null, new TreeNode(5, null, new TreeNode(6))),
  174.         new TreeNode(10)
  175.     ),
  176.     new TreeNode(3,
  177.         new TreeNode(9),
  178.         new TreeNode(11)
  179.     )
  180. );
  181. console.log("Example 3:", verticalOrder(root3));
  182.  
  183. // Example 4: Single Node
  184. const root4 = new TreeNode(1);
  185. console.log("Example 4:", verticalOrder(root4)); // Output: [[1]]
  186.  
  187. // Example 5: Skewed Tree (Left)
  188. const root5 = new TreeNode(1);
  189. root5.left = new TreeNode(2);
  190. root5.left.left = new TreeNode(3);
  191. console.log("Example 5:", verticalOrder(root5)); // Output: [[3], [2], [1]]
  192.  
  193.  
  194.  
  195. /* Approach 2
  196. Use BFS (Breadth-First Search) with a queue to traverse level by level.
  197.  
  198. Maintain a map (or object) to store node values grouped by their vertical column index.
  199.  
  200. Use a queue that stores (node, column, row), where:
  201.  
  202. column tracks vertical alignment (left is -1, right is +1).
  203.  
  204. row tracks depth (for sorting when needed).
  205.  
  206. After traversal:
  207.  
  208. Sort nodes by column first.
  209.  
  210. If multiple nodes share the same column, sort by row.
  211.  
  212. If row values are the same, sort by left-to-right order.
  213.  
  214. Construct the final result by collecting values column-wise.
  215.  
  216. Time Complexity
  217. O(N log N) in the worst case due to sorting inside each column.
  218.  
  219. O(N) for traversal of the tree.
  220.  
  221. Space Complexity
  222. O(N) for storing nodes in the hash map and queue.
  223.  
  224. This solution efficiently organizes and sorts nodes based on column and row values while maintaining left-to-right order. 🚀
  225. */
  226.  
  227.  
  228. class TreeNode {
  229.     constructor(val, left = null, right = null) {
  230.         this.val = val;
  231.         this.left = left;
  232.         this.right = right;
  233.     }
  234. }
  235.  
  236. function verticalOrderTraversal(root) {
  237.     if (!root) return [];
  238.  
  239.     let columnMap = new Map();
  240.     let queue = [[root, 0, 0]]; // [node, column, row]
  241.     let minCol = 0, maxCol = 0;
  242.  
  243.     while (queue.length) {
  244.         let [node, col, row] = queue.shift();
  245.  
  246.         if (!columnMap.has(col)) columnMap.set(col, []);
  247.         columnMap.get(col).push([row, node.val]);
  248.  
  249.         minCol = Math.min(minCol, col);
  250.         maxCol = Math.max(maxCol, col);
  251.  
  252.         if (node.left) queue.push([node.left, col - 1, row + 1]);
  253.         if (node.right) queue.push([node.right, col + 1, row + 1]);
  254.     }
  255.  
  256.     let result = [];
  257.     for (let i = minCol; i <= maxCol; i++) {
  258.         let sortedNodes = columnMap.get(i).sort((a, b) => {
  259.             if (a[0] !== b[0]) return a[0] - b[0]; // Sort by row
  260.             return a[1] - b[1]; // Sort by value for same row
  261.         }).map(x => x[1]);
  262.         result.push(sortedNodes);
  263.     }
  264.  
  265.     return result;
  266. }
  267.  
  268. // Example Usage
  269. let root1 = new TreeNode(3,
  270.     new TreeNode(9),
  271.     new TreeNode(20, new TreeNode(15), new TreeNode(7))
  272. );
  273. console.log(verticalOrderTraversal(root1)); // [[9], [3, 15], [20], [7]]
  274.  
  275. let root2 = new TreeNode(3,
  276.     new TreeNode(9, new TreeNode(4), new TreeNode(0)),
  277.     new TreeNode(8, new TreeNode(1), new TreeNode(7))
  278. );
  279. console.log(verticalOrderTraversal(root2)); // [[4], [9], [3, 0, 1], [8], [7]]
  280.  
  281.  
  282. /*
  283. Let's walk through an example step by step for the input:
  284.  
  285. Input: root = [1,2,3,4,10,9,11,null,5,null,null,null,null,null,null,null,6]
  286. Step 1: Construct the Binary Tree
  287. The given input represents a binary tree:
  288.  
  289.  
  290.            1
  291.          /   \
  292.         2     3
  293.        / \   /  \
  294.       4  10 9   11
  295.        \
  296.         5
  297.          \
  298.           6
  299. Each node has an associated column index:
  300.  
  301. Root (1) is at column 0
  302.  
  303. Left children move to column -1, right children move to column +1
  304.  
  305. Step 2: Assign Column & Row Indices
  306. We traverse the tree using BFS, maintaining (node, column, row):
  307.  
  308. Node    Column  Row
  309. 1   0   0
  310. 2   -1  1
  311. 3   +1  1
  312. 4   -2  2
  313. 10  0   2
  314. 9   0   2
  315. 11  +2  2
  316. 5   -1  3
  317. 6   0   4
  318. Step 3: Group by Column
  319. Sorting nodes first by column and then by row:
  320.  
  321. Column. Nodes Sorted by Row.    Values
  322. -2  [(2,4)] [4]
  323. -1  [(1,2), (3,5)]  [2,5]
  324. 0   [(0,1), (2,10), (2,9), (4,6)]   [1,10,9,6]
  325. +1  [(1,3)] [3]
  326. +2  [(2,11)]    [11]
  327. Step 4: Construct the Output
  328.  
  329. Output: [[4], [2,5], [1,10,9,6], [3], [11]]
  330.  
  331.  
  332. Explanation of Code:
  333. Define TreeNode Class:
  334.  
  335. Each node stores val, left, and right pointers.
  336.  
  337. Vertical Order Traversal Algorithm:
  338.  
  339. Use BFS (Level Order Traversal) with a queue ([node, column, row]).
  340.  
  341. Store values in a Map, where column is the key, and the value is an array [row, val].
  342.  
  343. Sort the columns (left to right) and within each column, sort by row and value.
  344.  
  345. Tree Construction:
  346.  
  347. Builds the given binary tree structure.
  348.  
  349. Print the Output:
  350.  
  351. Expected Output: [[4], [2,5], [1,10,9,6], [3], [11]]
  352.  
  353. Time and Space Complexity:
  354. Time Complexity: O(N log N)
  355.  
  356. O(N) for BFS traversal.
  357.  
  358. O(N log N) sorting columns and rows.
  359.  
  360. Space Complexity: O(N)
  361.  
  362. O(N) for storing nodes in the columnMap.
  363.  
  364. O(N) queue storage.
  365.  
  366. This solution is efficient for N ≤ 100 nodes. 🚀
  367. */
  368.  
  369.  
  370. class TreeNode {
  371.     constructor(val, left = null, right = null) {
  372.         this.val = val;
  373.         this.left = left;
  374.         this.right = right;
  375.     }
  376. }
  377.  
  378. function verticalOrderTraversal(root) {
  379.     if (!root) return [];
  380.  
  381.     let columnMap = new Map();
  382.     let queue = [[root, 0, 0]]; // [node, column, row]
  383.  
  384.     while (queue.length > 0) {
  385.         let [node, col, row] = queue.shift();
  386.  
  387.         if (!columnMap.has(col)) columnMap.set(col, []);
  388.         columnMap.get(col).push([row, node.val]);
  389.  
  390.         if (node.left) queue.push([node.left, col - 1, row + 1]);
  391.         if (node.right) queue.push([node.right, col + 1, row + 1]);
  392.     }
  393.  
  394.     return [...columnMap.entries()]
  395.         .sort((a, b) => a[0] - b[0]) // Sort by column index
  396.         .map(([_, values]) =>
  397.             values.sort((a, b) => a[0] - b[0] || a[1] - b[1]) // Sort by row, then value
  398.                   .map(v => v[1])
  399.         );
  400. }
  401.  
  402. // Constructing the tree: root = [1,2,3,4,10,9,11,null,5,null,null,null,null,null,null,null,6]
  403. let root = new TreeNode(1,
  404.     new TreeNode(2,
  405.         new TreeNode(4, null, new TreeNode(5, null, new TreeNode(6))),
  406.         new TreeNode(10)
  407.     ),
  408.     new TreeNode(3,
  409.         new TreeNode(9),
  410.         new TreeNode(11)
  411.     )
  412. );
  413.  
  414. console.log(verticalOrderTraversal(root));
  415. // Expected Output: [[4], [2,5], [1,10,9,6], [3], [11]]
  416.  
  417. /* 408. Valid Word Abbreviation Easy
  418.  
  419. A string can be abbreviated by replacing any number of non-adjacent, non-empty substrings with their lengths. The lengths should not have leading zeros.
  420.  
  421. For example, a string such as "substitution" could be abbreviated as (but not limited to):
  422.  
  423. "s10n" ("s ubstitutio n")
  424. "sub4u4" ("sub stit u tion")
  425. "12" ("substitution")
  426. "su3i1u2on" ("su bst i t u ti on")
  427. "substitution" (no substrings replaced)
  428. The following are not valid abbreviations:
  429.  
  430. "s55n" ("s ubsti tutio n", the replaced substrings are adjacent)
  431. "s010n" (has leading zeros)
  432. "s0ubstitution" (replaces an empty substring)
  433. Given a string word and an abbreviation abbr, return whether the string matches the given abbreviation.
  434.  
  435. A substring is a contiguous non-empty sequence of characters within a string.
  436.  
  437.  
  438.  
  439. Example 1:
  440.  
  441. Input: word = "internationalization", abbr = "i12iz4n"
  442. Output: true
  443. Explanation: The word "internationalization" can be abbreviated as "i12iz4n" ("i nternational iz atio n").
  444. Example 2:
  445.  
  446. Input: word = "apple", abbr = "a2e"
  447. Output: false
  448. Explanation: The word "apple" cannot be abbreviated as "a2e".
  449.  
  450.  
  451. Constraints:
  452.  
  453. 1 <= word.length <= 20
  454. word consists of only lowercase English letters.
  455. 1 <= abbr.length <= 10
  456. abbr consists of lowercase English letters and digits.
  457. All the integers in abbr will fit in a 32-bit integer.
  458.  
  459. Explanation
  460. Two Pointers Approach:
  461.  
  462. i tracks the position in word
  463.  
  464. j tracks the position in abbr
  465.  
  466. Handling Digits in abbr:
  467.  
  468. If abbr[j] is a digit:
  469.  
  470. Ensure it’s not '0' (leading zeros not allowed).
  471.  
  472. Convert consecutive digits into a number.
  473.  
  474. Move i forward by this number.
  475.  
  476. Handling Characters in abbr:
  477.  
  478. If abbr[j] is a letter, check if word[i] matches abbr[j].
  479.  
  480. If not, return false.
  481.  
  482. Final Check:
  483.  
  484. i should reach word.length and j should reach abbr.length exactly.
  485.  
  486. Time and Space Complexity
  487. Time Complexity: O(N + M), where:
  488.  
  489. N = length of word
  490.  
  491. M = length of abbr
  492.  
  493. Each character in abbr is processed once.
  494.  
  495. Space Complexity: O(1)
  496.  
  497. We use only a few integer variables (i, j, num), which take constant space.
  498.  
  499. 🚀 Optimized and efficient for small input sizes (word ≤ 20, abbr ≤ 10).
  500. */
  501.  
  502. function validWordAbbreviation(word, abbr) {
  503.     let i = 0, j = 0;
  504.  
  505.     while (i < word.length && j < abbr.length) {
  506.         if (!isNaN(abbr[j]) && abbr[j] !== '0') {  // If `abbr[j]` is a number and not '0'
  507.             let num = 0;
  508.             while (j < abbr.length && !isNaN(abbr[j])) {
  509.                 num = num * 10 + (abbr[j] - '0');
  510.                 j++;
  511.             }
  512.             i += num;  // Skip `num` characters in `word`
  513.         } else {
  514.             if (word[i] !== abbr[j]) return false; // Mismatched character
  515.             i++;
  516.             j++;
  517.         }
  518.     }
  519.  
  520.     return i === word.length && j === abbr.length;
  521. }
  522.  
  523. // Example Test Cases
  524. console.log(validWordAbbreviation("internationalization", "i12iz4n")); // true
  525. console.log(validWordAbbreviation("apple", "a2e")); // false
  526. console.log(validWordAbbreviation("substitution", "s10n")); // true
  527. console.log(validWordAbbreviation("substitution", "s55n")); // false (adjacent numbers not allowed)
  528. console.log(validWordAbbreviation("substitution", "s010n")); // false (leading zero not allowed)
  529. console.log(validWordAbbreviation("substitution", "s0ubstitution")); // false (empty substring replacement)
  530.  
  531. /*
  532. Approach:
  533.  
  534. The problem asks us to check if a given abbreviation abbr is valid for a given word word. We need to handle both letter and number parts in the abbreviation.
  535.  
  536. Initialize Pointers:
  537.  
  538. Initialize wordIndex to 0, pointing to the current character in word.
  539. Initialize abbrIndex to 0, pointing to the current character in abbr.
  540. Iterate Through Abbreviation:
  541.  
  542. Iterate through the abbreviation abbr character by character.
  543. Handle Characters:
  544.  
  545. For each character abbrChar in abbr:
  546. If abbrChar is a letter:
  547. Check if the current character in word is the same as abbrChar. If not, the abbreviation is invalid, return false.
  548. Increment both wordIndex and abbrIndex to move to the next characters in both strings.
  549. If abbrChar is a digit:
  550. Extract the entire number from abbr. Continue reading consecutive digits until a non-digit character is encountered.
  551. Convert the extracted string of digits to a number.
  552. Check for leading zeros in the number string. If found, the abbreviation is invalid, return false.
  553. Advance the wordIndex by the extracted number. This simulates skipping the abbreviated part of the word.
  554. Check for Complete Match:
  555.  
  556. After processing the entire abbreviation, check if both wordIndex and abbrIndex have reached the end of their respective strings (word and abbr). If they have, it means the abbreviation matches the word, return true. Otherwise, return false.
  557. Time Complexity:
  558.  
  559. The outer while loop iterates through the abbreviation abbr once.
  560. The inner while loop (when processing a number) iterates through consecutive digits in abbr. In the worst case, it can iterate up to the length of the number string, which is limited by the problem constraints (32-bit integer).
  561. All other operations (character comparison, string concatenation, number conversion) take constant time.
  562. Therefore, the time complexity is O(m + k), where m is the length of abbr, and k is the maximum length of a number in abbr. Since k is bounded by the maximum number of digits in a 32-bit integer, it can be considered a constant in practice. Thus, the time complexity can be simplified to O(m).
  563. Space Complexity:
  564.  
  565. The code uses a few constant-size variables (wordIndex, abbrIndex, numStr, num).
  566. The space used by these variables does not depend on the length of the input strings.
  567. Therefore, the space complexity is O(1).
  568. */
  569. /**
  570.  * @param {string} word
  571.  * @param {string} abbr
  572.  * @return {boolean}
  573.  */
  574. function validWordAbbreviation(word, abbr) {
  575.     let wordIndex = 0;
  576.     let abbrIndex = 0;
  577.  
  578.     while (wordIndex < word.length && abbrIndex < abbr.length) {
  579.         const abbrChar = abbr[abbrIndex];
  580.  
  581.         if (isNaN(Number(abbrChar))) { // abbrChar is a letter
  582.             if (word[wordIndex] !== abbrChar) {
  583.                 return false;
  584.             }
  585.             wordIndex++;
  586.             abbrIndex++;
  587.         } else { // abbrChar is a digit
  588.             let numStr = "";
  589.             while (abbrIndex < abbr.length && !isNaN(Number(abbr[abbrIndex]))) {
  590.                 numStr += abbr[abbrIndex];
  591.                 abbrIndex++;
  592.             }
  593.  
  594.             const num = Number(numStr);
  595.  
  596.             if (numStr.length > 1 && numStr[0] === '0') { // Check for leading zero
  597.                 return false;
  598.             }
  599.  
  600.             wordIndex += num;
  601.         }
  602.     }
  603.  
  604.     return wordIndex === word.length && abbrIndex === abbr.length;
  605. }
  606.  
  607. // Example 1:
  608. const word1 = "internationalization";
  609. const abbr1 = "i12iz4n";
  610. console.log(`"${abbr1}" is a valid abbreviation of "${word1}": ${validWordAbbreviation(word1, abbr1)}`); // Output: true
  611.  
  612. // Example 2:
  613. const word2 = "apple";
  614. const abbr2 = "a2e";
  615. console.log(`"${abbr2}" is a valid abbreviation of "${word2}": ${validWordAbbreviation(word2, abbr2)}`); // Output: false
  616.  
  617. // Example 3:
  618. const word3 = "substitution";
  619. const abbr3 = "s10n";
  620. console.log(`"${abbr3}" is a valid abbreviation of "${word3}": ${validWordAbbreviation(word3, abbr3)}`); // Output: true
  621.  
  622. // Example 4:
  623. const word4 = "substitution";
  624. const abbr4 = "sub4u4";
  625. console.log(`"${abbr4}" is a valid abbreviation of "${word4}": ${validWordAbbreviation(word4, abbr4)}`); // Output: true
  626.  
  627. // Example 5:
  628. const word5 = "substitution";
  629. const abbr5 = "12";
  630. console.log(`"${abbr5}" is a valid abbreviation of "${word5}": ${validWordAbbreviation(word5, abbr5)}`); // Output: true
  631.  
  632. // Example 6:
  633. const word6 = "substitution";
  634. const abbr6 = "su3i1u2on";
  635. console.log(`"${abbr6}" is a valid abbreviation of "${word6}": ${validWordAbbreviation(word6, abbr6)}`); // Output: true
  636.  
  637. // Example 7:
  638. const word7 = "substitution";
  639. const abbr7 = "substitution";
  640. console.log(`"${abbr7}" is a valid abbreviation of "${word7}": ${validWordAbbreviation(word7, abbr7)}`); // Output: true
  641.  
  642. // Example 8: Invalid - adjacent numbers
  643. const word8 = "substitution";
  644. const abbr8 = "s55n";
  645. console.log(`"${abbr8}" is a valid abbreviation of "${word8}": ${validWordAbbreviation(word8, abbr8)}`); // Output: false
  646.  
  647. // Example 9: Invalid - leading zero
  648. const word9 = "substitution";
  649. const abbr9 = "s010n";
  650. console.log(`"${abbr9}" is a valid abbreviation of "${word9}": ${validWordAbbreviation(word9, abbr9)}`); // Output: false
  651.  
  652. // Example 10: Invalid - empty substring
  653. const word10 = "substitution";
  654. const abbr10 = "s0ubstitution";
  655. console.log(`"${abbr10}" is a valid abbreviation of "${word10}": ${validWordAbbreviation(word10, abbr10)}`); // Output: false
  656.  
  657. // Example 11:
  658. const word11 = "word";
  659. const abbr11 = "w2d";
  660. console.log(`"${abbr11}" is a valid abbreviation of "${word11}": ${validWordAbbreviation(word11, abbr11)}`); // Output: true
  661.  
  662. // Example 12:
  663. const word12 = "a";
  664. const abbr12 = "1";
  665. console.log(`"${abbr12}" is a valid abbreviation of "${word12}": ${validWordAbbreviation(word12, abbr12)}`); // Output: true
  666.  
  667.  
  668. /* 339. Nested List Weight Sum Medium
  669.  
  670. You are given a nested list of integers nestedList. Each element is either an integer or a list whose elements may also be integers or other lists.
  671.  
  672. The depth of an integer is the number of lists that it is inside of. For example, the nested list [1,[2,2],[[3],2],1] has each integer's value set to its depth.
  673.  
  674. Return the sum of each integer in nestedList multiplied by its depth.
  675.  
  676. Example 1:
  677.  
  678. Input: nestedList = [[1,1],2,[1,1]]
  679. Output: 10
  680. Explanation: Four 1's at depth 2, one 2 at depth 1. 1*2 + 1*2 + 2*1 + 1*2 + 1*2 = 10.
  681. Example 2:
  682.  
  683. Input: nestedList = [1,[4,[6]]]
  684. Output: 27
  685. Explanation: One 1 at depth 1, one 4 at depth 2, and one 6 at depth 3. 1*1 + 4*2 + 6*3 = 27.
  686. Example 3:
  687.  
  688. Input: nestedList = [0]
  689. Output: 0
  690.  
  691. Constraints:
  692.  
  693. 1 <= nestedList.length <= 50
  694. The values of the integers in the nested list is in the range [-100, 100].
  695. The maximum depth of any integer is less than or equal to 50.
  696.  
  697. Explanation
  698. Recursive Depth-First Search (DFS):
  699.  
  700. We define a helper function dfs(list, depth) to traverse the nested structure.
  701.  
  702. Initialize sum = 0 at each level.
  703.  
  704. Iterate through each element:
  705.  
  706. If it’s an integer, multiply it by the current depth and add it to sum.
  707.  
  708. If it’s a list, call dfs recursively with an incremented depth.
  709.  
  710. Base Case:
  711.  
  712. If the list is empty, return 0.
  713.  
  714. Starting Condition:
  715.  
  716. We call dfs(nestedList, 1) since the top level starts at depth 1.
  717.  
  718. Time and Space Complexity
  719. Time Complexity: O(N)
  720.  
  721. N is the total number of integers and lists in nestedList.
  722.  
  723. Each element is visited once.
  724.  
  725. Space Complexity: O(D) (Depth of recursion)
  726.  
  727. D is the maximum depth of nesting (≤ 50).
  728.  
  729. In the worst case, recursion goes as deep as D.
  730.  
  731. 🚀 This solution efficiently handles nested structures and computes the weighted sum.
  732. */
  733.  
  734. function depthSum(nestedList) {
  735.     function dfs(list, depth) {
  736.         let sum = 0;
  737.         for (let element of list) {
  738.             if (Array.isArray(element)) {
  739.                 sum += dfs(element, depth + 1);
  740.             } else {
  741.                 sum += element * depth;
  742.             }
  743.         }
  744.         return sum;
  745.     }
  746.     return dfs(nestedList, 1);
  747. }
  748.  
  749. // Example Test Cases
  750. console.log(depthSum([[1,1],2,[1,1]])); // Output: 10
  751. console.log(depthSum([1,[4,[6]]])); // Output: 27
  752. console.log(depthSum([0])); // Output: 0
  753.  
  754. /*
  755. Approach:
  756.  
  757. The problem requires us to traverse a nested list and calculate a weighted sum, where each integer's value is multiplied by its depth within the nested structure. We can solve this efficiently using a recursive approach.
  758.  
  759. Initialization:
  760.  
  761. Initialize totalSum to 0. This variable will store the final result.
  762. Recursive Function calculateDepthSum:
  763.  
  764. This function takes two arguments:
  765. list: The current nested list being processed.
  766. depth: The depth of the current list.
  767. It iterates through each item in the given list:
  768. If item is an integer:
  769. Get the integer value using item.getInteger().
  770. Multiply the integer value by the current depth and add it to totalSum.
  771. If item is a nested list:
  772. Recursively call calculateDepthSum with item.getList() (to process the inner list) and depth + 1 (to increase the depth for the inner list).
  773. Initial Call:
  774.  
  775. Call calculateDepthSum(nestedList, 1) to start the recursion with the outermost nestedList and a depth of 1.
  776. Return Result:
  777.  
  778. Return the totalSum.
  779. Time Complexity:
  780.  
  781. The code visits each element (integer or list) in the nestedList exactly once.
  782. The recursive calls process each nested list.
  783. Therefore, the time complexity is O(N), where N is the total number of elements (integers and lists) in the nestedList.
  784. Space Complexity:
  785.  
  786. The space complexity is determined by the depth of the recursion.
  787. In the worst case, the nested list can have a maximum depth of 50 (as per the constraints).
  788. Therefore, the space complexity is O(D), where D is the maximum depth of the nested list. Since D <= 50, the space complexity is effectively O(1).
  789. */
  790.  
  791. /**
  792.  * // This is the interface that allows for creating nested lists.
  793.  * // You should not implement it yourself.
  794.  *
  795.  * function NestedInteger(value) {
  796.  * // If value is a number, initialize it with an integer value.
  797.  * // Otherwise, initialize it with an empty nested list.
  798.  * this.isInteger = function() {};
  799.  * this.getInteger = function() {};
  800.  * this.getList = function() {};
  801.  * }
  802.  */
  803. /**
  804.  * @param {NestedInteger[]} nestedList
  805.  * @return {number}
  806.  */
  807. function depthSum(nestedList) {
  808.     let totalSum = 0;
  809.  
  810.     function calculateDepthSum(list, depth) {
  811.         for (const item of list) {
  812.             if (item.isInteger()) {
  813.                 totalSum += item.getInteger() * depth;
  814.             } else {
  815.                 calculateDepthSum(item.getList(), depth + 1);
  816.             }
  817.         }
  818.     }
  819.  
  820.     calculateDepthSum(nestedList, 1); // Start with depth 1 for the outermost list
  821.     return totalSum;
  822. }
  823.  
  824. // Helper function to create NestedInteger objects (for testing)
  825. function NestedInteger(value) {
  826.     this.value = value;
  827.     this.list = [];
  828.     this.isInteger = function() {
  829.         return typeof this.value === 'number';
  830.     };
  831.     this.getInteger = function() {
  832.         return this.isInteger() ? this.value : null;
  833.     };
  834.     this.getList = function() {
  835.         return !this.isInteger() ? this.list : [];
  836.     };
  837.  
  838.     if (Array.isArray(value)) {
  839.         this.value = undefined; // Mark as not integer
  840.         this.list = value;
  841.     }
  842. }
  843.  
  844. // Example 1:
  845. const nestedList1 = [
  846.     new NestedInteger([new NestedInteger(1), new NestedInteger(1)]),
  847.     new NestedInteger(2),
  848.     new NestedInteger([new NestedInteger(1), new NestedInteger(1)])
  849. ];
  850. console.log("Example 1:", depthSum(nestedList1)); // Output: 10
  851.  
  852. // Example 2:
  853. const nestedList2 = [
  854.     new NestedInteger(1),
  855.     new NestedInteger([
  856.         new NestedInteger(4),
  857.         new NestedInteger([new NestedInteger(6)])
  858.     ])
  859. ];
  860. console.log("Example 2:", depthSum(nestedList2)); // Output: 27
  861.  
  862. // Example 3:
  863. const nestedList3 = [new NestedInteger(0)];
  864. console.log("Example 3:", depthSum(nestedList3)); // Output: 0
  865.  
  866. // Example 4: Deeply nested list
  867. const nestedList4 = [new NestedInteger([new NestedInteger([new NestedInteger([new NestedInteger(5)])])])];
  868. console.log("Example 4:", depthSum(nestedList4)); // Output: 20
  869.  
  870. // Example 5: Mixed list
  871. const nestedList5 = [new NestedInteger(2), new NestedInteger([new NestedInteger(3), new NestedInteger(4)]), new NestedInteger(5)];
  872. console.log("Example 5:", depthSum(nestedList5)); // Output: 17
  873.  
  874. /* 1249. Minimum Remove to Make Valid Parentheses Medium
  875.  
  876. Given a string s of '(' , ')' and lowercase English characters.
  877.  
  878. Your task is to remove the minimum number of parentheses ( '(' or ')', in any positions ) so that the resulting parentheses string is valid and return any valid string.
  879.  
  880. Formally, a parentheses string is valid if and only if:
  881.  
  882. It is the empty string, contains only lowercase characters, or
  883. It can be written as AB (A concatenated with B), where A and B are valid strings, or
  884. It can be written as (A), where A is a valid string.
  885.  
  886.  
  887. Example 1:
  888.  
  889. Input: s = "lee(t(c)o)de)"
  890. Output: "lee(t(c)o)de"
  891. Explanation: "lee(t(co)de)" , "lee(t(c)ode)" would also be accepted.
  892. Example 2:
  893.  
  894. Input: s = "a)b(c)d"
  895. Output: "ab(c)d"
  896. Example 3:
  897.  
  898. Input: s = "))(("
  899. Output: ""
  900. Explanation: An empty string is also valid.
  901.  
  902.  
  903. Constraints:
  904.  
  905. 1 <= s.length <= 105
  906. s[i] is either '(' , ')', or lowercase English letter.
  907.  
  908. Explanation
  909. Convert String to Array: Since strings are immutable in JavaScript, converting it to an array allows us to modify characters efficiently.
  910.  
  911. First Pass (Left to Right):
  912.  
  913. Use a stack to track indices of unmatched '('.
  914.  
  915. If ')' is found and there's no unmatched '(', mark it for removal.
  916.  
  917. Second Pass (Right to Left):
  918.  
  919. Remove all unmatched '(' left in the stack.
  920.  
  921. Reconstruct the String:
  922.  
  923. Join the array back into a valid string.
  924.  
  925. Time and Space Complexity
  926. Time Complexity: O(N)
  927.  
  928. We traverse the string twice, once to process parentheses and once to reconstruct the string.
  929.  
  930. Space Complexity: O(N)
  931.  
  932. We use an array (arr) of size N and a stack storing unmatched parentheses indices (at most N/2).
  933.  
  934. 🚀 This approach efficiently removes the minimum number of parentheses to make the string valid.
  935. */
  936.  
  937. function minRemoveToMakeValid(s) {
  938.     let stack = [];
  939.     let arr = s.split(""); // Convert string to array for easy modification
  940.  
  941.     // First pass: Mark invalid closing brackets ')'
  942.     for (let i = 0; i < arr.length; i++) {
  943.         if (arr[i] === '(') {
  944.             stack.push(i);
  945.         } else if (arr[i] === ')') {
  946.             if (stack.length > 0) {
  947.                 stack.pop(); // Valid match found
  948.             } else {
  949.                 arr[i] = ''; // Mark invalid ')' for removal
  950.             }
  951.         }
  952.     }
  953.  
  954.     // Second pass: Remove unmatched opening brackets '('
  955.     while (stack.length > 0) {
  956.         arr[stack.pop()] = '';
  957.     }
  958.  
  959.     return arr.join(""); // Reconstruct the valid string
  960. }
  961.  
  962. // Example Test Cases
  963. console.log(minRemoveToMakeValid("lee(t(c)o)de)")); // Output: "lee(t(c)o)de"
  964. console.log(minRemoveToMakeValid("a)b(c)d"));       // Output: "ab(c)d"
  965. console.log(minRemoveToMakeValid("))(("));         // Output: ""
  966.  
  967.  
  968.  
  969. /* 1650. Lowest Common Ancestor of a Binary Tree III Medium
  970.  
  971. Given two nodes of a binary tree p and q, return their lowest common ancestor (LCA).
  972.  
  973. Each node will have a reference to its parent node. The definition for Node is below:
  974.  
  975. class Node {
  976.     public int val;
  977.     public Node left;
  978.     public Node right;
  979.     public Node parent;
  980. }
  981. According to the definition of LCA on Wikipedia: "The lowest common ancestor of two nodes p and q in a tree T is the lowest node that has both p and q as descendants (where we allow a node to be a descendant of itself)."
  982.  
  983. Example 1:
  984.  
  985.         3
  986.        / \
  987.       5   1
  988.      / \  / \
  989.     6   2 0  8
  990.        / \
  991.       7   4
  992.  
  993. Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
  994. Output: 3
  995. Explanation: The LCA of nodes 5 and 1 is 3.
  996.  
  997. Example 2:
  998.  
  999.         3
  1000.        / \
  1001.       5   1
  1002.      / \  / \
  1003.     6   2 0  8
  1004.        / \
  1005.       7   4
  1006.  
  1007. Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
  1008. Output: 5
  1009. Explanation: The LCA of nodes 5 and 4 is 5 since a node can be a descendant of itself according to the LCA definition.
  1010.  
  1011. Example 3:
  1012.  
  1013.     1
  1014.    /
  1015.   2
  1016.  
  1017. Input: root = [1,2], p = 1, q = 2
  1018. Output: 1
  1019.  
  1020.  
  1021. Constraints:
  1022.  
  1023. The number of nodes in the tree is in the range [2, 105].
  1024. -109 <= Node.val <= 109
  1025. All Node.val are unique.
  1026. p != q
  1027. p and q exist in the tree.
  1028.  
  1029.  
  1030. JavaScript Solution: Lowest Common Ancestor (LCA) of Two Nodes in a Binary Tree
  1031. Since each node has a reference to its parent, we can find the Lowest Common Ancestor (LCA) efficiently by moving up the tree.
  1032.  
  1033. Approach
  1034. Use Two Pointers (p and q)
  1035.  
  1036. Start from p and q, moving their parents upward.
  1037.  
  1038. If one pointer reaches the root (null), reset it to the other node.
  1039.  
  1040. When p === q, we have found the LCA.
  1041.  
  1042. Why This Works?
  1043.  
  1044. This approach ensures that both pointers traverse the same distance.
  1045.  
  1046. If p and q have different depths, switching the pointer after reaching null balances the paths.
  1047.  
  1048. When they meet, it's guaranteed to be the LCA.
  1049.  
  1050. Time and Space Complexity
  1051. Time Complexity: O(H)
  1052.  
  1053. H is the height of the tree.
  1054.  
  1055. Each node is visited at most twice.
  1056.  
  1057. Space Complexity: O(1)
  1058.  
  1059. Uses only constant extra space since we are not using recursion or additional data structures.
  1060.  
  1061. 🚀 This is an efficient approach using parent pointers, ensuring an optimal O(H) complexity!
  1062.  
  1063. */
  1064.  
  1065. class Node {
  1066.     constructor(val, parent = null, left = null, right = null) {
  1067.         this.val = val;
  1068.         this.parent = parent;
  1069.         this.left = left;
  1070.         this.right = right;
  1071.     }
  1072. }
  1073.  
  1074. function lowestCommonAncestor(p, q) {
  1075.     let a = p, b = q;
  1076.    
  1077.     while (a !== b) {
  1078.         a = a ? a.parent : q;
  1079.         b = b ? b.parent : p;
  1080.     }
  1081.    
  1082.     return a; // or return b, both are the same
  1083. }
  1084.  
  1085. // Example Test Case
  1086. let root = new Node(3);
  1087. let node5 = new Node(5, root);
  1088. let node1 = new Node(1, root);
  1089. let node6 = new Node(6, node5);
  1090. let node2 = new Node(2, node5);
  1091. let node0 = new Node(0, node1);
  1092. let node8 = new Node(8, node1);
  1093. let node7 = new Node(7, node2);
  1094. let node4 = new Node(4, node2);
  1095.  
  1096. root.left = node5;
  1097. root.right = node1;
  1098. node5.left = node6;
  1099. node5.right = node2;
  1100. node1.left = node0;
  1101. node1.right = node8;
  1102. node2.left = node7;
  1103. node2.right = node4;
  1104.  
  1105. console.log(lowestCommonAncestor(node5, node1).val); // Output: 3
  1106. console.log(lowestCommonAncestor(node5, node4).val); // Output: 5
  1107. console.log(lowestCommonAncestor(root, node2).val);  // Output: 3
  1108.  
  1109.  
  1110. /*
  1111. Changes & Improvements
  1112. Function Signature Matches Your Request 🎯
  1113.  
  1114. Now accepts array representation of the tree and two integer values for p and q.
  1115.  
  1116. Internally Builds the Tree 🌳
  1117.  
  1118. Uses buildTree(arr) to create a binary tree with parent pointers.
  1119.  
  1120. Finds Nodes in the Tree 🔎
  1121.  
  1122. Uses findNode(root, val) to locate p and q.
  1123.  
  1124. Computes LCA Using Two-Pointer Approach 🚀
  1125.  
  1126. Efficiently finds LCA in O(H) time with O(1) extra space.
  1127.  
  1128. Time & Space Complexity
  1129. Operation   Time Complexity Space Complexity
  1130. Building Tree   O(N)    O(N)
  1131. Finding Node    O(N)    O(H) (Recursion)
  1132. Finding LCA O(H)    O(1)
  1133. Overall Complexity  O(N)    O(N)
  1134. ✅  🚀
  1135. */
  1136.  
  1137.  
  1138. class Node {
  1139.     constructor(val, parent = null) {
  1140.         this.val = val;
  1141.         this.parent = parent;
  1142.         this.left = null;
  1143.         this.right = null;
  1144.     }
  1145. }
  1146.  
  1147. // Function to build a binary tree from an array representation
  1148. function buildTree(arr) {
  1149.     if (!arr.length) return null;
  1150.    
  1151.     let nodes = arr.map(val => (val !== null ? new Node(val) : null));
  1152.    
  1153.     for (let i = 0; i < arr.length; i++) {
  1154.         if (nodes[i] !== null) {
  1155.             let leftIndex = 2 * i + 1;
  1156.             let rightIndex = 2 * i + 2;
  1157.            
  1158.             if (leftIndex < arr.length && nodes[leftIndex] !== null) {
  1159.                 nodes[i].left = nodes[leftIndex];
  1160.                 nodes[leftIndex].parent = nodes[i]; // Set parent reference
  1161.             }
  1162.             if (rightIndex < arr.length && nodes[rightIndex] !== null) {
  1163.                 nodes[i].right = nodes[rightIndex];
  1164.                 nodes[rightIndex].parent = nodes[i]; // Set parent reference
  1165.             }
  1166.         }
  1167.     }
  1168.     return nodes[0]; // Return root
  1169. }
  1170.  
  1171. // Function to find a node in the tree by value
  1172. function findNode(root, val) {
  1173.     if (!root) return null;
  1174.     if (root.val === val) return root;
  1175.     return findNode(root.left, val) || findNode(root.right, val);
  1176. }
  1177.  
  1178. // Modified lowestCommonAncestor function
  1179. function lowestCommonAncestor(arr, val1, val2) {
  1180.     let root = buildTree(arr);
  1181.     let p = findNode(root, val1);
  1182.     let q = findNode(root, val2);
  1183.    
  1184.     if (!p || !q) return null; // Edge case if nodes are not found
  1185.  
  1186.     let a = p, b = q;
  1187.    
  1188.     while (a !== b) {
  1189.         a = a ? a.parent : q;
  1190.         b = b ? b.parent : p;
  1191.     }
  1192.    
  1193.     return a.val; // Return LCA value
  1194. }
  1195.  
  1196. // Example Test Cases
  1197.  
  1198. // Example 1
  1199. console.log(lowestCommonAncestor([3,5,1,6,2,0,8,null,null,7,4], 5, 1)); // Output: 3
  1200.  
  1201. // Example 2
  1202. console.log(lowestCommonAncestor([3,5,1,6,2,0,8,null,null,7,4], 5, 4)); // Output: 5
  1203.  
  1204. // Example 3
  1205. console.log(lowestCommonAncestor([1,2], 1, 2)); // Output: 1
  1206.  
  1207.  
  1208. /* =================================
  1209. 227. Basic Calculator II M
  1210.  
  1211. Given a string s which represents an expression, evaluate this expression and return its value.
  1212.  
  1213. The integer division should truncate toward zero.
  1214.  
  1215. You may assume that the given expression is always valid. All intermediate results will be in the range of [-231, 231 - 1].
  1216.  
  1217. Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().
  1218.  
  1219. Example 1:
  1220.  
  1221. Input: s = "3+2*2"
  1222. Output: 7
  1223. Example 2:
  1224.  
  1225. Input: s = " 3/2 "
  1226. Output: 1
  1227. Example 3:
  1228.  
  1229. Input: s = " 3+5 / 2 "
  1230. Output: 5
  1231.  
  1232.  
  1233. Constraints:
  1234.  
  1235. 1 <= s.length <= 3 * 105
  1236. s consists of integers and operators ('+', '-', '*', '/') separated by some number of spaces.
  1237. s represents a valid expression.
  1238. All the integers in the expression are non-negative integers in the range [0, 231 - 1].
  1239. The answer is guaranteed to fit in a 32-bit integer.
  1240.  
  1241. */
  1242.  
  1243. function calculate(s) {
  1244.     let stack = [];
  1245.     let num = 0;
  1246.     let sign = '+';
  1247.     s = s.replace(/\s+/g, ''); // Remove spaces for easier parsing
  1248.  
  1249.     for (let i = 0; i < s.length; i++) {
  1250.         let char = s[i];
  1251.  
  1252.         if (!isNaN(char)) {
  1253.             num = num * 10 + (char - '0'); // Build multi-digit numbers
  1254.         }
  1255.  
  1256.         if (isNaN(char) || i === s.length - 1) {
  1257.             if (sign === '+') {
  1258.                 stack.push(num);
  1259.             } else if (sign === '-') {
  1260.                 stack.push(-num);
  1261.             } else if (sign === '*') {
  1262.                 stack.push(stack.pop() * num);
  1263.             } else if (sign === '/') {
  1264.                 stack.push(Math.trunc(stack.pop() / num)); // Truncate towards zero
  1265.             }
  1266.  
  1267.             sign = char; // Update sign to the new operator
  1268.             num = 0; // Reset number for next iteration
  1269.         }
  1270.     }
  1271.  
  1272.     return stack.reduce((acc, val) => acc + val, 0);
  1273. }
  1274.  
  1275. // **Example Test Cases**
  1276. console.log(calculate("3+2*2"));    // Output: 7
  1277. console.log(calculate(" 3/2 "));    // Output: 1
  1278. console.log(calculate(" 3+5 / 2 ")); // Output: 5
  1279. /*
  1280. The approach utilizes a stack-based method to handle multiplication and division before addition and subtraction.
  1281.  
  1282. Approach
  1283. Use a stack to store numbers while processing the expression.
  1284.  
  1285. Iterate through the string character by character:
  1286.  
  1287. If the character is a digit, extract the full number.
  1288.  
  1289. If the character is an operator (+, -, *, /), process the last number accordingly:
  1290.  
  1291. Push addition (+) and subtraction (-) directly into the stack.
  1292.  
  1293. Apply multiplication (*) and division (/) immediately with the last number in the stack.
  1294.  
  1295. Sum all values in the stack to get the final result.
  1296.  
  1297. Time & Space Complexity
  1298. Time Complexity: O(n) → Each character is processed once.
  1299.  
  1300. Space Complexity: O(n) in the worst case (if all numbers are stored in the stack).
  1301. */
  1302.  
  1303. function calculate(s) {
  1304.     let stack = [];
  1305.     let num = 0;
  1306.     let sign = '+'; // Default operator
  1307.     let n = s.length;
  1308.  
  1309.     for (let i = 0; i < n; i++) {
  1310.         let char = s[i];
  1311.  
  1312.         // Build full number
  1313.         if (char >= '0' && char <= '9') {
  1314.             num = num * 10 + (char - '0');
  1315.         }
  1316.  
  1317.         // If current char is an operator or we are at the last character
  1318.         if ((char < '0' || char > '9') && char !== ' ' || i === n - 1) {
  1319.             if (sign === '+') {
  1320.                 stack.push(num);
  1321.             } else if (sign === '-') {
  1322.                 stack.push(-num);
  1323.             } else if (sign === '*') {
  1324.                 let last = stack.pop();
  1325.                 stack.push(last * num);
  1326.             } else if (sign === '/') {
  1327.                 let last = stack.pop();
  1328.                 let result = last / num;
  1329.  
  1330.                 // stack.push(Math.trunc(stack.pop() / num)); // Truncate towards zero
  1331.                 // stack.push(last > 0 ? Math.floor(result) : Math.ceil(result)); // Manual truncation
  1332.  
  1333.                 // **Manual truncation towards zero**
  1334.                 if (result < 0) {
  1335.                     stack.push(result | 0); // Bitwise OR with zero truncates decimal part
  1336.                 } else {
  1337.                     stack.push(result - (result % 1)); // Remove decimal part manually
  1338.                 }
  1339.             }
  1340.  
  1341.             sign = char; // Update operator
  1342.             num = 0; // Reset number
  1343.         }
  1344.     }
  1345.  
  1346.     // Manually sum the stack values
  1347.     let result = 0;
  1348.     for (let val of stack) {
  1349.         result += val;
  1350.     }
  1351.  
  1352.     return result;
  1353. }
  1354.  
  1355. // **Example Test Cases**
  1356. console.log(calculate("3+2*2"));    // Output: 7
  1357. console.log(calculate(" 3/2 "));    // Output: 1
  1358. console.log(calculate(" 3+5 / 2 ")); // Output: 5
  1359. console.log(calculate("14-3/2"));  // Output: 13
  1360. console.log(calculate("10/3"));    // Output: 3
  1361. console.log(calculate("-10/3"));   // Output: -3
  1362.  
  1363.  
  1364. /* =================================
  1365.  
  1366. 680. Valid Palindrome II Easy
  1367. Given a string s, return true if the s can be palindrome after deleting at most one character from it.
  1368.  
  1369. Example 1:
  1370.  
  1371. Input: s = "aba"
  1372. Output: true
  1373. Example 2:
  1374.  
  1375. Input: s = "abca"
  1376. Output: true
  1377. Explanation: You could delete the character 'c'.
  1378. Example 3:
  1379.  
  1380. Input: s = "abc"
  1381. Output: false
  1382.  
  1383.  
  1384. Constraints:
  1385.  
  1386. 1 <= s.length <= 105
  1387. s consists of lowercase English letters.
  1388.  
  1389. Approach
  1390. Use a two-pointer approach to check for palindrome.
  1391.  
  1392. If a mismatch is found, try removing either the left or right character and check if the remaining substring is a palindrome.
  1393.  
  1394. This ensures we only delete at most one character.
  1395.  
  1396. Time & Space Complexity
  1397. Time Complexity: O(n) (single pass for checking + one more pass in case of a mismatch)
  1398.  
  1399. Space Complexity: O(1) (no extra space used, only pointers)
  1400.  
  1401. */
  1402.  
  1403. function validPalindrome(s) {
  1404.     function isPalindrome(l, r) {
  1405.         while (l < r) {
  1406.             if (s[l] !== s[r]) return false;
  1407.             l++;
  1408.             r--;
  1409.         }
  1410.         return true;
  1411.     }
  1412.  
  1413.     let left = 0, right = s.length - 1;
  1414.    
  1415.     while (left < right) {
  1416.         if (s[left] !== s[right]) {
  1417.             // Try removing either left or right character and check palindrome
  1418.             return isPalindrome(left + 1, right) || isPalindrome(left, right - 1);
  1419.         }
  1420.         left++;
  1421.         right--;
  1422.     }
  1423.    
  1424.     return true;
  1425. }
  1426.  
  1427. // **Example Test Cases**
  1428. console.log(validPalindrome("aba"));   // Output: true
  1429. console.log(validPalindrome("abca"));  // Output: true
  1430. console.log(validPalindrome("abc"));   // Output: false
  1431. console.log(validPalindrome("racecar")); // Output: true
  1432. console.log(validPalindrome("deeee"));  // Output: true
  1433. console.log(validPalindrome("abcddcba"));  // Output: true
  1434. console.log(validPalindrome("abcdedcba")); // Output: true
  1435.  
  1436. /* =================================
  1437.  
  1438. 1762. Buildings With an Ocean View Medium
  1439.  
  1440. There are n buildings in a line. You are given an integer array heights of size n that represents the heights of the buildings in the line.
  1441.  
  1442. The ocean is to the right of the buildings. A building has an ocean view if the building can see the ocean without obstructions. Formally, a building has an ocean view if all the buildings to its right have a smaller height.
  1443.  
  1444. Return a list of indices (0-indexed) of buildings that have an ocean view, sorted in increasing order.
  1445.  
  1446. Example 1:
  1447.  
  1448. Input: heights = [4,2,3,1]
  1449. Output: [0,2,3]
  1450. Explanation: Building 1 (0-indexed) does not have an ocean view because building 2 is taller.
  1451. Example 2:
  1452.  
  1453. Input: heights = [4,3,2,1]
  1454. Output: [0,1,2,3]
  1455. Explanation: All the buildings have an ocean view.
  1456. Example 3:
  1457.  
  1458. Input: heights = [1,3,2,4]
  1459. Output: [3]
  1460. Explanation: Only building 3 has an ocean view.
  1461.  
  1462. Constraints:
  1463.  
  1464. 1 <= heights.length <= 105
  1465. 1 <= heights[i] <= 109
  1466.  
  1467. */
  1468.  
  1469. function findBuildings(heights) {
  1470.     let result = [];
  1471.     let maxSoFar = -Infinity;
  1472.  
  1473.     for (let i = heights.length - 1; i >= 0; i--) {
  1474.         if (heights[i] > maxSoFar) {
  1475.             result.push(i);
  1476.             maxSoFar = heights[i];
  1477.         }
  1478.     }
  1479.  
  1480.     return result.reverse(); // Sorting in increasing order of indices
  1481.  
  1482.     /* Manually reversing the array
  1483.     let left = 0, right = result.length - 1;
  1484.     while (left < right) {
  1485.         [result[left], result[right]] = [result[right], result[left]];
  1486.         left++;
  1487.         right--;
  1488.     }
  1489.  
  1490.     return result;
  1491.     */
  1492. }
  1493.  
  1494. // **Example Test Cases**
  1495. console.log(findBuildings([4, 2, 3, 1])); // Output: [0, 2, 3]
  1496. console.log(findBuildings([4, 3, 2, 1])); // Output: [0, 1, 2, 3]
  1497. console.log(findBuildings([1, 3, 2, 4])); // Output: [3]
  1498. console.log(findBuildings([10, 8, 6, 4, 2])); // Output: [0, 1, 2, 3, 4]
  1499. console.log(findBuildings([2, 3, 4, 5, 1])); // Output: [3, 4]
  1500.  
  1501. /*
  1502. Time & Space Complexity
  1503. Time Complexity: O(n) (single pass from right to left)
  1504.  
  1505. Space Complexity: O(n) (to store the indices of valid buildings)
  1506.  
  1507. This approach ensures efficient traversal while keeping the logic simple and easy to follow! 🚀
  1508. */
  1509.  
  1510.  
  1511. /* =================================
  1512.  
  1513. 1570. Dot Product of Two Sparse Vectors Medium
  1514.  
  1515. Given two sparse vectors, compute their dot product.
  1516.  
  1517. Implement class SparseVector:
  1518.  
  1519. SparseVector(nums) Initializes the object with the vector nums
  1520. dotProduct(vec) Compute the dot product between the instance of SparseVector and vec
  1521. A sparse vector is a vector that has mostly zero values, you should store the sparse vector efficiently and compute the dot product between two SparseVector.
  1522.  
  1523. Follow up: What if only one of the vectors is sparse?
  1524.  
  1525. Example 1:
  1526.  
  1527. Input: nums1 = [1,0,0,2,3], nums2 = [0,3,0,4,0]
  1528. Output: 8
  1529. Explanation: v1 = SparseVector(nums1) , v2 = SparseVector(nums2)
  1530. v1.dotProduct(v2) = 1*0 + 0*3 + 0*0 + 2*4 + 3*0 = 8
  1531. Example 2:
  1532.  
  1533. Input: nums1 = [0,1,0,0,0], nums2 = [0,0,0,0,2]
  1534. Output: 0
  1535. Explanation: v1 = SparseVector(nums1) , v2 = SparseVector(nums2)
  1536. v1.dotProduct(v2) = 0*0 + 1*0 + 0*0 + 0*0 + 0*2 = 0
  1537. Example 3:
  1538.  
  1539. Input: nums1 = [0,1,0,0,2,0,0], nums2 = [1,0,0,0,3,0,4]
  1540. Output: 6
  1541.  
  1542.  
  1543. Constraints:
  1544.  
  1545. n == nums1.length == nums2.length
  1546. 1 <= n <= 10^5
  1547. 0 <= nums1[i], nums2[i] <= 100
  1548.  
  1549. Approach
  1550. Since the vectors are sparse (mostly zeros), storing all elements wastes space. Instead, we use a dictionary (object) or a map to store only non-zero elements with their indices. This reduces space complexity significantly.
  1551.  
  1552. For computing the dot product, we:
  1553.  
  1554. Iterate over the smaller sparse representation to minimize operations.
  1555.  
  1556. Multiply values where indices match.
  1557.  
  1558. Sum the results.
  1559.  
  1560. Time & Space Complexity
  1561. Initialization: O(n) (storing only non-zero elements)
  1562.  
  1563. Dot Product: O(min(N1, N2)) where N1, N2 are the non-zero elements count.
  1564.  
  1565. Space Complexity: O(N1 + N2) (storing only non-zero elements)
  1566.  
  1567. This approach efficiently handles large vectors while minimizing operations! 🚀
  1568.  
  1569. */
  1570.  
  1571. class SparseVector {
  1572.     constructor(nums) {
  1573.         this.sparseMap = new Map();
  1574.         for (let i = 0; i < nums.length; i++) {
  1575.             if (nums[i] !== 0) {
  1576.                 this.sparseMap.set(i, nums[i]);
  1577.             }
  1578.         }
  1579.     }
  1580.  
  1581.     dotProduct(vec) {
  1582.         let result = 0;
  1583.         // Iterate over the smaller sparse vector for efficiency
  1584.         let smaller = this.sparseMap.size <= vec.sparseMap.size ? this.sparseMap : vec.sparseMap;
  1585.         let larger = this.sparseMap.size > vec.sparseMap.size ? this.sparseMap : vec.sparseMap;
  1586.  
  1587.         for (let [index, value] of smaller) {
  1588.             if (larger.has(index)) {
  1589.                 result += value * larger.get(index);
  1590.             }
  1591.         }
  1592.         return result;
  1593.     }
  1594. }
  1595.  
  1596. // **Example Test Cases**
  1597. let v1 = new SparseVector([1, 0, 0, 2, 3]);
  1598. let v2 = new SparseVector([0, 3, 0, 4, 0]);
  1599. console.log(v1.dotProduct(v2)); // Output: 8
  1600.  
  1601. let v3 = new SparseVector([0, 1, 0, 0, 0]);
  1602. let v4 = new SparseVector([0, 0, 0, 0, 2]);
  1603. console.log(v3.dotProduct(v4)); // Output: 0
  1604.  
  1605. let v5 = new SparseVector([0, 1, 0, 0, 2, 0, 0]);
  1606. let v6 = new SparseVector([1, 0, 0, 0, 3, 0, 4]);
  1607. console.log(v5.dotProduct(v6)); // Output: 6
  1608.  
  1609.  
  1610. /* =================================
  1611. 528. Random Pick with Weight Medium
  1612.  
  1613. You are given a 0-indexed array of positive integers w where w[i] describes the weight of the ith index.
  1614.  
  1615. You need to implement the function pickIndex(), which randomly picks an index in the range [0, w.length - 1] (inclusive) and returns it. The probability of picking an index i is w[i] / sum(w).
  1616.  
  1617. For example, if w = [1, 3], the probability of picking index 0 is 1 / (1 + 3) = 0.25 (i.e., 25%), and the probability of picking index 1 is 3 / (1 + 3) = 0.75 (i.e., 75%).
  1618.  
  1619.  
  1620. Example 1:
  1621.  
  1622. Input
  1623. ["Solution","pickIndex"]
  1624. [[[1]],[]]
  1625. Output
  1626. [null,0]
  1627.  
  1628. Explanation
  1629. Solution solution = new Solution([1]);
  1630. solution.pickIndex(); // return 0. The only option is to return 0 since there is only one element in w.
  1631. Example 2:
  1632.  
  1633. Input
  1634. ["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"]
  1635. [[[1,3]],[],[],[],[],[]]
  1636. Output
  1637. [null,1,1,1,1,0]
  1638.  
  1639. Explanation
  1640. Solution solution = new Solution([1, 3]);
  1641. solution.pickIndex(); // return 1. It is returning the second element (index = 1) that has a probability of 3/4.
  1642. solution.pickIndex(); // return 1
  1643. solution.pickIndex(); // return 1
  1644. solution.pickIndex(); // return 1
  1645. solution.pickIndex(); // return 0. It is returning the first element (index = 0) that has a probability of 1/4.
  1646.  
  1647. Since this is a randomization problem, multiple answers are allowed.
  1648. All of the following outputs can be considered correct:
  1649. [null,1,1,1,1,0]
  1650. [null,1,1,1,1,1]
  1651. [null,1,1,1,0,0]
  1652. [null,1,1,1,0,1]
  1653. [null,1,0,1,0,0]
  1654. ......
  1655. and so on.
  1656.  
  1657.  
  1658. Constraints:
  1659.  
  1660. 1 <= w.length <= 104
  1661. 1 <= w[i] <= 105
  1662. pickIndex will be called at most 104 times.
  1663.  
  1664.  
  1665. Approach
  1666. We need to pick an index randomly based on the given weights, ensuring that index i is picked with probability w[i] / sum(w). The best way to achieve this efficiently is by using the prefix sum + binary search approach.
  1667.  
  1668. Steps
  1669. Precompute prefix sums:
  1670.  
  1671. Convert w into a prefix sum array:
  1672. prefix[i] = w[0] + w[1] + ... + w[i]
  1673.  
  1674. This allows us to map ranges of numbers to indices.
  1675.  
  1676. Pick a random number:
  1677.  
  1678. Generate a random number rand in the range [1, sum(w)].
  1679.  
  1680. Find the corresponding index using binary search:
  1681.  
  1682. Use binary search (lower_bound) to find the smallest prefix sum that is greater than or equal to rand.
  1683.  
  1684. The index where it appears is the selected index.
  1685.  
  1686. This method ensures O(log n) lookup time for pickIndex(), making it efficient even for large inputs.
  1687.  
  1688. Time & Space Complexity
  1689. Constructor (Solution(w)):
  1690.  
  1691. Time Complexity: O(n) (building prefix sum)
  1692.  
  1693. Space Complexity: O(n) (storing prefix sums)
  1694.  
  1695. pickIndex():
  1696.  
  1697. Time Complexity: O(log n) (binary search)
  1698.  
  1699. Space Complexity: O(1) (constant extra space)
  1700.  
  1701. This approach is efficient and scales well for large inputs. 🚀
  1702.  
  1703. */
  1704. class Solution {
  1705.     constructor(w) {
  1706.         this.prefixSums = [];
  1707.         this.totalSum = 0;
  1708.  
  1709.         for (let weight of w) {
  1710.             this.totalSum += weight;
  1711.             this.prefixSums.push(this.totalSum);
  1712.         }
  1713.     }
  1714.  
  1715.     pickIndex() {
  1716.         let rand = Math.random() * this.totalSum;
  1717.         let left = 0, right = this.prefixSums.length - 1;
  1718.  
  1719.         while (left < right) {
  1720.             let mid = Math.floor((left + right) / 2);
  1721.             if (this.prefixSums[mid] > rand) {
  1722.                 right = mid;
  1723.             } else {
  1724.                 left = mid + 1;
  1725.             }
  1726.         }
  1727.         return left;
  1728.     }
  1729. }
  1730.  
  1731. // **Example Test Cases**
  1732. let solution1 = new Solution([1]);
  1733. console.log(solution1.pickIndex()); // Always 0
  1734.  
  1735. let solution2 = new Solution([1, 3]);
  1736. console.log(solution2.pickIndex()); // Should return 0 ~25% of the time, 1 ~75% of the time
  1737.  
  1738.  
  1739. class Solution {
  1740.     constructor(w) {
  1741.         this.prefixSums = [];
  1742.         this.totalSum = 0;
  1743.         this.seed = 123456789; // Initial seed for randomness
  1744.  
  1745.         for (let weight of w) {
  1746.             this.totalSum += weight;
  1747.             this.prefixSums.push(this.totalSum);
  1748.         }
  1749.     }
  1750.  
  1751.     // Custom random number generator (LCG)
  1752.     randomLCG() {
  1753.         this.seed = (this.seed * 1664525 + 1013904223) % (2 ** 32);
  1754.         return this.seed / (2 ** 32); // Normalize to [0,1)
  1755.     }
  1756.  
  1757.     // Integer division without Math.floor()
  1758.     intDiv(a, b) {
  1759.         return (a - (a % b)) / b;
  1760.     }
  1761.  
  1762.     pickIndex() {
  1763.         let rand = this.randomLCG() * this.totalSum;
  1764.         let left = 0, right = this.prefixSums.length - 1;
  1765.  
  1766.         while (left < right) {
  1767.             let mid = this.intDiv(left + right, 2); // Using custom integer division
  1768.             if (this.prefixSums[mid] > rand) {
  1769.                 right = mid;
  1770.             } else {
  1771.                 left = mid + 1;
  1772.             }
  1773.         }
  1774.         return left;
  1775.     }
  1776. }
  1777.  
  1778. // **Example Test Cases**
  1779. let solution1 = new Solution([1]);
  1780. console.log(solution1.pickIndex()); // Always 0
  1781.  
  1782. let solution2 = new Solution([1, 3]);
  1783. console.log(solution2.pickIndex()); // Should return 0 ~25% of the time, 1 ~75% of the time
  1784.  
  1785.  
  1786. /* =========================
  1787. 938. Range Sum of BST Easy
  1788.  
  1789. Given the root node of a binary search tree and two integers low and high, return the sum of values of all nodes with a value in the inclusive range [low, high].
  1790.  
  1791.  
  1792.  
  1793. Example 1:
  1794.  
  1795.        10
  1796.       /  \
  1797.      5    15
  1798.     / \     \
  1799.    3   7     18
  1800.  
  1801. Input: root = [10,5,15,3,7,null,18], low = 7, high = 15
  1802. Output: 32
  1803. Explanation: Nodes 7, 10, and 15 are in the range [7, 15]. 7 + 10 + 15 = 32.
  1804.  
  1805. Example 2:
  1806.  
  1807.         10
  1808.        /  \
  1809.       5    15
  1810.      / \   /  \
  1811.     3   7 13  18
  1812.    /   /
  1813.   1   6
  1814.  
  1815. Input: root = [10,5,15,3,7,13,18,1,null,6], low = 6, high = 10
  1816. Output: 23
  1817. Explanation: Nodes 6, 7, and 10 are in the range [6, 10]. 6 + 7 + 10 = 23.
  1818.  
  1819.  
  1820. Constraints:
  1821.  
  1822. The number of nodes in the tree is in the range [1, 2 * 104].
  1823. 1 <= Node.val <= 105
  1824. 1 <= low <= high <= 105
  1825. All Node.val are unique.
  1826.  
  1827.  
  1828. Here is an efficient JavaScript implementation for summing all the nodes in a Binary Search Tree (BST) that fall within the given range [low, high].
  1829.  
  1830. Approach
  1831. Since it is a BST, we can avoid unnecessary recursion:
  1832.  
  1833. If node.val < low: Only explore the right subtree.
  1834.  
  1835. If node.val > high: Only explore the left subtree.
  1836.  
  1837. Otherwise, include node.val and explore both subtrees.
  1838.  
  1839. This reduces the number of recursive calls, making it more efficient than a brute-force traversal.
  1840.  
  1841.  
  1842. Time & Space Complexity
  1843. Time Complexity:
  1844.  
  1845. O(n) in the worst case (if the tree is a linked list).
  1846.  
  1847. O(log n) in the average case (if the tree is balanced).
  1848.  
  1849. Space Complexity:
  1850.  
  1851. O(h) due to recursion stack, where h is the tree height (O(log n) for balanced, O(n) for skewed).
  1852.  
  1853. This implementation efficiently finds the sum of node values within the range [low, high] in a BST. 🚀
  1854.  
  1855. */
  1856.  
  1857. class TreeNode {
  1858.     constructor(val, left = null, right = null) {
  1859.         this.val = val;
  1860.         this.left = left;
  1861.         this.right = right;
  1862.     }
  1863. }
  1864.  
  1865. function rangeSumBST(root, low, high) {
  1866.     if (!root) return 0;
  1867.    
  1868.     if (root.val < low) {
  1869.         return rangeSumBST(root.right, low, high);
  1870.     }
  1871.     if (root.val > high) {
  1872.         return rangeSumBST(root.left, low, high);
  1873.     }
  1874.    
  1875.     return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high);
  1876. }
  1877.  
  1878. // **Example 1**
  1879. let root1 = new TreeNode(10,
  1880.     new TreeNode(5, new TreeNode(3), new TreeNode(7)),
  1881.     new TreeNode(15, null, new TreeNode(18))
  1882. );
  1883. console.log(rangeSumBST(root1, 7, 15)); // Output: 32
  1884.  
  1885. // **Example 2**
  1886. let root2 = new TreeNode(10,
  1887.     new TreeNode(5, new TreeNode(3, new TreeNode(1)), new TreeNode(7, new TreeNode(6))),
  1888.     new TreeNode(15, new TreeNode(13), new TreeNode(18))
  1889. );
  1890. console.log(rangeSumBST(root2, 6, 10)); // Output: 23
  1891.  
  1892.  
  1893. /* ===============================
  1894.  
  1895. 215. Kth Largest Element in an Array Medium
  1896.  
  1897. Given an integer array nums and an integer k, return the kth largest element in the array.
  1898.  
  1899. Note that it is the kth largest element in the sorted order, not the kth distinct element.
  1900.  
  1901. Can you solve it without sorting?
  1902.  
  1903. Example 1:
  1904.  
  1905. Input: nums = [3,2,1,5,6,4], k = 2
  1906. Output: 5
  1907. Example 2:
  1908.  
  1909. Input: nums = [3,2,3,1,2,4,5,5,6], k = 4
  1910. Output: 4
  1911.  
  1912. Constraints:
  1913.  
  1914. 1 <= k <= nums.length <= 105
  1915. -104 <= nums[i] <= 104
  1916.  
  1917.  
  1918.  
  1919. You can solve this efficiently without sorting the entire array by using a Min Heap of size k. This ensures the kth largest element is always at the top of the heap.
  1920.  
  1921. ✅ Approach: Min Heap (Priority Queue)
  1922. Keep a min-heap of the top k elements seen so far.
  1923.  
  1924. If the size exceeds k, pop the smallest.
  1925.  
  1926. The top of the heap will be the kth largest.
  1927.  
  1928. 🧠 Why this works:
  1929. The heap always contains the k largest elements from the array.
  1930.  
  1931. The smallest among them (heap top) is the kth largest overall.
  1932.  
  1933.  
  1934.  
  1935. 🕒 Time Complexity:
  1936. O(n log k) where n is nums.length, because each insert/pop operation in the heap of size k takes log k.
  1937.  
  1938. 📦 Space Complexity:
  1939. O(k) for the heap.
  1940. */
  1941.  
  1942. class MinHeap {
  1943.     constructor() {
  1944.         this.heap = [];
  1945.     }
  1946.  
  1947.     push(val) {
  1948.         this.heap.push(val);
  1949.         this._heapifyUp();
  1950.     }
  1951.  
  1952.     pop() {
  1953.         if (this.size() <= 1) return this.heap.pop();
  1954.         const top = this.heap[0];
  1955.         this.heap[0] = this.heap.pop();
  1956.         this._heapifyDown();
  1957.         return top;
  1958.     }
  1959.  
  1960.     peek() {
  1961.         return this.heap[0];
  1962.     }
  1963.  
  1964.     size() {
  1965.         return this.heap.length;
  1966.     }
  1967.  
  1968.     _heapifyUp() {
  1969.         let i = this.heap.length - 1;
  1970.         while (i > 0) {
  1971.             const parent = Math.floor((i - 1) / 2);
  1972.             if (this.heap[i] >= this.heap[parent]) break;
  1973.             [this.heap[i], this.heap[parent]] = [this.heap[parent], this.heap[i]];
  1974.             i = parent;
  1975.         }
  1976.     }
  1977.  
  1978.     _heapifyDown() {
  1979.         let i = 0;
  1980.         const n = this.heap.length;
  1981.         while (true) {
  1982.             let left = 2 * i + 1, right = 2 * i + 2;
  1983.             let smallest = i;
  1984.  
  1985.             if (left < n && this.heap[left] < this.heap[smallest]) smallest = left;
  1986.             if (right < n && this.heap[right] < this.heap[smallest]) smallest = right;
  1987.  
  1988.             if (smallest === i) break;
  1989.  
  1990.             [this.heap[i], this.heap[smallest]] = [this.heap[smallest], this.heap[i]];
  1991.             i = smallest;
  1992.         }
  1993.     }
  1994. }
  1995.  
  1996. function findKthLargest(nums, k) {
  1997.     const heap = new MinHeap();
  1998.  
  1999.     for (let num of nums) {
  2000.         heap.push(num);
  2001.         if (heap.size() > k) heap.pop();
  2002.     }
  2003.  
  2004.     return heap.peek();
  2005. }
  2006.  
  2007. console.log(findKthLargest([3,2,1,5,6,4], 2)); // Output: 5
  2008. console.log(findKthLargest([3,2,3,1,2,4,5,5,6], 4)); // Output: 4
  2009.  
  2010.  
  2011. */
  2012. ✅ Approach: Quickselect (Average O(n), Worst O())
  2013. Quickselect is an efficient algorithm based on QuickSort partitioning. Instead of sorting the whole array, it partitions the array and recursively narrows down the search space until we find the kth largest element.
  2014.  
  2015. 🛠 How Quickselect Works:
  2016. Pick a pivot (we use the last element for simplicity).
  2017.  
  2018. Partition the array so that:
  2019.  
  2020. Elements greater than the pivot are on the left.
  2021.  
  2022. Elements smaller than the pivot are on the right.
  2023.  
  2024. Check the position of the pivot:
  2025.  
  2026. If it’s the kth largest index, return it.
  2027.  
  2028. If it’s greater, recurse on the left half.
  2029.  
  2030. If it’s smaller, recurse on the right half.
  2031.  
  2032. 🕒 Time Complexity Analysis
  2033. Best & Average Case: O(n)
  2034.  
  2035. Worst Case (Unbalanced Partitions): O(), but rare (can be optimized with random pivots).
  2036.  
  2037. 📦 Space Complexity:
  2038. O(1) (in-place partitioning, no extra memory used)
  2039.  
  2040. 🚀 Why Quickselect?
  2041. Faster than sorting (O(n log n)) for large datasets.
  2042.  
  2043. Less memory usage than a heap (O(k) space).
  2044.  
  2045. Let me know if you need further optimizations! 🚀
  2046.  
  2047. */
  2048.  
  2049. function quickSelect(nums, left, right, k) {
  2050.     let pivotIndex = partition(nums, left, right);
  2051.  
  2052.     if (pivotIndex === k) return nums[pivotIndex]; // Found the kth largest
  2053.     if (pivotIndex > k) return quickSelect(nums, left, pivotIndex - 1, k); // Search left
  2054.     return quickSelect(nums, pivotIndex + 1, right, k); // Search right
  2055. }
  2056.  
  2057. function partition(nums, left, right) {
  2058.     let pivot = nums[right]; // Choosing last element as pivot
  2059.     let i = left; // Pointer for greater elements
  2060.  
  2061.     for (let j = left; j < right; j++) {
  2062.         if (nums[j] >= pivot) { // Move larger elements to the left
  2063.             [nums[i], nums[j]] = [nums[j], nums[i]];
  2064.             i++;
  2065.         }
  2066.     }
  2067.  
  2068.     // Swap pivot into its correct position
  2069.     [nums[i], nums[right]] = [nums[right], nums[i]];
  2070.     return i; // Pivot index
  2071. }
  2072.  
  2073. function findKthLargest(nums, k) {
  2074.     let n = nums.length;
  2075.     return quickSelect(nums, 0, n - 1, k - 1); // k-1 because array is 0-indexed
  2076. }
  2077.  
  2078. console.log(findKthLargest([3,2,1,5,6,4], 2)); // Output: 5
  2079. console.log(findKthLargest([3,2,3,1,2,4,5,5,6], 4)); // Output: 4
  2080. console.log(findKthLargest([1,2,3,4,5,6,7,8,9,10], 3)); // Output: 8
  2081. console.log(findKthLargest([10,9,8,7,6,5,4,3,2,1], 3)); // Output: 8
  2082.  
  2083. /* ===============================
  2084.  
  2085. 691. Stickers to Spell Word Hard
  2086.  
  2087. We are given n different types of stickers. Each sticker has a lowercase English word on it.
  2088.  
  2089. You would like to spell out the given string target by cutting individual letters from your collection of stickers and rearranging them. You can use each sticker more than once if you want, and you have infinite quantities of each sticker.
  2090.  
  2091. Return the minimum number of stickers that you need to spell out target. If the task is impossible, return -1.
  2092.  
  2093. Note: In all test cases, all words were chosen randomly from the 1000 most common US English words, and target was chosen as a concatenation of two random words.
  2094.  
  2095.  
  2096.  
  2097. Example 1:
  2098.  
  2099. Input: stickers = ["with","example","science"], target = "thehat"
  2100. Output: 3
  2101. Explanation:
  2102. We can use 2 "with" stickers, and 1 "example" sticker.
  2103. After cutting and rearrange the letters of those stickers, we can form the target "thehat".
  2104. Also, this is the minimum number of stickers necessary to form the target string.
  2105. Example 2:
  2106.  
  2107. Input: stickers = ["notice","possible"], target = "basicbasic"
  2108. Output: -1
  2109. Explanation:
  2110. We cannot form the target "basicbasic" from cutting letters from the given stickers.
  2111.  
  2112.  
  2113. Constraints:
  2114.  
  2115. n == stickers.length
  2116. 1 <= n <= 50
  2117. 1 <= stickers[i].length <= 10
  2118. 1 <= target.length <= 15
  2119. stickers[i] and target consist of lowercase English letters.
  2120.  
  2121.  
  2122.  
  2123. Approach:
  2124. The problem asks for the minimum number of stickers needed to form a target string by cutting individual letters. We can use each sticker multiple times. This problem has optimal substructure and overlapping subproblems, suggesting a dynamic programming or memoization approach.
  2125.  
  2126. Preprocessing:
  2127.  
  2128. Count the frequency of each character in the target string. This will be our goal state.
  2129. Filter the stickers array to keep only those stickers that contain at least one character present in the target. Stickers with no relevant characters won't help us form the target. For each valid sticker, pre-calculate the frequency of its characters.
  2130. Memoization (Top-Down Dynamic Programming):
  2131.  
  2132. We will use a recursive function solve(currentFreq) that takes the current frequency of characters we have collected so far as input.
  2133. The base case for the recursion is when the currentFreq has at least the required frequency for every character in the target. In this case, we have formed the target, and the number of stickers used to reach this state is 0.
  2134. We use a memo (a Map in JavaScript) to store the results of subproblems (states represented by character frequencies). The key for the memo will be a string representation of the currentFreq array. If we have already computed the result for a given currentFreq, we can directly return it from the memo.
  2135. Recursive Step:
  2136.  
  2137. Inside the solve function, if the target is not yet formed (i.e., there's at least one character whose current frequency is less than the target frequency), we iterate through each validStickers.
  2138. For each validSticker, we simulate using one instance of that sticker. We update the currentFreq by adding the character counts from the sticker.
  2139. We then recursively call solve with this new nextFreq. If the recursive call returns a value other than Infinity (meaning a solution was found from that state), we update our minStickerCount by taking the minimum of the current minStickerCount and 1 + count (where count is the result of the recursive call, and 1 represents the sticker we just used).
  2140. After trying all validStickers, we store the minStickerCount in the memo for the current freqKey and return it.
  2141. Initial Call:
  2142.  
  2143. We start the process by calling solve with an initial frequency array of all zeros (representing that we haven't used any stickers yet).
  2144. Result Handling:
  2145.  
  2146. The final result of the solve function will be the minimum number of stickers needed. If the solve function returns Infinity, it means it's impossible to form the target, so we return -1.
  2147. Time Complexity:
  2148. Let T be the length of the target string, and S be the number of unique characters in the alphabet (26 in this case).
  2149. The state of our DP is represented by the frequency of each character we have collected so far. In the worst case, the frequency of each character can go up to the frequency in the target. The number of possible states could be roughly proportional to the product of (target frequency of each character + 1). However, a tighter bound is harder to determine precisely due to the dependencies.
  2150. For each state, we iterate through all the validStickers (at most n). For each sticker, we do a constant amount of work (updating the frequency array).
  2151. The number of reachable states can be large, but memoization helps us avoid recomputing them. In the worst case, the number of unique character frequency profiles we might encounter can be significant, potentially exponential in the length of the target.
  2152. However, given the constraints (target length <= 15), the number of reachable states might be manageable with memoization.
  2153. A rough upper bound on the number of states could be something like (T+1) ^ S
  2154.  , where T is the maximum length of the target and S is the alphabet size (26). For each state, we iterate through at most n stickers.
  2155. Therefore, the time complexity is roughly O(n⋅(number of states)). The exact number of states is hard to pin down precisely but is bounded by something related to the combinations of character counts up to the target frequencies. In the worst case, this could be exponential in the length of the target.
  2156. Space Complexity:
  2157. targetFreq: O(S), where S is the size of the alphabet (26).
  2158. validStickers: In the worst case, it can contain all n stickers, and each sticker's frequency array is of size S, so O(n⋅S).
  2159. memo: The size of the memo is equal to the number of unique states we encounter. In the worst case, this could also be related to the combinations of character counts up to the target frequencies, potentially exponential in the length of the target. The value stored for each state is a constant.
  2160. Recursion call stack: In the worst case, the depth of the recursion could be related to the length of the target.
  2161. Overall, the space complexity is dominated by the memo and validStickers, which can be significant but is crucial for the efficiency gained through memoization. A rough upper bound on the space complexity could also be related to the number of states, potentially exponential in the length of the target in the worst case. However, in practice, with memoization, we only store the results for the states we actually reach.
  2162. */
  2163.  
  2164. function minStickers(stickers, target) {
  2165.   const n = stickers.length;
  2166.   const targetFreq = new Array(26).fill(0);
  2167.   for (const char of target) {
  2168.     targetFreq[char.charCodeAt(0) - 'a'.charCodeAt(0)]++;
  2169.   }
  2170.  
  2171.   const validStickers = [];
  2172.   for (const sticker of stickers) {
  2173.     const stickerFreq = new Array(26).fill(0);
  2174.     for (const char of sticker) {
  2175.       stickerFreq[char.charCodeAt(0) - 'a'.charCodeAt(0)]++;
  2176.     }
  2177.     // Check if the sticker has any letter that is present in the target
  2178.     if (stickerFreq.some((count, i) => count > 0 && targetFreq[i] > 0)) {
  2179.       validStickers.push(stickerFreq);
  2180.     }
  2181.   }
  2182.  
  2183.   if (validStickers.length === 0) {
  2184.     return -1; // No sticker can contribute to the target
  2185.   }
  2186.  
  2187.   const memo = new Map();
  2188.  
  2189.   function solve(currentFreq) {
  2190.     const freqKey = currentFreq.join(',');
  2191.     if (memo.has(freqKey)) {
  2192.       return memo.get(freqKey);
  2193.     }
  2194.  
  2195.     let remaining = false;
  2196.     for (let i = 0; i < 26; i++) {
  2197.       if (currentFreq[i] < targetFreq[i]) {
  2198.         remaining = true;
  2199.         break;
  2200.       }
  2201.     }
  2202.  
  2203.     if (!remaining) {
  2204.       return 0; // Target is formed
  2205.     }
  2206.  
  2207.     let minStickerCount = Infinity;
  2208.  
  2209.     for (const stickerFreq of validStickers) {
  2210.       const nextFreq = [...currentFreq];
  2211.       let canUse = false;
  2212.       for (let i = 0; i < 26; i++) {
  2213.         if (stickerFreq[i] > 0 && currentFreq[i] < targetFreq[i]) {
  2214.           nextFreq[i] += stickerFreq[i];
  2215.           canUse = true;
  2216.         }
  2217.       }
  2218.  
  2219.       if (canUse) {
  2220.         const count = solve(nextFreq);
  2221.         if (count !== Infinity) {
  2222.           minStickerCount = Math.min(minStickerCount, 1 + count);
  2223.         }
  2224.       }
  2225.     }
  2226.  
  2227.     memo.set(freqKey, minStickerCount);
  2228.     return minStickerCount;
  2229.   }
  2230.  
  2231.   const initialFreq = new Array(26).fill(0);
  2232.   const result = solve(initialFreq);
  2233.  
  2234.   return result === Infinity ? -1 : result;
  2235. }
  2236.  
  2237. console.log(minStickers(["with","example","science"], "thehat")); // Output: 3
  2238. console.log(minStickers(["notice","possible"], "basicbasic")); // Output: -1
  2239. console.log(minStickers(["these","guess","about","garden","him"], "atom")); // Output: 2
  2240.  
  2241.  
  2242. /* =================================
  2243.  
  2244. 346. Moving Average from Data Stream Easy
  2245.  
  2246. Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window.
  2247.  
  2248. Implement the MovingAverage class:
  2249.  
  2250. MovingAverage(int size) Initializes the object with the size of the window size.
  2251. double next(int val) Returns the moving average of the last size values of the stream.
  2252.  
  2253.  
  2254. Example 1:
  2255.  
  2256. Input
  2257. ["MovingAverage", "next", "next", "next", "next"]
  2258. [[3], [1], [10], [3], [5]]
  2259. Output
  2260. [null, 1.0, 5.5, 4.66667, 6.0]
  2261.  
  2262. Explanation
  2263. MovingAverage movingAverage = new MovingAverage(3);
  2264. movingAverage.next(1); // return 1.0 = 1 / 1
  2265. movingAverage.next(10); // return 5.5 = (1 + 10) / 2
  2266. movingAverage.next(3); // return 4.66667 = (1 + 10 + 3) / 3
  2267. movingAverage.next(5); // return 6.0 = (10 + 3 + 5) / 3
  2268.  
  2269.  
  2270. Constraints:
  2271.  
  2272. 1 <= size <= 1000
  2273. -10^5 <= val <= 10^5
  2274. At most 104 calls will be made to next.
  2275.  
  2276. Here's a clean JavaScript implementation of the MovingAverage class using a queue to maintain the window and an ongoing sum to keep track of the average efficiently
  2277.  
  2278. Time Complexity:
  2279. constructor(size): The constructor performs constant time operations (initialization of variables). Therefore, its time complexity is O(1).
  2280.  
  2281. next(val): O(1) – Constant time operations (push, shift, add, subtract)
  2282.  
  2283. push(val) takes O(1) on average (amortized).
  2284. The if condition checks the window size, which is a constant time operation.
  2285. shift() operation on an array takes O(k) time in the worst case, where k is the current size of the window. However, since the window size is at most size, this is bounded by O(size).
  2286. The remaining operations (addition, subtraction, division) are constant time O(1).
  2287. Considering the constraints where at most 10<sup>4</sup> calls to next will be made, and in each call, shift() might take up to O(size), the overall complexity over multiple calls could be a concern if shift() was frequently called on a large window. However, the problem asks for the complexity of a single next operation. In that context, the dominant operation, in the worst case when the window is full and we need to remove an element, is shift(), which is O(size).
  2288. However, if we consider using a data structure that allows O(1) removal from the front (like a doubly linked list or a circular buffer with indices), the next operation could be optimized to O(1). Given the array implementation, the worst-case time complexity of a single next operation is O(size) due to the potential shift() operation.
  2289.  
  2290. Amortized Analysis: If we consider the total cost over m calls to next, where m can be up to 10<sup>4</sup>, each element is added and removed from the array at most once. Therefore, the total cost of shift() operations over all calls would be O(m), leading to an amortized time complexity of O(1) per next operation.
  2291.  
  2292. Space Complexity: O(size)
  2293. The window array stores at most size elements. Therefore, the space complexity is O(size), as the memory used by the window grows linearly with the window size.
  2294. The sum and size variables take constant space, O(1).
  2295. Thus, the overall space complexity of the MovingAverage class is O(size).
  2296. */
  2297.  
  2298. class MovingAverage {
  2299.   constructor(size) {
  2300.     this.size = size;
  2301.     this.queue = [];
  2302.     this.sum = 0;
  2303.   }
  2304.  
  2305.   next(val) {
  2306.     this.queue.push(val);
  2307.     this.sum += val;
  2308.  
  2309.     if (this.queue.length > this.size) {
  2310.       this.sum -= this.queue.shift();
  2311.     }
  2312.  
  2313.     return this.sum / this.queue.length;
  2314.   }
  2315. }
  2316.  
  2317.  
  2318. const movingAverage = new MovingAverage(3);
  2319. console.log(movingAverage.next(1));   // 1.0
  2320. console.log(movingAverage.next(10));  // (1 + 10) / 2 = 5.5
  2321. console.log(movingAverage.next(3));   // (1 + 10 + 3) / 3 = 4.66667
  2322. console.log(movingAverage.next(5));   // (10 + 3 + 5) / 3 = 6.0
  2323.  
  2324. /*
  2325. Let's rewrite the MovingAverage class using a circular queue implementation with pointers to avoid using shift() (which is O(n)). This keeps everything at O(1) time and space.
  2326. */
  2327. class MovingAverage {
  2328.   constructor(size) {
  2329.     this.size = size;
  2330.     this.buffer = new Array(size);
  2331.     this.start = 0;
  2332.     this.count = 0;
  2333.     this.sum = 0;
  2334.   }
  2335.  
  2336.   next(val) {
  2337.     if (this.count < this.size) {
  2338.       this.count++;
  2339.     } else {
  2340.       this.sum -= this.buffer[this.start];
  2341.       this.start = (this.start + 1) % this.size;
  2342.     }
  2343.  
  2344.     const idx = (this.start + this.count - 1) % this.size;
  2345.     this.buffer[idx] = val;
  2346.     this.sum += val;
  2347.  
  2348.     return this.sum / this.count;
  2349.   }
  2350. }
  2351.  
  2352. const movingAverage = new MovingAverage(3);
  2353. console.log(movingAverage.next(1));   // 1.0
  2354. console.log(movingAverage.next(10));  // 5.5
  2355. console.log(movingAverage.next(3));   // 4.66667
  2356. console.log(movingAverage.next(5));   // 6.0
  2357.  
  2358. /* ============================
  2359.  
  2360. 71. Simplify Path Medium
  2361.  
  2362. You are given an absolute path for a Unix-style file system, which always begins with a slash '/'. Your task is to transform this absolute path into its simplified canonical path.
  2363.  
  2364. The rules of a Unix-style file system are as follows:
  2365.  
  2366. A single period '.' represents the current directory.
  2367. A double period '..' represents the previous/parent directory.
  2368. Multiple consecutive slashes such as '//' and '///' are treated as a single slash '/'.
  2369. Any sequence of periods that does not match the rules above should be treated as a valid directory or file name. For example, '...' and '....' are valid directory or file names.
  2370. The simplified canonical path should follow these rules:
  2371.  
  2372. The path must start with a single slash '/'.
  2373. Directories within the path must be separated by exactly one slash '/'.
  2374. The path must not end with a slash '/', unless it is the root directory.
  2375. The path must not have any single or double periods ('.' and '..') used to denote current or parent directories.
  2376. Return the simplified canonical path.
  2377.  
  2378.  
  2379.  
  2380. Example 1:
  2381.  
  2382. Input: path = "/home/"
  2383.  
  2384. Output: "/home"
  2385.  
  2386. Explanation:
  2387.  
  2388. The trailing slash should be removed.
  2389.  
  2390. Example 2:
  2391.  
  2392. Input: path = "/home//foo/"
  2393.  
  2394. Output: "/home/foo"
  2395.  
  2396. Explanation:
  2397.  
  2398. Multiple consecutive slashes are replaced by a single one.
  2399.  
  2400. Example 3:
  2401.  
  2402. Input: path = "/home/user/Documents/../Pictures"
  2403.  
  2404. Output: "/home/user/Pictures"
  2405.  
  2406. Explanation:
  2407.  
  2408. A double period ".." refers to the directory up a level (the parent directory).
  2409.  
  2410. Example 4:
  2411.  
  2412. Input: path = "/../"
  2413.  
  2414. Output: "/"
  2415.  
  2416. Explanation:
  2417.  
  2418. Going one level up from the root directory is not possible.
  2419.  
  2420. Example 5:
  2421.  
  2422. Input: path = "/.../a/../b/c/../d/./"
  2423.  
  2424. Output: "/.../b/d"
  2425.  
  2426. Explanation:
  2427.  
  2428. "..." is a valid name for a directory in this problem.
  2429.  
  2430.  
  2431.  
  2432. Constraints:
  2433.  
  2434. 1 <= path.length <= 3000
  2435. path consists of English letters, digits, period '.', slash '/' or '_'.
  2436. path is a valid absolute Unix path.
  2437.  
  2438.  
  2439.  
  2440. To simplify a Unix-style path, we simulate navigation through directories using a stack:
  2441.  
  2442. 🔧 Approach:
  2443. Split the path by '/'.
  2444.  
  2445. Traverse each part:
  2446.  
  2447. If it's '' or '.': skip it.
  2448.  
  2449. If it's '..': pop the top of the stack if it's not empty.
  2450.  
  2451. Otherwise: push the part to the stack (it's a valid directory name).
  2452.  
  2453. Join the stack with '/' and prepend a '/' to form the canonical path.
  2454.  
  2455. 📊 Complexity Analysis:
  2456. Time Complexity: O(n) — where n is the length of the path string (we split and traverse once).
  2457.  
  2458. Space Complexity: O(m) — for the stack, where m is the number of valid path components.
  2459.  
  2460. */
  2461.  
  2462. function simplifyPath(path) {
  2463.   const parts = path.split('/');
  2464.   const stack = [];
  2465.  
  2466.   for (const part of parts) {
  2467.     if (part === '' || part === '.') {
  2468.       continue;
  2469.     } else if (part === '..') {
  2470.       if (stack.length > 0) {
  2471.         stack.pop();
  2472.       }
  2473.     } else {
  2474.       stack.push(part);
  2475.     }
  2476.   }
  2477.  
  2478.   return '/' + stack.join('/');
  2479. }
  2480.  
  2481. console.log(simplifyPath("/home/"));                       // "/home"
  2482. console.log(simplifyPath("/home//foo/"));                  // "/home/foo"
  2483. console.log(simplifyPath("/home/user/Documents/../Pictures")); // "/home/user/Pictures"
  2484. console.log(simplifyPath("/../"));                         // "/"
  2485. console.log(simplifyPath("/.../a/../b/c/../d/./"));        // "/.../b/d"
  2486.  
  2487.  
  2488. /* ===========================
  2489. 791 Custom Sort String Medium
  2490.  
  2491. You are given two strings order and s. All the characters of order are unique and were sorted in some custom order previously.
  2492.  
  2493. Permute the characters of s so that they match the order that order was sorted. More specifically, if a character x occurs before a character y in order, then x should occur before y in the permuted string.
  2494.  
  2495. Return any permutation of s that satisfies this property.
  2496.  
  2497. Example 1:
  2498.  
  2499. Input: order = "cba", s = "abcd"
  2500.  
  2501. Output: "cbad"
  2502.  
  2503. Explanation: "a", "b", "c" appear in order, so the order of "a", "b", "c" should be "c", "b", and "a".
  2504.  
  2505. Since "d" does not appear in order, it can be at any position in the returned string. "dcba", "cdba", "cbda" are also valid outputs.
  2506.  
  2507. Example 2:
  2508.  
  2509. Input: order = "bcafg", s = "abcd"
  2510.  
  2511. Output: "bcad"
  2512.  
  2513. Explanation: The characters "b", "c", and "a" from order dictate the order for the characters in s. The character "d" in s does not appear in order, so its position is flexible.
  2514.  
  2515. Following the order of appearance in order, "b", "c", and "a" from s should be arranged as "b", "c", "a". "d" can be placed at any position since it's not in order. The output "bcad" correctly follows this rule. Other arrangements like "dbca" or "bcda" would also be valid, as long as "b", "c", "a" maintain their order.
  2516.  
  2517. Constraints:
  2518.  
  2519. 1 <= order.length <= 26
  2520. 1 <= s.length <= 200
  2521. order and s consist of lowercase English letters.
  2522. All the characters of order are unique.
  2523.  
  2524.  
  2525. To solve this problem, the goal is to reorder the characters of s such that any character that appears in order respects the ordering defined by order. Characters not in order can appear anywhere in the result.
  2526.  
  2527. ✅ Approach:
  2528. Count the frequency of each character in s.
  2529.  
  2530. Go through order, and for each character, if it's in s, append it as many times as it appears.
  2531.  
  2532. Append the remaining characters (those not in order) to the end.
  2533.  
  2534. 📊 Complexity:
  2535. Time: O(n + m), where n = s.length and m = order.length
  2536.  
  2537. Space: O(n) for the frequency map
  2538.  
  2539.  
  2540.  
  2541. */
  2542.  
  2543. function customSortString(order, s) {
  2544.   const count = {}; // Count characters in s
  2545.  
  2546.   // Count frequency of each character in s
  2547.   for (let ch of s) {
  2548.     count[ch] = (count[ch] || 0) + 1;
  2549.   }
  2550.  
  2551.   let result = "";
  2552.  
  2553.   // Append characters in the order specified by 'order'
  2554.   for (let ch of order) {
  2555.     if (count[ch]) {
  2556.       for (let i = 0; i < count[ch]; i++) {
  2557.         result += ch;
  2558.       }
  2559.       delete count[ch]; // remove to avoid reprocessing
  2560.     }
  2561.   }
  2562.  
  2563.   // Append remaining characters not in 'order'
  2564.   for (let ch in count) {
  2565.     for (let i = 0; i < count[ch]; i++) {
  2566.       result += ch;
  2567.     }
  2568.   }
  2569.  
  2570.   return result;
  2571. }
  2572.  
  2573.  
  2574.  
  2575.  
  2576. function customSortString(order, s) {
  2577.   const sFreq = new Map();
  2578.   for (const char of s) {
  2579.     sFreq.set(char, (sFreq.get(char) || 0) + 1);
  2580.   }
  2581.  
  2582.   let result = '';
  2583.  
  2584.   for (const char of order) {
  2585.     if (sFreq.has(char)) {
  2586.       const count = sFreq.get(char);
  2587.       for (let i = 0; i < count; i++) {
  2588.         result += char;
  2589.       }
  2590.       sFreq.delete(char);
  2591.     }
  2592.   }
  2593.  
  2594.   for (const [char, freq] of sFreq) {
  2595.     for (let i = 0; i < freq; i++) {
  2596.       result += char;
  2597.     }
  2598.   }
  2599.  
  2600.   return result;
  2601. }
  2602.  
  2603. console.log(customSortString("cba", "abcd"));   // "cbad", "cbda", "dcba", etc.
  2604. console.log(customSortString("bcafg", "abcd")); // "bcad", "cbad", "bcda", etc.
  2605.  
  2606.  
  2607.  
  2608. /* ===========================
  2609.  
  2610. 426 Convert Binary Search Tree to Sorted Doubly Linked List Medium
  2611.  
  2612. Convert a Binary Search Tree to a sorted Circular Doubly-Linked List in place.
  2613.  
  2614. You can think of the left and right pointers as synonymous to the predecessor and successor pointers in a doubly-linked list. For a circular doubly linked list, the predecessor of the first element is the last element, and the successor of the last element is the first element.
  2615.  
  2616. We want to do the transformation in place. After the transformation, the left pointer of the tree node should point to its predecessor, and the right pointer should point to its successor. You should return the pointer to the smallest element of the linked list.
  2617.  
  2618.  
  2619.  
  2620. Example 1:
  2621.  
  2622.  
  2623.  
  2624. Input: root = [4,2,5,1,3]
  2625.       4
  2626.      / \
  2627.     2   5
  2628.    / \
  2629.   1   3
  2630.  
  2631.  
  2632. Output: [1,2,3,4,5]
  2633.  
  2634.         _______________________
  2635.        ^                       |
  2636. HEAD-> 1 <-> 2 <-> 3 <-> 4 <-> 5
  2637.        ^                       |
  2638.        |_______________________|
  2639.  
  2640.  
  2641. Explanation: The figure below shows the transformed BST. The solid line indicates the successor relationship, while the dashed line means the predecessor relationship.
  2642.  
  2643. Example 2:
  2644.  
  2645.     2
  2646.    / \
  2647.   1   3
  2648.  
  2649.  
  2650. Input: root = [2,1,3]
  2651.  
  2652. Output: [1,2,3]
  2653.         ____________
  2654.        ↑           ↓
  2655. HEAD-> 1 <-> 2 <-> 3
  2656.         ↖_________↙
  2657.  
  2658. Constraints:
  2659.  
  2660. The number of nodes in the tree is in the range [0, 2000].
  2661. -1000 <= Node.val <= 1000
  2662. All the values of the tree are unique.
  2663.  
  2664.  
  2665. Approach:
  2666. The key idea is to perform an Inorder Traversal of the Binary Search Tree (BST). In an Inorder Traversal, we visit the left subtree, then the current node, and finally the right subtree. For a BST, an Inorder Traversal visits the nodes in ascending order of their values. This ordered sequence of nodes is exactly what we need for our sorted doubly-linked list.
  2667.  
  2668. We will maintain two pointers during the traversal: head and prev.
  2669.  
  2670. head: This pointer will store the first node encountered in the Inorder Traversal, which will be the smallest element in the BST and hence the head of our sorted circular doubly-linked list. It is initialized to null.
  2671.  
  2672. prev: This pointer will keep track of the previously visited node during the traversal. This allows us to establish the right (successor) and left (predecessor) connections between consecutive nodes in the sorted order. It is also initialized to null.
  2673.  
  2674. The inorderTraversal function works as follows:
  2675.  
  2676. Base Case: If the current node is null, we return.
  2677.  
  2678. Recursive Left Subtree: We recursively call inorderTraversal on the node.left to process the left subtree first.
  2679.  
  2680. Process Current Node:
  2681.  
  2682. If prev is null, it means we are visiting the very first node in the Inorder Traversal. This node is the smallest element, so we set head = node.
  2683. If prev is not null, it means we have already visited a node. We need to establish the doubly-linked list connections:
  2684. Set the right pointer of the prev node to the current node (prev.right = node).
  2685. Set the left pointer of the current node to the prev node (node.left = prev).
  2686. After establishing the connections (or setting the head), we update prev to the current node so that in the next step, this current node will be the prev node for the next visited node.
  2687. Recursive Right Subtree: We recursively call inorderTraversal on the node.right to process the right subtree.
  2688.  
  2689. After the inorderTraversal is complete, the head pointer will be pointing to the smallest element of the BST, and all the nodes will be connected in a sorted doubly-linked list using their left and right pointers.
  2690.  
  2691. Finally, to make the list circular, we need to connect the last node (which prev will be pointing to after the traversal) with the first node (head):
  2692.  
  2693. Set the left pointer of the head to the prev node (head.left = prev).
  2694. Set the right pointer of the prev node to the head node (prev.right = head).
  2695. We then return the head pointer, which points to the smallest element of the sorted circular doubly-linked list.
  2696.  
  2697. Time Complexity:
  2698. The inorderTraversal function visits each node in the BST exactly once. Therefore, the time complexity is O(N), where N is the number of nodes in the BST. The operations performed at each node (comparisons, pointer assignments) take constant time. The final step of making the list circular also takes constant time.
  2699.  
  2700. Space Complexity:
  2701. The space complexity is determined by the recursion stack used during the Inorder Traversal. In the worst case (a skewed tree), the depth of the recursion can be equal to the number of nodes, leading to a space complexity of O(N). In the best case (a balanced tree), the depth of the recursion would be O(log N), so the space complexity would be O(log N). Since the problem statement doesn't guarantee a balanced tree, we should consider the worst-case scenario. The space used for the head and prev pointers is constant, O(1). Therefore, the overall space complexity is O(N).
  2702.  
  2703. The transformation is done in place because we are reusing the existing left and right pointers of the tree nodes to form the predecessor and successor pointers of the doubly-linked list without allocating any significant extra space for new nodes.
  2704.  
  2705. */
  2706.  
  2707.  
  2708. /**
  2709.  * // Definition for a Node.
  2710.  * function Node(val,left,right) {
  2711.  * this.val = val;
  2712.  * this.left = left;
  2713.  * this.right = right;
  2714.  * };
  2715.  */
  2716. /**
  2717.  * @param {Node} root
  2718.  * @return {Node}
  2719.  */
  2720. function treeToDoublyList(root) {
  2721.   if (!root) {
  2722.     return null;
  2723.   }
  2724.  
  2725.   let head = null;
  2726.   let prev = null;
  2727.  
  2728.   function inorderTraversal(node) {
  2729.     if (!node) {
  2730.       return;
  2731.     }
  2732.  
  2733.     inorderTraversal(node.left);
  2734.  
  2735.     if (!prev) {
  2736.       // First node encountered in inorder traversal is the head of the list
  2737.       head = node;
  2738.     } else {
  2739.       // Set up the doubly linked list connections
  2740.       prev.right = node;
  2741.       node.left = prev;
  2742.     }
  2743.     prev = node;
  2744.  
  2745.     inorderTraversal(node.right);
  2746.   }
  2747.  
  2748.   inorderTraversal(root);
  2749.  
  2750.   // Make the list circular
  2751.   if (head && prev) {
  2752.     head.left = prev;
  2753.     prev.right = head;
  2754.   }
  2755.  
  2756.   return head;
  2757. }
  2758.  
  2759. // Helper function to create a TreeNode (for testing)
  2760. function TreeNode(val, left, right) {
  2761.   this.val = val === undefined ? 0 : val;
  2762.   this.left = left === undefined ? null : left;
  2763.   this.right = right === undefined ? null : right;
  2764. }
  2765.  
  2766. // Example 1:
  2767. const root1 = new TreeNode(4);
  2768. root1.left = new TreeNode(2);
  2769. root1.right = new TreeNode(5);
  2770. root1.left.left = new TreeNode(1);
  2771. root1.left.right = new TreeNode(3);
  2772. const result1 = treeToDoublyList(root1);
  2773. let current1 = result1;
  2774. const output1 = [];
  2775. if (current1) {
  2776.   output1.push(current1.val);
  2777.   current1 = current1.right;
  2778.   while (current1 && current1 !== result1) {
  2779.     output1.push(current1.val);
  2780.     current1 = current1.right;
  2781.   }
  2782. }
  2783. console.log("Example 1 Output:", output1); // Expected: [1, 2, 3, 4, 5]
  2784.  
  2785. // Example 2:
  2786. const root2 = new TreeNode(2);
  2787. root2.left = new TreeNode(1);
  2788. root2.right = new TreeNode(3);
  2789. const result2 = treeToDoublyList(root2);
  2790. let current2 = result2;
  2791. const output2 = [];
  2792. if (current2) {
  2793.   output2.push(current2.val);
  2794.   current2 = current2.right;
  2795.   while (current2 && current2 !== result2) {
  2796.     output2.push(current2.val);
  2797.     current2 = current2.right;
  2798.   }
  2799. }
  2800. console.log("Example 2 Output:", output2); // Expected: [1, 2, 3]
  2801.  
  2802.  
  2803.  
  2804. /*
  2805. To convert a Binary Search Tree (BST) to a sorted circular doubly-linked list in place, we can use in-order traversal which visits nodes in sorted order.
  2806.  
  2807. During the traversal, we'll:
  2808.  
  2809. Keep track of the previous node visited (prev)
  2810.  
  2811. Link the prev.right to current node, and current.left to prev
  2812.  
  2813. At the end, link the head and tail to make it circular
  2814.  
  2815. ✅ Key Requirements:
  2816. Must be in-place
  2817.  
  2818. Use left as prev, and right as next
  2819.  
  2820. Final list is circular
  2821.  
  2822. ✅ Time & Space Complexity
  2823. Time: O(n), since we visit each node once
  2824.  
  2825. Space: O(h) = O(log n) for balanced tree due to recursion stack
  2826.  
  2827. */
  2828.  
  2829. function treeToDoublyList(root) {
  2830.   if (!root) return null;
  2831.  
  2832.   let first = null; // Head of the list
  2833.   let last = null;  // Tail (previous node)
  2834.  
  2835.   function dfs(node) {
  2836.     if (!node) return;
  2837.  
  2838.     dfs(node.left);
  2839.  
  2840.     if (last) {
  2841.       // Link previous node (last) with current node
  2842.       last.right = node;
  2843.       node.left = last;
  2844.     } else {
  2845.       // First node visited is the smallest
  2846.       first = node;
  2847.     }
  2848.  
  2849.     last = node;
  2850.  
  2851.     dfs(node.right);
  2852.   }
  2853.  
  2854.   dfs(root);
  2855.  
  2856.   // Close the circular doubly linked list
  2857.   first.left = last;
  2858.   last.right = first;
  2859.  
  2860.   return first;
  2861. }
  2862.  
  2863. let head = treeToDoublyList(root);
  2864. let curr = head;
  2865. let result = [];
  2866. do {
  2867.   result.push(curr.val);
  2868.   curr = curr.right;
  2869. } while (curr !== head);
  2870. console.log(result); // Should print sorted values
  2871.  
  2872. /* =================================
  2873.  
  2874. function insert(head, insertVal) {
  2875.   const newNode = { val: insertVal, next: null };
  2876.  
  2877.   if (!head) {
  2878.     newNode.next = newNode;
  2879.     return newNode;
  2880.   }
  2881.  
  2882.   let curr = head;
  2883.  
  2884.   while (true) {
  2885.     let next = curr.next;
  2886.  
  2887.     const inOrder = curr.val <= insertVal && insertVal <= next.val;
  2888.     const isRotationPoint = curr.val > next.val;
  2889.  
  2890.     if (
  2891.       inOrder ||
  2892.       (isRotationPoint && (insertVal >= curr.val || insertVal <= next.val)) ||
  2893.       next === head // full loop, no suitable place
  2894.     ) {
  2895.       curr.next = newNode;
  2896.       newNode.next = next;
  2897.       break;
  2898.     }
  2899.  
  2900.     curr = curr.next;
  2901.   }
  2902.  
  2903.   return head;
  2904. }
  2905.  
  2906. // Helper to build and print circular list (for test/debug purposes)
  2907. function createCircularList(values) {
  2908.   if (!values.length) return null;
  2909.   const nodes = values.map(val => ({ val, next: null }));
  2910.   for (let i = 0; i < nodes.length; i++) {
  2911.     nodes[i].next = nodes[(i + 1) % nodes.length];
  2912.   }
  2913.   return nodes[0]; // return any node
  2914. }
  2915. function printCircularList(head, count = 10) {
  2916.   let result = [];
  2917.   let curr = head;
  2918.   while (count-- && curr) {
  2919.     result.push(curr.val);
  2920.     curr = curr.next;
  2921.     if (curr === head) break;
  2922.   }
  2923.   console.log(result);
  2924. }
  2925.  
  2926. // Example:
  2927. let head = createCircularList([3, 4, 1]);
  2928. head = insert(head, 2);
  2929. printCircularList(head); // Output might be: [3, 4, 1, 2]
  2930.  
  2931. VM3368:50 (4) [3, 4, 1, 2]
  2932. undefined
  2933. let head2 = createCircularList([1]);
  2934. head2 = insert(head2, 0);
  2935. printCircularList(head2);  // Output might be: [1, 0]
  2936.  
  2937. /* ============================================
  2938. 708. Insert into a Sorted Circular Linked List Medium
  2939.  
  2940. Given a Circular Linked List node, which is sorted in non-descending order, write a function to insert a value insertVal into the list such that it remains a sorted circular list. The given node can be a reference to any single node in the list and may not necessarily be the smallest value in the circular list.
  2941.  
  2942. If there are multiple suitable places for insertion, you may choose any place to insert the new value. After the insertion, the circular list should remain sorted.
  2943.  
  2944. If the list is empty (i.e., the given node is null), you should create a new single circular list and return the reference to that single node. Otherwise, you should return the originally given node.
  2945.  
  2946.  
  2947.  
  2948. Example 1:
  2949. Input: head = [3,4,1], insertVal = 2
  2950.  
  2951. 1____
  2952. ↑    ↓
  2953. 4 <- 3 <- HEAD
  2954.  
  2955. Output: [3,4,1,2]
  2956.  
  2957. 1 -> 2
  2958. ↑    ↓
  2959. 4 <- 3 <- HEAD
  2960.  
  2961. Explanation: In the figure above, there is a sorted circular list of three elements. You are given a reference to the node with value 3, and we need to insert 2 into the list. The new node should be inserted between node 1 and node 3. After the insertion, the list should look like this, and we should still return node 3.
  2962.  
  2963.  
  2964.  
  2965. Example 2:
  2966.  
  2967. Input: head = [], insertVal = 1
  2968. Output: [1]
  2969. Explanation: The list is empty (given head is null). We create a new single circular list and return the reference to that single node.
  2970. Example 3:
  2971.  
  2972. Input: head = [1], insertVal = 0
  2973. Output: [1,0]
  2974.  
  2975.  
  2976. Constraints:
  2977.  
  2978. The number of nodes in the list is in the range [0, 5 * 104].
  2979. -106 <= Node.val, insertVal <= 106
  2980.  
  2981. ✅ Key Concepts
  2982. The list is circular, so the last node points back to the first.
  2983.  
  2984. The list is sorted in non-descending order.
  2985.  
  2986. You may be given any node (not necessarily the smallest).
  2987.  
  2988. The inserted value should be placed in the correct order.
  2989.  
  2990. You must handle:
  2991.  
  2992. Empty list
  2993.  
  2994. Single-node list
  2995.  
  2996. Normal insertion
  2997.  
  2998. Rotation point (where max wraps around to min)
  2999.  
  3000. ✅ Time & Space Complexity
  3001. Time Complexity: O(n) — You may need to traverse all nodes once
  3002.  
  3003. Space Complexity: O(1) — No extra space used except new node
  3004. */
  3005.  
  3006. class Node {
  3007.     constructor(val, next = null) {
  3008.         this.val = val;
  3009.         this.next = next;
  3010.     }
  3011. }
  3012.  
  3013. function insert(head, insertVal) {
  3014.   const newNode = new Node(insertVal);
  3015.  
  3016.   // Case 1: Empty list
  3017.   if (!head) {
  3018.     newNode.next = newNode;
  3019.     return newNode;
  3020.   }
  3021.  
  3022.   let curr = head;
  3023.  
  3024.   while (true) {
  3025.     const next = curr.next;
  3026.  
  3027.     const inBetween = curr.val <= insertVal && insertVal <= next.val;
  3028.     const atRotation = curr.val > next.val;
  3029.  
  3030.     // Case 2: Normal place between two nodes
  3031.     // Case 3: At rotation point (insertVal is new min or new max)
  3032.     if (
  3033.       inBetween ||
  3034.       (atRotation && (insertVal >= curr.val || insertVal <= next.val)) ||
  3035.       next === head // Case 4: Made full loop with no match (all elements are equal or no place found)
  3036.     ) {
  3037.       curr.next = newNode;
  3038.       newNode.next = next;
  3039.       break;
  3040.     }
  3041.  
  3042.     curr = next;
  3043.   }
  3044.  
  3045.   return head;
  3046. }
  3047.  
  3048.  
  3049. // Helper to create a circular list from array
  3050. function createCircularList(arr) {
  3051.   if (!arr.length) return null;
  3052.   const nodes = arr.map(val => ({ val, next: null }));
  3053.   for (let i = 0; i < nodes.length; i++) {
  3054.     nodes[i].next = nodes[(i + 1) % nodes.length];
  3055.   }
  3056.   return nodes[0]; // return reference to any node
  3057. }
  3058.  
  3059. // Helper to print limited number of circular list elements
  3060. function printCircularList(head, limit = 10) {
  3061.   const result = [];
  3062.   let curr = head;
  3063.   while (limit-- && curr) {
  3064.     result.push(curr.val);
  3065.     curr = curr.next;
  3066.     if (curr === head) break;
  3067.   }
  3068.   console.log(result);
  3069. }
  3070.  
  3071. // Test case:
  3072. let head = createCircularList([3, 4, 1]);
  3073. head = insert(head, 2);
  3074. printCircularList(head); // Output: [3, 4, 1, 2] or rotation variant
  3075.  
  3076.  
  3077.  
  3078.  
  3079. /**
  3080.  * // Definition for a Node.
  3081.  * function Node(val, next) {
  3082.  * this.val = val;
  3083.  * this.next = next;
  3084.  * };
  3085.  */
  3086.  
  3087. /**
  3088.  * @param {Node} head
  3089.  * @param {number} insertVal
  3090.  * @return {Node}
  3091.  */
  3092. function insert(head, insertVal) {
  3093.     const newNode = new Node(insertVal);
  3094.  
  3095.     if (!head) {
  3096.         newNode.next = newNode;
  3097.         return newNode;
  3098.     }
  3099.  
  3100.     let current = head;
  3101.  
  3102.     while (true) {
  3103.         const nextNode = current.next;
  3104.  
  3105.         // Case 1: Insertion in the middle of the sorted list
  3106.         if ((current.val <= insertVal && insertVal <= nextNode.val) ||
  3107.             // Case 2: Insertion at the end of the sorted list (wrapping around)
  3108.             (current.val > nextNode.val && (insertVal >= current.val || insertVal <= nextNode.val)) ||
  3109.             // Case 3: List with a single node
  3110.             current.next === head) {
  3111.             newNode.next = nextNode;
  3112.             current.next = newNode;
  3113.             return head;
  3114.         }
  3115.  
  3116.         current = nextNode;
  3117.  
  3118.         // Safety break to avoid infinite loop in case of all equal values (though the problem states non-descending)
  3119.         if (current === head) {
  3120.             newNode.next = nextNode;
  3121.             current.next = newNode;
  3122.             return head;
  3123.         }
  3124.     }
  3125. }
  3126.  
  3127. /*
  3128. Approach:
  3129. Handle Empty List:
  3130.  
  3131. If the given head is null, it means the list is empty. In this case, we create a new node with the insertVal, make its next pointer point to itself to form a single-node circular list, and return this new node as the head.
  3132.  
  3133. Handle Non-Empty List:
  3134.  
  3135. Create a new node newNode with the given insertVal.
  3136.  
  3137. Initialize a pointer current to the head of the list.
  3138.  
  3139. Iterate through the circular linked list using a while (true) loop. We will break out of this loop when we find the correct insertion point.
  3140.  
  3141. In each iteration, get the nextNode (i.e., current.next).
  3142.  
  3143. We need to consider three main scenarios for insertion:
  3144.  
  3145. Case 1: Insertion in the middle of the sorted list:
  3146.  
  3147. If the insertVal is greater than or equal to the current node's value (current.val <= insertVal) and less than or equal to the next node's value (insertVal <= nextNode.val), then the newNode should be inserted between current and nextNode.
  3148.  
  3149. We set newNode.next = nextNode and current.next = newNode.
  3150.  
  3151. Since the original head reference should be returned, we return head.
  3152.  
  3153. Case 2: Insertion at the end of the sorted list (wrapping around):
  3154.  
  3155. This case occurs when the sorted circular list has a "break point" where the values decrease (e.g., 3 -> 4 -> 1). If the insertVal needs to be inserted at the end (before the wrap-around) or at the beginning (after the wrap-around), this condition handles it.
  3156.  
  3157. If current.val is greater than nextNode.val (indicating the wrap-around), and either insertVal is greater than or equal to current.val (inserting at the end) or insertVal is less than or equal to nextNode.val (inserting at the beginning), then newNode should be inserted between current and nextNode.
  3158.  
  3159. We set newNode.next = nextNode and current.next = newNode.
  3160.  
  3161. Return head.
  3162.  
  3163. Case 3: List with a single node:
  3164.  
  3165. If current.next is equal to head, it means the list has only one node. In this case, the newNode should be inserted after this single node.
  3166.  
  3167. We set newNode.next = nextNode (which is head) and current.next = newNode.
  3168.  
  3169. Return head.
  3170.  
  3171. Move the current pointer to the nextNode (current = nextNode) to continue traversing the list.
  3172.  
  3173. Include a safety break condition (if (current === head)) to handle cases where all values in the list are the same. In such a scenario, the insertVal can be inserted at any point, and this condition ensures we don't get into an infinite loop.
  3174.  
  3175. Time Complexity:
  3176. In the worst case, we might need to traverse the entire circular linked list once to find the correct insertion point. This happens when the insertVal is either the new minimum or the new maximum and needs to be inserted at the wrap-around point.
  3177.  
  3178. Therefore, the time complexity is O(N), where N is the number of nodes in the circular linked list.
  3179.  
  3180. Space Complexity:
  3181. We are creating only one new node for the insertVal.
  3182.  
  3183. The rest of the operations involve pointer manipulations and do not require additional data structures that scale with the input size.
  3184.  
  3185. Therefore, the space complexity is O(1).
  3186. */
  3187.  
  3188. /* ========================================================================================
  3189. 986. Interval List Intersections Medium
  3190.  
  3191. You are given two lists of closed intervals, firstList and secondList, where firstList[i] = [starti, endi] and secondList[j] = [startj, endj]. Each list of intervals is pairwise disjoint and in sorted order.
  3192.  
  3193. Return the intersection of these two interval lists.
  3194.  
  3195. A closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b.
  3196.  
  3197. The intersection of two closed intervals is a set of real numbers that are either empty or represented as a closed interval. For example, the intersection of [1, 3] and [2, 4] is [2, 3].
  3198.  
  3199.  
  3200. Example 1:
  3201.  
  3202.  
  3203. Input: firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]
  3204. Output: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]
  3205. Example 2:
  3206.  
  3207. Input: firstList = [[1,3],[5,9]], secondList = []
  3208. Output: []
  3209.  
  3210.  
  3211. Constraints:
  3212.  
  3213. 0 <= firstList.length, secondList.length <= 1000
  3214. firstList.length + secondList.length >= 1
  3215. 0 <= starti < endi <= 109
  3216. endi < starti+1
  3217. 0 <= startj < endj <= 109
  3218. endj < startj+1
  3219. */
  3220.  
  3221.  
  3222.  
  3223. /**
  3224.  * @param {number[][]} firstList
  3225.  * @param {number[][]} secondList
  3226.  * @return {number[][]}
  3227.  */
  3228. function intervalIntersection(firstList, secondList) {
  3229.     let i = 0;
  3230.     let j = 0;
  3231.     const result = [];
  3232.  
  3233.     while (i < firstList.length && j < secondList.length) {
  3234.         const [start1, end1] = firstList[i];
  3235.         const [start2, end2] = secondList[j];
  3236.  
  3237.         const low = Math.max(start1, start2);
  3238.         const high = Math.min(end1, end2);
  3239.  
  3240.         if (low <= high) {
  3241.             result.push([low, high]);
  3242.         }
  3243.  
  3244.         if (end1 < end2) {
  3245.             i++;
  3246.         } else {
  3247.             j++;
  3248.         }
  3249.     }
  3250.  
  3251.     return result;
  3252. }
  3253.  
  3254. // Usage Examples:
  3255.  
  3256. // Example 1:
  3257. const firstList1 = [[0, 2], [5, 10], [13, 23], [24, 25]];
  3258. const secondList1 = [[1, 5], [8, 12], [15, 24], [25, 26]];
  3259. const result1 = intervalIntersection(firstList1, secondList1);
  3260. console.log("Example 1:", result1); // Output: [[1, 2], [5, 5], [8, 10], [15, 23], [24, 24], [25, 25]]
  3261.  
  3262. // Example 2:
  3263. const firstList2 = [[1, 3], [5, 9]];
  3264. const secondList2 = [];
  3265. const result2 = intervalIntersection(firstList2, secondList2);
  3266. console.log("Example 2:", result2); // Output: []
  3267.  
  3268. // Example 3:
  3269. const firstList3 = [[1, 4], [7, 9], [11, 15]];
  3270. const secondList3 = [[2, 5], [6, 8], [10, 20]];
  3271. const result3 = intervalIntersection(firstList3, secondList3);
  3272. console.log("Example 3:", result3); // Output: [[2, 4], [6, 8], [10, 15]]
  3273.  
  3274. // Example 4: Overlapping intervals
  3275. const firstList4 = [[0, 5]];
  3276. const secondList4 = [[0, 5]];
  3277. const result4 = intervalIntersection(firstList4, secondList4);
  3278. console.log("Example 4:", result4); // Output: [[0, 5]]
  3279.  
  3280. // Example 5: No intersection
  3281. const firstList5 = [[1, 2]];
  3282. const secondList5 = [[3, 4]];
  3283. const result5 = intervalIntersection(firstList5, secondList5);
  3284. console.log("Example 5:", result5);  // Output: []
  3285.  
  3286. /* ========================================================================================
  3287.  
  3288. 1091. Shortest Path in Binary Matrix Medium
  3289.  
  3290. Given an n x n binary matrix grid, return the length of the shortest clear path in the matrix. If there is no clear path, return -1.
  3291.  
  3292. A clear path in a binary matrix is a path from the top-left cell (i.e., (0, 0)) to the bottom-right cell (i.e., (n - 1, n - 1)) such that:
  3293.  
  3294. All the visited cells of the path are 0.
  3295. All the adjacent cells of the path are 8-directionally connected (i.e., they are different and they share an edge or a corner).
  3296. The length of a clear path is the number of visited cells of this path.
  3297.  
  3298. Example 1:
  3299.  
  3300. Input: grid = [
  3301. [0,1],
  3302. [1,0]
  3303. ]
  3304. Output: 2
  3305. Example 2:
  3306.  
  3307. Input: grid = [
  3308. [0,0,0],
  3309. [1,1,0],
  3310. [1,1,0]
  3311. ]
  3312. Output: 4
  3313. Example 3:
  3314.  
  3315. Input: grid = [
  3316. [1,0,0],
  3317. [1,1,0],
  3318. [1,1,0]
  3319. ]
  3320. Output: -1
  3321.  
  3322. Constraints:
  3323.  
  3324. n == grid.length
  3325. n == grid[i].length
  3326. 1 <= n <= 100
  3327. grid[i][j] is 0 or 1
  3328.  
  3329. To solve the shortest clear path in a binary matrix, we can use Breadth-First Search (BFS). BFS is ideal for shortest-path problems in unweighted grids because it explores neighbors level by level.
  3330.  
  3331. ✅ Problem Requirements Recap
  3332. Move from top-left (0, 0) to bottom-right (n-1, n-1)
  3333.  
  3334. Only walk on 0s (clear cells)
  3335.  
  3336. Movement is 8-directional (horizontal, vertical, diagonal)
  3337.  
  3338. Return the length of the shortest path or -1 if impossible
  3339.  
  3340. ✅ Approach: BFS
  3341. If the start or end is blocked (grid[0][0] == 1 or grid[n-1][n-1] == 1), return -1
  3342.  
  3343. Use a queue to perform BFS from (0, 0)
  3344.  
  3345. Store current position and path length in queue: [[x, y, steps]]
  3346.  
  3347. For each move, check all 8 directions and only visit cells that are 0 and unvisited
  3348.  
  3349. If we reach (n-1, n-1), return the path length
  3350.  
  3351. ✅ Directions (8 total)
  3352. text
  3353. Copy
  3354. Edit
  3355. (-1,-1) (-1,0) (-1,1)
  3356. (0,-1)   *     (0,1)
  3357. (1,-1)  (1,0)  (1,1)
  3358.  
  3359. ✅ Time & Space Complexity
  3360. Time Complexity: O(n^2) — each cell is visited at most once
  3361.  
  3362. Space Complexity: O(n^2) — for the queue and marking visited
  3363.  
  3364. */
  3365.  
  3366. function shortestPathBinaryMatrix(grid) {
  3367.   const n = grid.length;
  3368.   if (grid[0][0] !== 0 || grid[n - 1][n - 1] !== 0) return -1;
  3369.  
  3370.   const directions = [
  3371.     [-1, -1], [-1, 0], [-1, 1],
  3372.     [0, -1],          [0, 1],
  3373.     [1, -1],  [1, 0], [1, 1]
  3374.   ];
  3375.  
  3376.   const queue = [[0, 0, 1]]; // [x, y, steps]
  3377.   let head = 0;
  3378.   grid[0][0] = 1; // mark as visited
  3379.  
  3380.   while (head < queue.length) {
  3381.     const [x, y, steps] = queue[head++];
  3382.    
  3383.     if (x === n - 1 && y === n - 1) return steps;
  3384.  
  3385.     for (const [dx, dy] of directions) {
  3386.       const nx = x + dx;
  3387.       const ny = y + dy;
  3388.  
  3389.       if (nx >= 0 && ny >= 0 && nx < n && ny < n && grid[nx][ny] === 0) {
  3390.         queue.push([nx, ny, steps + 1]);
  3391.         grid[nx][ny] = 1; // mark visited
  3392.       }
  3393.     }
  3394.   }
  3395.  
  3396.   return -1;
  3397. }
  3398.  
  3399. console.log(shortestPathBinaryMatrix([[0,1],[1,0]])); // 2
  3400. console.log(shortestPathBinaryMatrix([[0,0,0],[1,1,0],[1,1,0]])); // 4
  3401. console.log(shortestPathBinaryMatrix([[1,0,0],[1,1,0],[1,1,0]])); // -1
  3402.  
  3403.  
  3404.  
  3405.  
  3406.  
  3407. /**
  3408.  * @param {number[][]} grid
  3409.  * @return {number}
  3410.  */
  3411. function shortestPathBinaryMatrix(grid) {
  3412.     const n = grid.length;
  3413.  
  3414.     // Check if the start or end is blocked.
  3415.     if (grid[0][0] === 1 || grid[n - 1][n - 1] === 1) {
  3416.         return -1;
  3417.     }
  3418.  
  3419.     // If it's a 1x1 matrix and the only cell is 0, the shortest path is 1.
  3420.     if (n === 1 && grid[0][0] === 0) {
  3421.         return 1;
  3422.     }
  3423.  
  3424.     const queue = [[0, 0, 1]]; // [row, col, pathLength]
  3425.     let queueFront = 0; // Index to track the front of the queue
  3426.     grid[0][0] = 1; // Mark the starting cell as visited.
  3427.  
  3428.     const directions = [
  3429.         [0, 1], [0, -1], [1, 0], [-1, 0],
  3430.         [1, 1], [1, -1], [-1, 1], [-1, -1]
  3431.     ];
  3432.  
  3433.     while (queueFront < queue.length) { // Use queueFront < queue.length as the loop condition
  3434.         const [row, col, pathLength] = queue[queueFront];
  3435.         queueFront++; // Increment queueFront instead of shifting
  3436.  
  3437.         for (const [dRow, dCol] of directions) {
  3438.             const newRow = row + dRow;
  3439.             const newCol = col + dCol;
  3440.  
  3441.             if (newRow >= 0 && newRow < n && newCol >= 0 && newCol < n && grid[newRow][newCol] === 0) {
  3442.                 if (newRow === n - 1 && newCol === n - 1) {
  3443.                     return pathLength + 1;
  3444.                 }
  3445.                 grid[newRow][newCol] = 1; // Mark cell as visited
  3446.                 queue.push([newRow, newCol, pathLength + 1]);
  3447.             }
  3448.         }
  3449.     }
  3450.     return -1;
  3451. }
  3452.  
  3453. // Example 1:
  3454. const grid1 = [[0, 1], [1, 0]];
  3455. console.log("Example 1:", shortestPathBinaryMatrix(grid1)); // Output: 2
  3456.  
  3457. // Example 2:
  3458. const grid2 = [[0, 0, 0], [1, 1, 0], [1, 1, 0]];
  3459. console.log("Example 2:", shortestPathBinaryMatrix(grid2)); // Output: 4
  3460.  
  3461. // Example 3:
  3462. const grid3 = [[1, 0, 0], [1, 1, 0], [1, 1, 0]];
  3463. console.log("Example 3:", shortestPathBinaryMatrix(grid3)); // Output: -1
  3464.  
  3465. // Example 4: A clear path exists
  3466. const grid4 = [[0, 0, 0], [0, 1, 0], [0, 0, 0]];
  3467. console.log("Example 4:", shortestPathBinaryMatrix(grid4)); // Output: 3
  3468.  
  3469. // Example 5: No clear path
  3470. const grid5 = [[1, 1, 1], [1, 1, 1], [1, 1, 1]];
  3471. console.log("Example 5:", shortestPathBinaryMatrix(grid5)); // Output: -1
  3472.  
  3473. /*
  3474. Approach:
  3475.  
  3476. The approach is the same as the previous solution, using Breadth-First Search (BFS), but with a modification to avoid using the shift() method, which can have a time complexity of O(n) in some JavaScript implementations.
  3477.  
  3478. Base Cases and Input Validation: Same as before.
  3479. BFS Initialization:
  3480. Initialize a queue as before.
  3481. Initialize queueFront = 0; This variable will keep track of the index of the element at the front of the queue.
  3482. Mark the starting cell as visited.
  3483. BFS Traversal:
  3484. The while loop continues as long as queueFront is less than queue.length. This condition effectively checks if there are still elements to process in the queue.
  3485. Inside the loop:
  3486. Get the element at the front of the queue using queue[queueFront].
  3487. Increment queueFront by 1. This is equivalent to "dequeueing" the element, but without modifying the array itself. We are just moving the pointer to the next element.
  3488. The rest of the logic (checking for the destination, generating neighbors, checking validity, marking visited, and enqueuing) remains the same as before.
  3489. No Path Found: Same as before.
  3490. Time Complexity:
  3491.  
  3492. The key change is how we process the queue. Instead of shift(), which can be O(n), we use queueFront to track the front of the queue. This allows us to "dequeue" elements in O(1) time.
  3493. The rest of the operations are the same as before.
  3494. Therefore, the overall time complexity remains O(n<sup>2</sup>), where n is the dimension of the grid.
  3495. Space Complexity:
  3496.  
  3497. The space complexity is the same as the previous solution. The queue can still, in the worst case, contain all the cells in the grid.
  3498. Therefore, the space complexity is O(n<sup>2</sup>).
  3499. */
  3500.  
  3501.  
  3502. /* ======================================================
  3503.  
  3504. 921. Minimum Add to Make Parentheses Valid Medium
  3505.  
  3506. A parentheses string is valid if and only if:
  3507.  
  3508. It is the empty string,
  3509. It can be written as AB (A concatenated with B), where A and B are valid strings, or
  3510. It can be written as (A), where A is a valid string.
  3511. You are given a parentheses string s. In one move, you can insert a parenthesis at any position of the string.
  3512.  
  3513. For example, if s = "()))", you can insert an opening parenthesis to be "(()))" or a closing parenthesis to be "())))".
  3514. Return the minimum number of moves required to make s valid.
  3515.  
  3516.  
  3517. Example 1:
  3518.  
  3519. Input: s = "())"
  3520. Output: 1
  3521. Example 2:
  3522.  
  3523. Input: s = "((("
  3524. Output: 3
  3525.  
  3526.  
  3527. Constraints:
  3528.  
  3529. 1 <= s.length <= 1000
  3530. s[i] is either '(' or ')'.
  3531.  
  3532. Approach:
  3533.  
  3534. The problem asks for the minimum number of parentheses to add to a given string to make it valid. A valid parentheses string has a balanced number of opening and closing parentheses, and for every closing parenthesis, there must be a corresponding opening parenthesis before it.
  3535.  
  3536. The approach uses a simple counter-based method:
  3537.  
  3538. Initialize Counters:
  3539.  
  3540. Initialize openCount to 0, representing the count of unmatched opening parentheses.
  3541. Initialize closeCount to 0, representing the count of unmatched closing parentheses.
  3542. Iterate Through the String:
  3543.  
  3544. Iterate through each character in the input string s.
  3545. If the character is an opening parenthesis '(':
  3546. Increment openCount.
  3547. If the character is a closing parenthesis ')':
  3548. If there is an unmatched opening parenthesis (openCount > 0):
  3549. Decrement openCount (because this closing parenthesis can be matched with an existing opening one).
  3550. Otherwise (if openCount is 0):
  3551. Increment closeCount (because this closing parenthesis is unmatched and requires an opening parenthesis to be inserted).
  3552. Calculate the Result:
  3553.  
  3554. After iterating through the entire string, openCount will hold the number of unmatched opening parentheses, and closeCount will hold the number of unmatched closing parentheses.
  3555. The total number of parentheses needed to make the string valid is the sum of openCount and closeCount.
  3556. Time Complexity:
  3557.  
  3558. The code iterates through the input string s once.
  3559. All operations inside the loop (character comparison, counter increments/decrements) take constant time.
  3560. Therefore, the time complexity is O(n), where n is the length of the string s.
  3561. Space Complexity:
  3562.  
  3563. The code uses only two integer variables (openCount and closeCount) to store the counts.
  3564. These variables take constant space.
  3565. Therefore, the space complexity is O(1).
  3566.  
  3567. */
  3568.  
  3569. /**
  3570.  * @param {string} s
  3571.  * @return {number}
  3572.  */
  3573. function minAddToMakeValid(s) {
  3574.     let openCount = 0;
  3575.     let closeCount = 0;
  3576.  
  3577.     for (const char of s) {
  3578.         if (char === '(') {
  3579.             openCount++;
  3580.         } else if (openCount > 0) {
  3581.             openCount--;
  3582.         } else {
  3583.             closeCount++;
  3584.         }
  3585.     }
  3586.  
  3587.     return openCount + closeCount;
  3588. }
  3589.  
  3590. // Example 1:
  3591. const s1 = "())";
  3592. console.log("Example 1:", minAddToMakeValid(s1)); // Output: 1
  3593.  
  3594. // Example 2:
  3595. const s2 = "(((";
  3596. console.log("Example 2:", minAddToMakeValid(s2)); // Output: 3
  3597.  
  3598. // Example 3:
  3599. const s3 = "()";
  3600. console.log("Example 3:", minAddToMakeValid(s3)); // Output: 0
  3601.  
  3602. // Example 4:
  3603. const s4 = "()))((";
  3604. console.log("Example 4:", minAddToMakeValid(s4)); // Output: 4
  3605.  
  3606. // Example 5:
  3607. const s5 = "()()";
  3608. console.log("Example 5:", minAddToMakeValid(s5)); // Output: 0
  3609.  
  3610.  
  3611.  
Advertisement
Add Comment
Please, Sign In to add comment