├── .eslintrc.json ├── .gitignore ├── .vscode └── settings.json ├── 2-sum.js ├── E027_remove_element.js ├── Eazy └── 1189-max-no-of-baloons-substring.js ├── LeetCode-logo.png ├── Max_Average_Subarray-2.js ├── Max_Average_Subarray.js ├── Medium └── 3-Sum │ ├── 3-Sum-2nd-Slightly-Less-Than-2-Pointer.js │ ├── 3-Sum-3rd-2-Pointer-Best.js │ ├── 3-Sum-Brute-Force.js │ └── 3-Sum-Combined-Performance-Test.js ├── README.md ├── RangeSumQuery.js ├── Remove_Nth_Node_From_End_of_LinkedList.js ├── add-digits.js ├── integer_to_roman.js ├── isSuperUgly.js ├── isUgly-Find-nth-Ugly.js ├── isUgly.js ├── license-Key-Formatting.js ├── longest-Common-Prefix.js ├── longest_substring_without_repeating_char.js ├── majority_element.js ├── max-contiguous-subarray-general-Solution.js ├── max-sum-subarray.js ├── merge-sorted-array.js ├── merge-two-sorted-linked-lists.js ├── palindrome-number.js ├── product-of-Array-Except-Self-GOOD-LONG-EXPLANATION.js ├── product-of-Array-Except-Self-without-constraint.JS ├── remove-duplicates-from-sorted-array.js ├── reverse_integer.js ├── roman_to_integer.js ├── self-dividing-number.js ├── shortest-distance-to-a-character.js ├── string-to-integer-atoi-1.js ├── string-to-integer-atoi-2.js ├── valid-parentheses.js └── zigzag-conversion.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore docs files 2 | _gh_pages 3 | .ruby-version 4 | 5 | # Numerous always-ignore extensions 6 | *.diff 7 | *.err 8 | *.orig 9 | *.log 10 | *.rej 11 | *.swo 12 | *.swp 13 | *.zip 14 | *.vi 15 | *~ 16 | *.~lock* 17 | .~lock* 18 | 19 | # OS or Editor folders 20 | .DS_Store 21 | ._* 22 | Thumbs.db 23 | .cache 24 | .project 25 | .settings 26 | .tmproj 27 | *.esproj 28 | nbproject 29 | *.sublime-project 30 | *.sublime-workspace 31 | .idea 32 | 33 | # Komodo 34 | *.komodoproject 35 | .komodotools 36 | 37 | # grunt-html-validation 38 | validation-status.json 39 | validation-report.json 40 | 41 | # Folders to ignore 42 | node_modules 43 | Project-Note-PAUL 44 | 45 | 46 | # Ignore all logfiles and tempfiles. 47 | !/log/.keep 48 | /tmp 49 | /.gems 50 | 51 | random-code-1.js 52 | random-code-2.js 53 | random-code-3.js 54 | random-code-4.js 55 | performance-1.js 56 | 57 | 58 | #ignore file name ending in "-bkp.js" OR "-bkp.ts" OR "-bkp.py" OR "-test.js" OR "-test.ts" OR "-test.py" in its name. So I will have to put "-test.js" at all files that is just for my development-time random testing code . 59 | **/*-bkp.js 60 | **/*-bkp.ts 61 | **/*-bkp.py 62 | **/*-test.js 63 | **/*-test.ts 64 | **/*-test.py -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "workbench.colorTheme": "Sunburst", 4 | "files.associations": { 5 | "*.js": "javascript" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /2-sum.js: -------------------------------------------------------------------------------- 1 | // Look at my detail blog post at - https://rohan-paul.github.io/javascript/2018/04/29/2-sum/ 2 | 3 | /*https://leetcode.com/problems/two-sum/description/ 4 | 5 | Given an array of integers, return indices of the two numbers such that they add up to a specific target. 6 | 7 | You may assume that each input would have exactly one solution, and you may not use the same element twice. 8 | 9 | Example: 10 | Given nums = [2, 7, 11, 15], target = 9, 11 | 12 | Because nums[0] + nums[1] = 2 + 7 = 9, 13 | return [0, 1]. 14 | */ 15 | 16 | // My Solution 17 | var twoSum = function (nums, target) { 18 | var result = []; 19 | 20 | for (var i = 0; i < nums.length; i++) { 21 | for (var j = i + 1; j < nums.length; j++) { 22 | if (nums[i] + nums[j] === target) { 23 | result.push(i); 24 | result.push(j); 25 | } 26 | } 27 | } 28 | return result; 29 | } 30 | 31 | // console.log(twoSum([2, 7, 11, 15], 17)); 32 | /* Complexity Analysis of above solution by me - https://leetcode.com/problems/two-sum/solution/ 33 | 34 | Time complexity : O(n^2). For each element, we try to find its complement by looping through the rest of array which takes O(n)O(n) time. Therefore, the time complexity is O(n^2). Space complexity : O(1). */ 35 | 36 | // Alternative solution 37 | var twoSumAlt = function(nums, target) { 38 | var result = []; 39 | nums.forEach(function(num, i) { 40 | var diff = target - num; 41 | var k = nums.indexOf(diff); 42 | if ( k > -1 && k !== i) { 43 | result.push(i); 44 | result.push(k); 45 | } 46 | }); 47 | return result; 48 | } 49 | 50 | /*There are 3 approaches to this solution: 51 | 52 | Let the sum be T and n be the size of array 53 | 54 | Approach 1: 55 | The naive way to do this would be to check all combinations (n choose 2). This exhaustive search is O(n2). 56 | 57 | Approach 2: 58 | A better way would be to sort the array. This takes O(n log n) 59 | Then for each x in array A, use binary search to look for T-x. This will take O(nlogn). 60 | So, overall search is O(n log n) 61 | 62 | Approach 3 : 63 | The best way would be to insert every element into a hash table (without sorting). This takes O(n) as constant time insertion. 64 | Then for every x, we can just look up its complement, T-x, which is O(1). 65 | Overall the run time of this approach is O(n).*/ 66 | 67 | /*Best Solution in O(n) time - 68 | 69 | https://leetcode.com/problems/two-sum/solution/ 70 | 71 | Here, under the first for loop, I am doing a < numsObject[num] = i > which means, I am assigning the actual array element value to be the key in the key-value pair of the object / associative-array. And the index-no of that element (i) of that array to be the value in the key-value object. 72 | Then with each iteration, will check with hasOwnPropery() if the key exists. And the key will be the other element, i.e. the difference from the target. 73 | We reduce the look up time from O(n)O(n) to O(1)O(1) by trading space for speed. A hash table is built exactly for this purpose, it supports fast look up in near constant time. I say "near" because if a collision occurred, a look up could degenerate to O(n)O(n) time. But look up in hash table should be amortized O(1)O(1) time as long as the hash function was chosen carefully. 74 | */ 75 | function twoSum_O_n_time(arr, target) { 76 | let numObject = {}; 77 | for (var i = 0; i < arr.length; i++) { 78 | let thisNum = "" + arr[i]; 79 | numObject[thisNum] = i; 80 | } 81 | for (var i = 0; i < arr.length; i++) { 82 | let diff = target - arr[i]; 83 | if (numObject.hasOwnProperty(diff.toString()) && numObject[diff.toString()] !== i) { 84 | return [i, numObject[diff.toString()]]; 85 | } 86 | } 87 | } 88 | // console.log(twoSum_On_Best([2, 7, 11, 15], 9)); 89 | 90 | /*Complexity Analysis of the above best-case O(n) time solution. 91 | 92 | Time complexity : O(n)). We traverse the list containing n elements exactly twice. Since the hash table reduces the look up time to O(1), the time complexity is O(n). 93 | 94 | Space complexity : O(n). The extra space required depends on the number of items stored in the hash table, which stores exactly nn elements. 95 | */ 96 | 97 | 98 | /* The best solution - 99 | While we iterate and inserting elements into the table, we also look back to check if current element's complement already exists in the table. If it exists, we have found a solution and return immediately. 100 | So, basically we are doing the checking in one-pass. */ 101 | 102 | function twoSumBest(array, target) { 103 | const numsMap = new Map(); 104 | for (let i = 0; i < array.length; i++) { 105 | if(numsMap.has(target - array[i])) { 106 | return [numsMap.get(target - array[i], i)]; 107 | // get() returns a specified element associated with the specified key from the Map object. 108 | } else { 109 | numsMap.set(array[i], i); 110 | // set() adds or updates an element with a specified key and value to a Map object. 111 | } 112 | } 113 | } 114 | 115 | /* Time complexity : O(n). We traverse the list containing nn elements only once. Each look up in the table costs only O(1) time. 116 | 117 | Space complexity : O(n). The extra space required depends on the number of items stored in the hash table, which stores at most nn elements. 118 | 119 | In the above, I also used Map rather than use an object literal as a map given V8 has recently added significant performance improvements to Map and Set making them indispensable as lookups. 120 | */ 121 | 122 | 123 | 124 | // Performance Test - First create a random array with 3000 elements 125 | 126 | var arr = Array.from({length: 3000}, () => Math.floor(Math.random() * 3000)); 127 | 128 | 129 | console.time("Solution-1-Brute Force"); 130 | twoSum(arr, (arr[668] + arr[1669])); 131 | console.timeEnd("Solution-1-Brute Force"); 132 | 133 | console.log("*******************************"); 134 | 135 | console.time("Solution-2-Slightly Improved"); 136 | twoSumAlt(arr, (arr[668] + arr[1669])); 137 | console.timeEnd("Solution-2-Slightly Improved"); 138 | 139 | console.log("*******************************"); 140 | 141 | console.time("Solution-3-O(n) time with HashMap"); 142 | twoSum_O_n_time(arr, (arr[668] + arr[1669])); 143 | console.timeEnd("Solution-3-O(n) time with HashMap"); 144 | 145 | console.log("*******************************"); 146 | 147 | console.time("Solution-4-Even more efficient solution"); 148 | twoSumBest(arr, (arr[668] + arr[1669])); 149 | console.timeEnd("Solution-4-Even more efficient solution"); 150 | -------------------------------------------------------------------------------- /E027_remove_element.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/remove-element/description/ 2 | 3 | Given an array and a value, remove all instances of that value in-place and return the new length. 4 | 5 | Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. 6 | 7 | The order of elements can be changed. It doesn't matter what you leave beyond the new length. 8 | 9 | Example: 10 | 11 | Given nums = [3,2,2,3], val = 3, 12 | 13 | Your function should return length = 2, with the first two elements of nums being 2.*/ 14 | 15 | /*My solution steps - First read about in-place Algo ( https://en.wikipedia.org/wiki/In-place_algorithm ) 16 | 17 | Basically, under this algo, a small amount of extra storage space is allowed for auxiliary variables (which in this case is the variable 'tmp') 18 | 19 | A> Create two pointers from beginning and end ( the variables head and tail in this code) 20 | 21 | A> Take the first element of the array (i.e. index starting with 0) and compare it to the given "val" 22 | 23 | B> If it matches, do the following 24 | 25 | (i) Swap the value of head with the tail. This is because, I want moved the matched value to the end of the array, and then reduce tail by doing tail-- So I can completely ignore that matched value for all my future calculations. Effectively I have removed the matched valued. 26 | 27 | (ii) Decrement tail by one. Because, when there's a match, I am removing that particular element from the Array fully, i.e. removing it from all counting. Which means I have to reduce the numerical index value of (nums.length - 1) by one. 28 | 29 | Also, with the swapping code, I have already swapped the original value of tail by assigning it to head. So, decrementing tail will have no impact on the comparisons to be made for the next iteration, as that matched valued needs to be effectively taken out of scene completely. 30 | 31 | C> Else, if it DOES NOT match, increment the value of head by 1, and then compare the second element of the array with the given "val". 32 | So, for each non-matching character (with the given 'value') - I am incrementing 'head' by one. Meaning, at the end of the array the final value of 'head' will be my length of array. 33 | 34 | E> Do this loops till the last element of the array 35 | */ 36 | 37 | var removeElement = function (nums, val) { 38 | var head = 0; // index of the first element of the array 39 | var tail = nums.length - 1; // index of the last element of the array 40 | 41 | while ( head <= tail ) { 42 | // console.log("value of A[i] in next iteration for comparison " + nums[head]); 43 | if (nums[head] === val) { 44 | var temp = nums[head]; 45 | nums[head] = nums[tail]; 46 | nums[tail] = temp; 47 | tail--; 48 | // console.log("value of A[i] after swaping " + nums[head]); 49 | } else { 50 | head++; 51 | } 52 | } 53 | return head; 54 | } 55 | 56 | console.log(removeElement([3,2,2,3, 4, 5], 3)); 57 | 58 | 59 | //Alternative solution (but not implementing in-place algo) 60 | var removeElement_alt = function(nums, val) { 61 | for (var i = 0; i < nums.length; i++) { 62 | if (nums[i] === val) { 63 | nums.splice(i, 1); // Remember splice() mutates the original array. So on the next iteration, the value of nums.length will be reduced by 1 64 | } 65 | } 66 | return nums.length; 67 | } 68 | 69 | console.log(removeElement_alt([3,2,2,3, 4, 5], 3)); 70 | 71 | // SOLUTION - 3 - Same as above, just starting the loop from the end of the array 72 | removeElement_3 = (nums, val) => { 73 | for (let i = nums.length - 1; i >= 0; i--) { 74 | if (nums[i] === val ) { 75 | nums.splice(i, 1) 76 | } 77 | } 78 | return nums.length; 79 | } 80 | 81 | console.log(removeElement_3([3,2,2,3, 4, 5], 3)); 82 | 83 | 84 | // SOLUTION-4 85 | removeElements_4 = (nums, val) => { 86 | let index = 0; 87 | for (let i = 0; i < nums.length; i++) { 88 | if (nums[i] !== val) { 89 | index++ 90 | } 91 | } 92 | return index; 93 | } 94 | 95 | console.log(removeElements_4([3,2,2,3, 4, 5], 3)); 96 | 97 | 98 | // SOLUTION-5 99 | removeElements_5 = (nums, val) => { 100 | while (nums.indexOf(val) !== -1) { 101 | nums.splice(nums.indexOf(val), 1) 102 | } 103 | return nums.length 104 | } 105 | 106 | console.log(removeElements_5([3,2,2,3, 4, 5], 3)); -------------------------------------------------------------------------------- /Eazy/1189-max-no-of-baloons-substring.js: -------------------------------------------------------------------------------- 1 | /* Problem - https://leetcode.com/problems/maximum-number-of-balloons/description/ 2 | 3 | Given a string text, you want to use the characters of text to form as many instances of the word "balloon" as possible. 4 | You can use each character in text at most once. Return the maximum number of instances that can be formed. 5 | 6 | Example 1: 7 | Input: text = "nlaebolko" 8 | Output: 1 9 | 10 | Example 2: 11 | Input: text = "loonbalxballpoon" 12 | Output: 2 13 | 14 | Example 3: 15 | Input: text = "leetcode" 16 | Output: 0 17 | 18 | */ 19 | 20 | const WORD = "balloon" 21 | 22 | const maxNumberOfBalloons = text => { 23 | // First a function to return Hash to keep count of letter occurrence 24 | 25 | /* const charCounter = str => { 26 | let charCount = {} 27 | for (let i = 0; i < str.length; i++) { 28 | if (!charCount[str[i]]) { 29 | charCount[str[i]] = 0 30 | } 31 | charCount[str[i]]++ 32 | } 33 | return charCount 34 | } */ 35 | 36 | // Another way to write the same above function to build the hash counter 37 | const charCounter = str => { 38 | let charCount = {} 39 | for (let i = 0; i < str.length; i++) { 40 | if (!charCount[str[i]]) { 41 | charCount[str[i]] = 1 42 | } else { 43 | charCount[str[i]] = 1 + charCount[str[i]] 44 | } 45 | } 46 | return charCount 47 | } 48 | 49 | let minFreq = 9999 50 | let wordHash = charCounter(WORD) 51 | let textHash = charCounter(text) 52 | 53 | Object.keys(wordHash).forEach(key => { 54 | if (!textHash[key]) { 55 | minFreq = 0 56 | return minFreq 57 | } 58 | let freq = parseInt(textHash[key] / wordHash[key]) 59 | if (freq < minFreq) minFreq = freq 60 | }) 61 | return minFreq 62 | } 63 | 64 | console.log(maxNumberOfBalloons("nlaebolko")) // 1 65 | console.log(maxNumberOfBalloons("loonbalxballpoon")) // 2 66 | console.log(maxNumberOfBalloons("leetcode")) // 0 67 | -------------------------------------------------------------------------------- /LeetCode-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohan-paul/LeetCode_Solution_JS/68feacb13f7be8d65765ad03cf23b0e9a0012e9d/LeetCode-logo.png -------------------------------------------------------------------------------- /Max_Average_Subarray-2.js: -------------------------------------------------------------------------------- 1 | /* SOLUTION - 1 - Implementing Kadane's Algo - in a slightly different way 2 | 3 | Kadane's Algo - Basically I have to look for all contiguous sub-arrays of size 4, and also keep track of the maximum sum contiguous sub-array until the end. Whenever I find a new contiguous sub-array, I check if the current sum is greater than the max_sum so far and updates it accordingly. 4 | 5 | C) In the first loop is I am just generating the sum of the sub-array of the first 4 elements. 6 | 7 | D) In the second loop, I am traversing a sliding window - at each iteration, I am deducting the first element from left and adding next element to the right. And after doing this, updating the max_so_far to its highest value, by comparing it to its previous highest value. 8 | 9 | So for first loop of < curr_max += (nums[j] - nums[j - k]); > will do curr_max += nums[j] - muns[0] 10 | 11 | That is its adding one element on the right and deducting one element on the left. 12 | 13 | Here, instead of running 2 separate loops, I am doing the sliding-window mechanism within the same loop 14 | 15 | */ 16 | 17 | maxSumSubArrayAverage = (arr, k) => { 18 | 19 | let finalMax = -Infinity; 20 | 21 | let currentMaxSum = 0; 22 | 23 | for (let i = 0; i < arr.length; i++) { 24 | 25 | currentMaxSum += arr[i]; 26 | 27 | // But as soon as i exceeds k, I have to start deducting left side elements, so the total no of sub-array elementes are maintained at k 28 | 29 | if (i >= k ) { 30 | currentMaxSum -= arr[i - k] // So when I react i = k, the left-most element (with index 0 ) will be deducted from the sum. 31 | } 32 | 33 | // And for each sub-array with 4 elements, I have to compare the sum and update it. So comparison will only start after the first 4 elements sum has been caluclated. So, it becomes a train of 4 elementst starting from the 4th-element. 34 | if ( i >= k - 1) { 35 | finalMax = Math.max(currentMaxSum, finalMax); 36 | } 37 | } 38 | return finalMax / k; 39 | } 40 | 41 | console.log(maxSumSubArrayAverage([1, 12, -5, -6, 50, 3], 4)); 42 | 43 | // SOLUTION - 2 (Kadane's Algo) 44 | 45 | maxSumSubArrayAverage2 = (arr, k) => { 46 | 47 | let finalMax = -Infinity; 48 | 49 | let currentMax = 0; 50 | 51 | for (let i = 0; i < arr.length; i++) { 52 | 53 | currentMax += (arr[i] - ( arr[i - k] || 0 ) ) ; 54 | // What a beautiful way to reduce left elements beyond k 55 | 56 | if ( i >= k - 1) finalMax = Math.max(currentMax, finalMax) 57 | } 58 | return finalMax / k 59 | } 60 | 61 | console.log(maxSumSubArrayAverage2([1, 12, -5, -6, 50, 3], 4)); -------------------------------------------------------------------------------- /Max_Average_Subarray.js: -------------------------------------------------------------------------------- 1 | /* Original Problem Statement - Maximum Average Subarray 2 | 3 | https://leetcode.com/contest/leetcode-weekly-contest-41/problems/maximum-average-subarray-i/ 4 | 5 | Given an array consisting of n integers, find the contiguous subarray of given length k that has the maximum average value. And you need to output the maximum average value. 6 | 7 | Example 1: 8 | Input: [1,12,-5,-6,50,3], k = 4 9 | Output: 12.75 10 | Explanation: Maximum average is (12-5-6+50)/4 = 51/4 = 12.75 11 | 12 | Note: 13 | 1 <= k <= n <= 30,000. 14 | Elements of the given array will be in the range [-10,000, 10,000]. 15 | 16 | */ 17 | 18 | /* SOLUTION-1 19 | A) If N is number of elements in an array and k is each window size, then the number of windows possible is = N-k+1 . So in my below example that would be 6 - 4 + 1 i.e. 3 20 | 21 | B) Kadane's Algo - Basically I have to look for all contiguous sub-arrays of size 4, and also keep track of the maximum sum contiguous sub-array until the end. Whenever I find a new contiguous sub-array, I check if the current sum is greater than the max_sum so far and updates it accordingly. 22 | 23 | C) In the first loop is I am just generating the sum of the sub-array of the first 4 elements. 24 | 25 | D) In the second loop, I am traversing a sliding window - at each iteration, I am deducting the first element from left and adding next element to the right. And after doing this, updating the max_so_far to its highest value, by comparing it to its previous highest value. 26 | 27 | So for first loop of the second for-loop in the below function -> curr_max += (nums[j] - nums[j - k]); -> will do curr_max += nums[j] - muns[0] 28 | 29 | That is its adding one element on the right and deducting one element on the left. 30 | */ 31 | 32 | function findMaxAverage(nums, k) { 33 | let curr_max = 0 34 | 35 | for (let i = 0; i < k; i++) { 36 | curr_max += nums[i] 37 | } 38 | 39 | var max_so_far = curr_max 40 | 41 | // Now add one element to the front of the 'max_so_far' and delete one element from the back of 'max_so_far' 42 | // For example if nums.length is 5 and my k is 3 then the first time 'max_so_far' is calculated it will be the 43 | // first 3 items, then I have to add the 4-th item i.e. num[3] and delete the first item which will be 44 | // nums[j - k] i.e. num[3 - 3] 45 | for (var j = k; j < nums.length; j++) { 46 | curr_max += nums[j] - nums[j - k] 47 | 48 | // Each time we get a new curr_sum compare it with max_so_far and update max_so_far if it is greater than max_so_far 49 | max_so_far = Math.max(curr_max, max_so_far) 50 | } 51 | return max_so_far / k 52 | } 53 | 54 | // console.log(findMaxAverage([1, 12, -5, -6, 50, 3], 4)); // => 12.75 55 | 56 | /* SOLUTION-2 - General Maximum subarray problem solved with Brute Force. 57 | Find the contiguous subarray within a one-dimensional array of numbers which has the largest sum. For example, for the sequence of values −2, 1, −3, 4, −1, 2, 1, −5, 4; the contiguous subarray with the largest sum is 4, −1, 2, 1, with sum 6. 58 | 59 | 60 | In the below solutions we start at all positions of the array and calculate running sums. So here the time-compelxity is O(n^2). 61 | 62 | */ 63 | function findMaxSubArrayBruteForce2(arr) { 64 | var max_so_far = Number.NEGATIVE_INFINITY 65 | 66 | var leftIndex = 0, 67 | rightIndex = arr.length - 1, 68 | len = arr.length 69 | 70 | for (var i = 0; i < len; i++) { 71 | maxSum = 0 72 | 73 | for (var j = i; j < len; j++) { 74 | maxSum += arr[j] 75 | 76 | if (max_so_far < maxSum) { 77 | leftIndex = i 78 | max_so_far = maxSum 79 | rightIndex = j 80 | } 81 | } 82 | } 83 | 84 | // Inside the above, loop, the setting of leftIndex & rightIndex value is only for logging it in the final output. It has no impact on the final calculation of the maximum-sum-subarray 85 | 86 | return { 87 | left: leftIndex, 88 | right: rightIndex, 89 | final_max_sum_subArray: max_so_far, 90 | } 91 | } 92 | 93 | var array = [-2, 1, -3, 4, -1, 2, 1, -5, 4] 94 | 95 | // console.log(findMaxSubArrayBruteForce2(array)); 96 | 97 | /* SOLUTION-3 - In the below solutions we generate all (i, j): i <= j pairs and calculate the sum between. The time complexity is O(N^3) 98 | 99 | The difference between the O(N^2) and O(N^3) functions is that in the O(N^2) function, the sum is computed implicitly every time the end index is incremented, while in the O(N^3) function, the sum is computed with a third explicit loop between start and end 100 | */ 101 | 102 | function findMaxSubArrayBruteForce3(arr) { 103 | var max_so_far = Number.NEGATIVE_INFINITY 104 | var leftIndex = 0, 105 | rightIndex = arr.length - 1, 106 | len = arr.length 107 | 108 | for (var i = 0; i < len; i++) { 109 | for (var j = i; j < len; j++) { 110 | maxSum = 0 111 | for (var k = i; k <= j; k++) { 112 | maxSum += arr[k] 113 | 114 | if (max_so_far < maxSum) { 115 | leftIndex = i 116 | max_so_far = maxSum 117 | rightIndex = j 118 | } 119 | } 120 | } 121 | } 122 | return { 123 | left: leftIndex, 124 | right: rightIndex, 125 | final_max_sum_subArray: max_so_far, 126 | } 127 | } 128 | 129 | var array = [-2, 1, -3, 4, -1, 2, 1, -5, 4] 130 | 131 | console.log(findMaxSubArrayBruteForce3(array)) 132 | -------------------------------------------------------------------------------- /Medium/3-Sum/3-Sum-2nd-Slightly-Less-Than-2-Pointer.js: -------------------------------------------------------------------------------- 1 | // Slightly lower performance than the 2-pointer-Best solution. But almost exactly the same solution. 2 | 3 | function threeSum2(arr) { 4 | 5 | arr.sort((a, b) => { 6 | return a - b; 7 | }); 8 | 9 | const result = []; 10 | 11 | for (let indexA = 0; indexA < arr.length - 2; indexA++) { 12 | 13 | // if (arr[indexA] > 0) return result; 14 | 15 | let indexB = indexA + 1; 16 | let indexC = arr.length - 1; 17 | 18 | if (indexA > 0 && arr[indexA] === arr[indexA - 1]) continue; 19 | 20 | while (indexB < indexC ) { 21 | 22 | let sum = arr[indexA] + arr[indexB] + arr[indexC]; 23 | 24 | if (sum < 0) { 25 | indexB++; 26 | } else if (sum > 0) { 27 | indexC--; 28 | } else { 29 | result.push([arr[indexA], arr[indexB], arr[indexC]]); 30 | while (arr[indexB] === arr[indexB + 1]) indexB++; 31 | while (arr[indexC] === arr[indexC - 1]) indexC-- 32 | indexB++; 33 | indexC--; 34 | } 35 | // The only difference with this solution and the 2-Pointer-BEST solution is that in this, I am doing all the indexB and indexC increment and decrement logic and operaion in the condition when sum = 0 . But in the best sollution I am doing this in the respecting sum < 0 or sum > 0 lines. But looks like this does not have any significant impact on speed of the program. 36 | } 37 | } 38 | return result; 39 | } 40 | 41 | console.log(threeSum2([-1, 0, 1, 2, -1, -4])); 42 | 43 | /* Main Performance Difference with the 2-Pointer-Best Solution - this one is SUPER IMPORTANT 44 | A> In this solution, I did not put the part < if (arr[indexA] > 0) return result; > immediately after I start thr first for loop. And as soon as I include it, this runs at equivalent spEed to the 2-Pointer best solution. 45 | 46 | B> In the 3-Sum-Combined-Performance.js file just experiment with commenting out this line from the solution-2 code, and immediately the result will be like 30ms for Sol-2 (this one) and 5ms (Best version) for Sol-3 47 | */ 48 | -------------------------------------------------------------------------------- /Medium/3-Sum/3-Sum-3rd-2-Pointer-Best.js: -------------------------------------------------------------------------------- 1 | /* Solution-3- FASTEST "2 pointer solution" in O(n^2) Time - 2 | 3 | A> First sort the array from lowest to highest. 4 | 5 | B> Now with each iteration of the first for loop, keeping a's value constant, I am looping the values of the next 2 variables b and c to check if (a + b + c = 0). b starting from indexA + 1 and increasing and c starting from the end of the array nums.length -1 and decreasing. 6 | 7 | C> If I see that the result (sum of Triplets i.e a + b + c) is more than zero, I can decrement from right-most elements to reach zero. 8 | And if the result is less than zero, I increment the b (middle element in the triplet) elements value. 9 | 10 | D> After all values of b and c are exhausted, I go back to the next iteration of the for loop for the next value of a. 11 | 12 | Given a has the lowest value after sorting the array, and with each value of a, I have already checked for all values of b and c to check if sum is zero - as soon as 'a' becomes > 0 I can return from the function. Because it means I have reached a point where all the subsequent values of the array will be higher than zero. So no point in iterating further. 13 | 14 | E> And 'a' will only take value upto (nums.length - 3) as the last 2 values will be taken by the subsequent 2 variables b and c 15 | 16 | G> 17 | */ 18 | var threeSumTwoPointer = function (nums) { 19 | nums.sort((a, b) => a - b); 20 | 21 | const result = []; 22 | 23 | if (!nums || nums.length < 3) return result; 24 | 25 | for (let indexA = 0; indexA < nums.length - 2; indexA++) { 26 | const a = nums[indexA]; 27 | 28 | if (a > 0) return result; 29 | if (a === nums[indexA - 1]) continue; 30 | 31 | let indexB = indexA + 1; 32 | let indexC = nums.length - 1; 33 | 34 | // Now check if sum is zero, and if NOT, then run the next set of 2 if loop to update indexB and indexC 35 | while (indexB < indexC) { 36 | const b = nums[indexB]; 37 | const c = nums[indexC]; 38 | 39 | if ((a + b + c) === 0) { 40 | result.push([a, b, c]); 41 | } 42 | 43 | // Now with the below 2 if functions, I am just implementing how the indexB and indexC will be incremented and decremented with each iteration and gets feeded back to the above while function ( while (indexB < indexC )) 44 | 45 | if ((a + b + c) >= 0) { 46 | while (nums[indexC - 1] === c) { indexC--; } // This is equivalent to continue in my previous implementation 47 | indexC--; 48 | } 49 | 50 | if((a + b + c ) <= 0) { 51 | while (nums[indexB + 1] === b) { indexB++ } // This is equivalent to continue in my previous implementation 52 | indexB++ 53 | } 54 | } 55 | } 56 | return result; 57 | 58 | } 59 | 60 | console.log(threeSumTwoPointer([-1, 0, 1, 2, -1, -4])); -------------------------------------------------------------------------------- /Medium/3-Sum/3-Sum-Brute-Force.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/3sum/description/ 2 | Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. Note: The solution set must not contain duplicate triplets. Example: Given array nums = [-1, 0, 1, 2, -1, -4], 3 | 4 | A solution set is: 5 | [ 6 | [-1, 0, 1], 7 | [-1, -1, 2] 8 | ]*/ 9 | 10 | /* Solution-1 My First solution which is CORRECT BUT WITH IT I GOT A FAILURE SAYING "TIME LIMIT EXCEEDED. Tried 2 times" 11 | 12 | Explanation - The requirement is to find all unique triplets in the array (The solution set must not contain duplicate triplets.). This means in the resultant array, no number would be repeated. So, I wil achieve this with the following 2 techniques. 13 | 14 | A> First sort the array. So if there are multiple numbers, like two 5's they will come sequentially. 15 | 16 | B> Then, within the loop, I will check for each iteration that the current element that I am taking is not === previous element. 17 | 18 | Complexity Analysis - 19 | Time complexity : O(n^3) 20 | Because each of these nested loops executes n times, the total time complexity is $$O(n^3)$$, where n is a size of an array. 21 | 22 | Space complexity : O(n^2). If we assume that resultant array is not considered as additional space we need $$O(n^2)$$ space for storing triplets in a set. 23 | */ 24 | 25 | var threeSum_Brute = function(nums) { 26 | nums = nums.sort(function (a, b) { 27 | return a - b; 28 | }); 29 | 30 | let uniqueTriplets = []; 31 | let i, j, k; 32 | let len = nums.length; 33 | 34 | for (i = 0; i < len; i++) { 35 | if (i > 0 && nums[i] === nums[i-1]) continue; // The continue statement "jumps over" one iteration in the loop. So, if 2 successive elements are same (i.e. duplicates) leave this iteration and jump over to the next one 36 | 37 | for (j = i + 1; j < len; j++) { 38 | if ( j > i + 1 && nums[j] === nums[j-1]) continue; 39 | 40 | for (k = j + 1; k < len; k++) { 41 | if (k > j + 1 && nums[k] === nums[k - 1]) continue; 42 | 43 | if ((nums[i] + nums[j] + nums[k]) === 0) { 44 | uniqueTriplets.push([nums[i], nums[j], nums[k]]); 45 | // Very imp - I am wrapping individual elements nums[i], nums[j], nums[k] into a wrapper-array in the .push function. So that the final output comes in multiple array as required by the original problem statement. 46 | } 47 | } 48 | } 49 | } 50 | return uniqueTriplets; 51 | } 52 | 53 | console.log(threeSum_Brute([-1, 0, 1, 2, -1, -4])); 54 | -------------------------------------------------------------------------------- /Medium/3-Sum/3-Sum-Combined-Performance-Test.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/3sum/description/ */ 2 | 3 | var threeSum_Brute = function(nums) { 4 | nums = nums.sort(function (a, b) { 5 | return a - b; 6 | }); 7 | 8 | let uniqueTriplets = []; 9 | let i, j, k; 10 | let len = nums.length; 11 | 12 | for (i = 0; i < len; i++) { 13 | if (i > 0 && nums[i] === nums[i-1]) continue; // The continue statement "jumps over" one iteration in the loop. So, if 2 successive elements are same (i.e. duplicates) leave this iteration and jump over to the next one 14 | 15 | for (j = i + 1; j < len; j++) { 16 | if ( j > i + 1 && nums[j] === nums[j-1]) continue; 17 | 18 | for (k = j + 1; k < len; k++) { 19 | if (k > j + 1 && nums[k] === nums[k - 1]) continue; 20 | 21 | if ((nums[i] + nums[j] + nums[k]) === 0) { 22 | uniqueTriplets.push([nums[i], nums[j], nums[k]]); 23 | // Very imp - I am wrapping individual elements nums[i], nums[j], nums[k] into a wrapper-array in the .push function. So that the final output comes in multiple array as required by the original problem statement. 24 | } 25 | } 26 | } 27 | } 28 | return uniqueTriplets; 29 | } 30 | 31 | // Solution-2 - 2-Pointer solution, but less optimized than the 3rd solution below. 32 | function threeSum2(arr) { 33 | 34 | arr.sort((a, b) => { 35 | return a - b; 36 | }); 37 | 38 | const result = []; 39 | 40 | for (let indexA = 0; indexA < arr.length - 2; indexA++) { 41 | 42 | // if (arr[indexA] > 0) return result; 43 | 44 | let indexB = indexA + 1; 45 | let indexC = arr.length - 1; 46 | 47 | if (indexA > 0 && arr[indexA] === arr[indexA - 1]) continue; 48 | 49 | while (indexB < indexC ) { 50 | 51 | let sum = arr[indexA] + arr[indexB] + arr[indexC]; 52 | 53 | if (sum < 0) { 54 | indexB++; 55 | } else if (sum > 0) { 56 | indexC--; 57 | } else { 58 | result.push([arr[indexA], arr[indexB], arr[indexC]]); 59 | while (arr[indexB] === arr[indexB + 1]) indexB++; 60 | while (arr[indexC] === arr[indexC - 1]) indexC-- 61 | indexB++; 62 | indexC--; 63 | } 64 | } 65 | } 66 | return result; 67 | } 68 | 69 | 70 | /* Solution-3- FASTEST "2 pointer solution" in O(n^2) Time */ 71 | var threeSumTwoPointer = function (nums) { 72 | nums.sort((a, b) => a - b); 73 | 74 | const result = []; 75 | 76 | if (!nums || nums.length < 3) return result; 77 | 78 | for (let indexA = 0; indexA < nums.length - 2; indexA++) { 79 | const a = nums[indexA]; 80 | 81 | if (a > 0) return result; 82 | if (a === nums[indexA - 1]) continue; 83 | 84 | let indexB = indexA + 1; 85 | let indexC = nums.length - 1; 86 | 87 | // Now check if sum is zero, and if NOT, then run the next set of 2 if loop to update indexB and indexC 88 | while (indexB < indexC) { 89 | const b = nums[indexB]; 90 | const c = nums[indexC]; 91 | 92 | if ((a + b + c) === 0) { 93 | result.push([a, b, c]); 94 | } 95 | 96 | // Now with the below 2 if functions, I am just implementing how the indexB and indexC will be incremented and decremented with each iteration and gets feeded back to the above while function ( while (indexB < indexC )) 97 | 98 | if ((a + b + c) >= 0) { 99 | while (nums[indexC - 1] === c) { indexC--; } // This is equivalent to continue in my previous implementation 100 | indexC--; 101 | } 102 | 103 | if((a + b + c ) <= 0) { 104 | while (nums[indexB + 1] === b) { indexB++ } // This is equivalent to continue in my previous implementation 105 | indexB++ 106 | } 107 | } 108 | } 109 | return result; 110 | 111 | } 112 | 113 | // Performance Test - First create a random array with 3000 elements 114 | 115 | var arr = Array.from({length: 2000}, () => Math.floor(Math.random() * 3000)); 116 | 117 | 118 | console.time("Solution-1-Brute Force"); 119 | threeSum_Brute(arr); 120 | console.timeEnd("Solution-1-Brute Force"); 121 | 122 | console.log("***************************************************"); 123 | 124 | console.time("Solution-2-Sub-Obtimal-2-Pointer"); 125 | threeSum2 (arr); 126 | console.timeEnd("Solution-2-Sub-Obtimal-2-Pointer"); 127 | 128 | console.log("***************************************************"); 129 | 130 | console.time("Solution-3-Optimized-Two-Pointer"); 131 | threeSumTwoPointer(arr); 132 | console.timeEnd("Solution-3-Optimized-Two-Pointer"); 133 | 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Leetcode.com 2 | ============ 3 | 4 | ![](https://github.com/rohan-paul/LeetCode_Solution_JS/blob/master/LeetCode-logo.png) 5 | 6 | My solutions to the coding challenges in [LeetCode.com](https://leetcode.com/rohan23/) in JavaScript. I shall update the repository as and when I progress through the problems. 7 | -------------------------------------------------------------------------------- /RangeSumQuery.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/range-sum-query-immutable/description/ 2 | 3 | Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. 4 | 5 | Example: 6 | Given nums = [-2, 0, 3, -5, 2, -1] 7 | 8 | sumRange(0, 2) -> 1 9 | sumRange(2, 5) -> -1 10 | sumRange(0, 5) -> -3 11 | 12 | */ 13 | 14 | var NumArray = function(nums) { 15 | this.arr = nums; 16 | }; 17 | 18 | /** 19 | * @param {number} i 20 | * @param {number} j 21 | * @return {number} 22 | */ 23 | NumArray.prototype.sumRange = function(i, j) { 24 | 25 | let result = 0; 26 | 27 | for (let index = i; index <= j; index++ ) { 28 | result += this.arr[index]; 29 | } 30 | return result; 31 | }; 32 | 33 | 34 | 35 | /** 36 | * Your NumArray object will be instantiated and called as such: 37 | * var obj = Object.create(NumArray).createNew(nums) 38 | * var param_1 = obj.sumRange(i,j) 39 | */ 40 | 41 | // var obj = Object.create(NumArray).createNew([-2, 0, 3, -5, 2, -1]); 42 | 43 | var obj = new NumArray([-2, 0, 3, -5, 2, -1]); 44 | 45 | var param_1 = obj.sumRange(0, 2); 46 | console.log(param_1); -------------------------------------------------------------------------------- /Remove_Nth_Node_From_End_of_LinkedList.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/ 2 | 3 | Given a linked list, remove the nth node from the end of list and return its head. 4 | 5 | For example, 6 | 7 | Given linked list: 1->2->3->4->5, and n = 2. 8 | 9 | After removing the second node from the end, the linked list becomes 1->2->3->5. 10 | Note: Given n will always be valid. Try to do this in one pass. */ 11 | 12 | /* 13 | A> In order to remove a node from a linked list, we need to find the node that is just before the node we want to remove. Once we find that node, we change its next property to no longer reference the removed node. But, the previous node is modified to point to the node after the removed node. So the key line of code will be 14 | 15 | prevNode.next = prevNode.next.next 16 | 17 | We are just skipping over the node we want to remove and linking the “previous” node with the node just after the one we are removing. 18 | 19 | 20 | B> The nth node from the end will be (list.length - n + 1)-th node from the begining of the Linked List. 21 | 22 | For example: 23 | 24 | 1-> 2 -> 3 -> 4 -> 5 -> 6 -> 7 25 | 26 | To return 2nd node from the end(n = 2), we need to return 6th (7 - 2 + 1) node from beginning which is node '6'. 27 | 28 | http://www.ideserve.co.in/learn/find-nth-node-from-the-end-of-linked-list 29 | 30 | C> So the problem could be simply reduced to another one : Remove the (L - n + 1)th node from the beginning in the list , where L is the list length. 31 | 32 | D> First we will add an auxiliary dummy or fake head node which in the below program I am naming as "currentNode", which points to the list head. The “dummy” node is used to simplify some corner cases such as a list with only one node, or removing the head of the list. The key step is we have to relink next pointer of the (L - n)th node to the (L - n + 2)th node and we are done. 33 | 34 | */ 35 | 36 | var removeNthFromEnd = function(head, n) { 37 | var list = [], 38 | currentNode = head; 39 | 40 | while(currentNode.next !== null) { 41 | list.push(currentNode); 42 | currentNode = currentNode.next; 43 | } 44 | list.push(currentNode); 45 | 46 | // Now we have to deal with 3 cases about the initial position of the node-to-be-removed. 47 | 48 | /* Case-1 >> When the node-to-be-removed is somewhere in between the last and first nodes of the linked-list. 49 | 50 | A) The link of the node before the removed node is redirected to point to the node the removed node is pointing to. 51 | 52 | B) But now the total length of the list has been reduced by one after removal of the n-th node, so the The new n-th node from the end will be (list.length - n + 1 - 1 )-th node from the beginning of the Linked List i.e. (list.length -n )-th node. 53 | 54 | C) And the node previous to the removed node will be ((list.length -n + 1) - 1 - 1)-th node, i.e. (list.length - n - 1)-th node. 55 | 56 | D) So, now, I have to link the node before the removed node to be redirected to point to the node after the removed node, which will be (list.length -n + 1)-th node. 57 | 58 | D) So I do, list[list.length - n - 1].next = list[list.length -n + 1] 59 | So, to remove the current element from the list, all we have to do is link previous.next with current.next . This way, the current element will be lost in the computer memory and will be available to be cleaned by the garbage collector. 60 | */ 61 | 62 | if (list.length -n - 1 >= 0 && list.length -n + 1 < list.length) { 63 | list[list.length - n - 1].next = list[list.length -n + 1]; 64 | return list[0]; 65 | } 66 | 67 | /* Case-2 >> If the node-to-be-removed was the first node of the Linked-list. 68 | That is, after removal the position of the previous-node to the removed-node will be negative. 69 | In this case, if the node-removed was the only node of the linked list then for the head of the list, return an empty array if list.length is <=1. ELSE, 70 | If the length is more than one, then return the index 1 element for the head. */ 71 | if(list.length - n - 1 < 0) { 72 | return list.length <=1 ? [] : list[1] 73 | } 74 | 75 | /* Case - 3 >> If the node-to-be-removed was the last node of the Linked-list. 76 | That is, after removal the previous node becomes the last node of the Linked-list, then just point its next-node to null.*/ 77 | 78 | if (list.length - n + 1 >= list.length) { 79 | list[list.length - n - 1 ].next = null; 80 | return list[0]; 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /add-digits.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/add-digits/description/#_=_ 2 | 3 | Given a non-negative integer num, repeatedly add all its digits until the result has only one digit. 4 | 5 | For example: 6 | 7 | Given num = 38, the process is like: 3 + 8 = 11, 1 + 1 = 2. Since 2 has only one digit, return it. 8 | 9 | Follow up: 10 | Could you do it without any loop/recursion in O(1) runtime?*/ 11 | 12 | // My solution using recursion 13 | 14 | var addDigits = function(num) { 15 | if(num < 10) { 16 | return num; 17 | } else { 18 | var str = num.toString().split(''); 19 | var repeatSum = str.reduce(function(prev, curr) { 20 | return parseInt(prev, 10) + parseInt(curr, 10); 21 | }); 22 | return addDigits(repeatSum); 23 | } 24 | }; 25 | 26 | // console.log(addDigits(9)); 27 | 28 | // Alternative - 2 - Same as above, but more compact 29 | 30 | addDigits4 = num => { 31 | let sum = (num + '').split('').reduce((a, b) => parseInt(a) + parseInt(b), 0); 32 | return sum >= 10 ? addDigits4(sum) : sum; 33 | } 34 | 35 | console.log(addDigits4(38)); 36 | 37 | //Beautiful solution without using recursion 38 | /* 39 | A> If the given num is less than 10 then num % 9 would always given that num 40 | B> But for the specific case when the num is 9, I have to get the result of 9, so to cover this specific case I do - (1+(9-1)%9) 41 | 42 | this method depends on this math Eqn for decimal number: 43 | 44 | N=(a[0] * 1 + a[1] * 10 + …a[n] * 10 ^n),and a[0]…a[n] are all between [0,9] 45 | 46 | we set M = a[0] + a[1] + …a[n] 47 | 48 | and another truth is that: 49 | 50 | 1 % 9 = 1 51 | 52 | 10 % 9 = 1 53 | 54 | 100 % 9 = 1 55 | 56 | so N % 9 = a[0] + a[1] + …a[n] 57 | 58 | means N % 9 = M 59 | 60 | so N = M (% 9) 61 | 62 | as 9 % 9 = 0,so we can make (n - 1) % 9 + 1 63 | 64 | */ 65 | addDigits2 = num => 1 + ((num-1) % 9); 66 | 67 | // console.log(addDigits2(38)); // => 2 68 | 69 | //Alternative-3 without Recursion 70 | 71 | addDigits3 = num => { 72 | 73 | num += '' // This is just converting the number to string, should be equivalent to num.toString() 74 | 75 | while (num.length !==1 ) { 76 | 77 | let sum = 0; 78 | 79 | for (let i = 0; i < num.length; i++) { 80 | sum += parseInt(num[i]); 81 | } 82 | 83 | // Now once the first sum is calculate for the first set of digits, now reset the original num to be equal to sum. So for the next while loop, that number's digits can be summed up 84 | 85 | num = '' + sum; 86 | } 87 | return parseInt(num); 88 | } 89 | 90 | console.log(addDigits3(38)); // => 2 -------------------------------------------------------------------------------- /integer_to_roman.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/integer-to-roman/description/ 2 | 3 | Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999.*/ 4 | 5 | /*Algorithm Logic - https://www.rapidtables.com/convert/number/how-number-to-roman-numerals.html 6 | 7 | https://www.geeksforgeeks.org/converting-decimal-number-lying-between-1-to-3999-to-roman-numerals/ 8 | 9 | Following is the list of Roman symbols which include subtractive cases also: 10 | 11 | Decimal value Roman numeral 12 | 1 I 13 | 4 IV 14 | 5 V 15 | 9 IX 16 | 10 X 17 | 40 XL 18 | 50 L 19 | 90 XC 20 | 100 C 21 | 400 CD 22 | 500 D 23 | 900 CM 24 | 1000 M 25 | 26 | Idea is to convert the units, tens, hundreds, and thousands places of the given number separately. If the digit is 0, then there’s no corresponding Roman numeral symbol. The conversion of digit’s 4’s and 9’s are little bit different from other digits because these digits follows subtractive notation. 27 | 28 | A> Compare given number with base values in the order 1000, 900, 500, 400, 50, 40, 10, 9, 5, 4, 1. 29 | 30 | B> Base value which is just smaller or equal to the given number will be the initial base value (largest base value) . 31 | 32 | C> Divide the number by its largest base value, the corresponding base symbol will be repeated quotient times, the remainder will then become the number for future division and repetitions. 33 | 34 | D> The process will be repeated until the number becomes zero. */ 35 | 36 | 37 | var intToRoman = function(num) { 38 | 39 | var romanNumeral = [ "M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I" ]; 40 | 41 | var decimalValue = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 ]; 42 | 43 | var result = ''; 44 | 45 | for (var i = 0; i < decimalValue.length; i++) { 46 | var dValue = decimalValue[i]; 47 | if (num >= dValue) { 48 | var count = parseInt(num / dValue); 49 | num = num % dValue; 50 | 51 | for (var j = 0; j < count; j++) { 52 | result = result + romanNumeral[i]; 53 | } 54 | } 55 | } 56 | return result; 57 | 58 | } 59 | 60 | console.log(intToRoman(3549)); // Should output - MMMDXLIX 61 | 62 | console.log(intToRoman(12)); // Should output - XII 63 | 64 | /*Explanation: 65 | 66 | Step 1 67 | Initially number = 3549 68 | Since 3549 >= 1000 ; largest base value will be 1000 initially. 69 | Divide 3549/1000. Quotient = 3, Remainder =549. The corresponding symbol M will be repeated thrice. 70 | Step 2 71 | 72 | Now, number = 549 73 | 1000 > 549 >= 500 ; largest base value will be 500. 74 | Divide 549/500. Quotient = 1, Remainder =49. The corresponding symbol D will be repeated once. 75 | Step 3 76 | 77 | Now, number = 49 78 | 50 > 49 >= 40 ; largest base value is 40. 79 | Divide 49/40. Quotient = 1, Remainder = 9. The corresponding symbol XL will be repeated once. 80 | Step 4 81 | 82 | Now, number = 9 83 | 10> 9 >= 9 ; largest base value is 9. 84 | Divide 9/9. Quotient = 1, Remainder = 0. The corresponding symbol IX will be repeated once. 85 | Step 5 86 | 87 | Finally number becomes 0, algorithm stops here. 88 | Output obtained MMMDXLIX.*/ 89 | 90 | // Alternative Solution 91 | var intToRomanAlt = function(num) { 92 | 93 | // First creat 4 arrays for each of roman numberals equivalent for decimal's 1-digit, 2-digit, 3-digit, 4-digit numbers. 94 | 95 | var M = ["", "M", "MM", "MMM"]; 96 | var C = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"]; 97 | var X = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"]; 98 | var I = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; 99 | 100 | 101 | return [ 102 | M[parseInt(num / 1000)], 103 | C[parseInt((num % 1000) / 100)], 104 | X[parseInt((num % 100) / 10)], 105 | I[num % 10] 106 | ].join(''); 107 | }; 108 | 109 | // console.log(intToRomanAlt(3549)); 110 | 111 | // console.time("MySolution"); 112 | // intToRoman(3549); 113 | // console.timeEnd("MySolution"); 114 | 115 | // console.log("*******************************"); 116 | 117 | // console.time("Best-1"); 118 | // intToRomanAlt(3549); 119 | // console.timeEnd("Best-1"); -------------------------------------------------------------------------------- /isSuperUgly.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/super-ugly-number/description/ 2 | 3 | - NOTE I HAVE NOT YET DONE THIS PROBLEM 4 | 5 | Write a program to find the nth super ugly number. 6 | 7 | Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k. 8 | 9 | Example: 10 | 11 | Input: n = 12, primes = [2,7,13,19] 12 | Output: 32 13 | 14 | Explanation: [1,2,4,7,8,13,14,16,19,26,28,32] is the sequence of the first 12 super ugly numbers given primes = [2,7,13,19] of size 4. 15 | 16 | A NICE ALGO AND STEP TO SOLVE IS GIVEN IN - https://www.geeksforgeeks.org/super-ugly-number-number-whose-prime-factors-given-set/ 17 | 18 | 19 | 20 | */ 21 | 22 | isSuperUgly = (n, primes) => { 23 | 24 | for (i of primes) { 25 | while (n % i === 0) { 26 | n /= i; 27 | } 28 | } 29 | // After the while loops runs completely if the final number is 1 then its a superUgly. Else not, because if it was divided by any other number apart from the given set of primes, then the final number would be a decimal and will NOT be equal to 1 30 | return n === 1 31 | } 32 | 33 | console.log(isSuperUgly(19, [2,7,13,19])) // => true 34 | console.log(isSuperUgly(32, [2,7,13,19])) // => true 35 | 36 | /* 37 | 38 | var nthSuperUglyNumber = function (n, primes) { 39 | 40 | let counter = 0; 41 | 42 | for (let i = 0; i < 10000; i++ ) { 43 | if (isSuperUgly(i, primes)) { 44 | counter++ 45 | } 46 | if (counter === n) { 47 | return i; 48 | break; 49 | } 50 | } 51 | }; 52 | 53 | 54 | console.log(nthSuperUglyNumber(12, [2,7,13,19])) */ 55 | 56 | -------------------------------------------------------------------------------- /isUgly-Find-nth-Ugly.js: -------------------------------------------------------------------------------- 1 | isUgly = (num) => { 2 | 3 | if ( num <= 0 ) return false; 4 | 5 | let primeFactors = [2, 3, 5]; 6 | 7 | for ( var i of primeFactors ) { 8 | while ( num % i === 0 ) { 9 | num /= i; 10 | } 11 | } 12 | return num === 1; 13 | } 14 | // console.log(isUgly(9000)); // should output true 15 | 16 | 17 | // Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, … shows the first 11 ugly numbers. By convention, 1 is included. 18 | // Find n-th ugly number 19 | 20 | find_nth_Ugly = n => { 21 | let counter = 0; 22 | 23 | for (let i = 0; i < 1000; i++) { 24 | if (isUgly (i)) { 25 | counter++ 26 | } 27 | if (counter === n) { 28 | return i; 29 | break; 30 | } 31 | } 32 | } 33 | 34 | console.log(find_nth_Ugly(3)) // Should return 3 35 | 36 | // Return the series of the first n-th ugly numbers 37 | 38 | find_nth_Ugly = n => { 39 | 40 | let uglySeries = []; 41 | 42 | for (let i = 0; i <= n; i++) { 43 | if (isUgly (i)) { 44 | uglySeries.push(i) 45 | } 46 | } 47 | return uglySeries; 48 | } 49 | 50 | console.log(find_nth_Ugly(3)); // Should return [ 1, 2, 3 ] -------------------------------------------------------------------------------- /isUgly.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/ugly-number/description/ - 2 | 3 | Write a program to check whether a given number is an ugly number. 4 | 5 | Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. 6 | 7 | Example 1: 8 | 9 | Input: 6 10 | Output: true 11 | Explanation: 6 = 2 × 3 12 | Example 2: 13 | 14 | Input: 8 15 | Output: true 16 | Explanation: 8 = 2 × 2 × 2 17 | Example 3: 18 | 19 | Input: 14 20 | Output: false 21 | Explanation: 14 is not ugly since it includes another prime factor 7. 22 | 23 | https://www.geeksforgeeks.org/ugly-numbers/ 24 | 25 | Note that 1 is typically treated as an ugly number. The sequence 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, … shows the first 11 ugly numbers. By convention, 1 is considered to be ugly number. By convention, 1 is included. 26 | 27 | Solution Algo - To check if a number is ugly, divide the number by greatest divisible powers of 2, 3 and 5, if the number becomes 1 then it is an ugly number otherwise not. 28 | 29 | Let's take an example : N=9000 (We want to check this number is ugly or not) , but for that we have to check it by dividing N by the Greatest Divisible Power of prime ( 2,3 or 5) : 30 | N=9000 = 2^3 * 3^2 * 5^3 31 | So, GDP of 2 becomes - 2^3 = 8 32 | GDP of 3 becomes - 3^2 = 9 33 | GDP of 5 becomes - 5^3=125 34 | */ 35 | 36 | // my Accepted solution 37 | 38 | isUgly = (num) => { 39 | 40 | if ( num <= 0 ) return false; 41 | 42 | let primeFactors = [2, 3, 5]; 43 | 44 | for ( var i of primeFactors ) { 45 | while ( num % i === 0 ) { 46 | num /= i; 47 | } 48 | } 49 | // After the while loops runs completely if the final number is 1 then its a superUgly. Else not, because if it was divided by any other number apart from the given set of primes, then the final number would be a decimal and will NOT be equal to 1 50 | return num === 1; 51 | } 52 | console.log(isUgly(9000)); // should output true 53 | 54 | // The below solution did not pass the leetcode giving Time Limit Exceeded reason 55 | 56 | isUglyAlt = (num) => { 57 | 58 | if (num < 0) return false; 59 | if (num === 1) return true; 60 | 61 | while (num % 2 === 0 ) { num /= 2} 62 | while (num % 3 === 0 ) { num /= 3} 63 | while (num % 5 === 0 ) { num /= 5} 64 | 65 | return num === 1; 66 | } 67 | 68 | 69 | 70 | console.log(isUglyAlt(9000)); // should output true 71 | 72 | // SOLUTION-3 - Recursively 73 | isUgly_2 = (num) => { 74 | // First define the terminal cases to stop the recursion 75 | if (num <= 0) return false; 76 | if (num === 1 || num === 2 || num === 3 || num === 5) return true; 77 | if (num % 2 === 0) return isUgly_2(num / 2); 78 | if (num % 3 === 0) return isUgly_2(num / 3); 79 | if (num % 5 === 0) return isUgly_2(num / 5); 80 | else return false; 81 | } 82 | 83 | console.log(isUgly(9000)); // should output true -------------------------------------------------------------------------------- /license-Key-Formatting.js: -------------------------------------------------------------------------------- 1 | /* // https://leetcode.com/problems/license-key-formatting/description/ 2 | 3 | You are given a license key represented as a string S which consists only alphanumeric character and dashes. The string is separated into N+1 groups by N dashes. 4 | 5 | Rule - Given a number K, we would want to reformat the strings such that each group contains exactly K characters, except for the first group which could be shorter than K, but still must contain at least one character. Furthermore, there must be a dash inserted between two groups and all lowercase letters should be converted to uppercase. 6 | 7 | Given a non-empty string S and a number K, format the string according to the rules described above. 8 | 9 | Example 1: 10 | Input: S = "5F3Z-2e-9-w", K = 4 11 | 12 | Output: "5F3Z-2E9W" 13 | 14 | Explanation: The string S has been split into two parts, each part has 4 characters. 15 | Note that the two extra dashes are not needed and can be removed. 16 | Example 2: 17 | Input: S = "2-5g-3-J", K = 2 18 | 19 | Output: "2-5G-3J" 20 | 21 | Explanation: The string S has been split into three parts, each part has 2 characters except the first part as it could be shorter as mentioned above. */ 22 | 23 | /* Algo - 24 | 25 | A) Replace all the "-" from the given string with empty space, so I am left with a clean alpha-numeric string 26 | 27 | B) Looking at the above input example, Length of the first group will have K elements ONLY if len is divisible by K . 28 | 29 | C) And if len is NOT divisible then make the length of the first group to be equal to the remainder (of len / K ) - so the rest of the group can each take K letters. 30 | 31 | D) Now use substring() to form the first group - by extracting letters from 0-index upto length-of-first-group - 1. Meaning if ength-of-first-group is 4, I have to extract upto 3. And substring() by definition works like that. It does not include the indexEnd (its second argument ) 32 | 33 | str.substring(indexStart[, indexEnd]) - substring() extracts characters from indexStart up to but not including indexEnd 34 | 35 | indexStart - The index of the first character to include in the returned substring. 36 | indexEnd - Optional. The index of the first character to exclude from the returned substring. 37 | Return value - A new string containing the specified part of the given string. 38 | 39 | */ 40 | 41 | var licenseKeyFormatting = function(S, K) { 42 | 43 | let cleanStr = S.toUpperCase().replace(/-/g, ''); 44 | 45 | let len = cleanStr.length; 46 | 47 | // let s1 is the length of the first group 48 | 49 | let s1 = (( len % K ) === 0 ) ? K : (len % K); 50 | 51 | // now form the first group of the resultant string 52 | let resultStr = cleanStr.substring(0, s1); 53 | 54 | // Now that, I have the first group, the next group will be >> first-group + "-" + K elements of the string 55 | // Also as a final reconciliation after I place all the K number of elements in each group the total length should be equal to cleanStr length 56 | // i.e. s1 + K + K ... === len . Till this is not the case, I have to keep placing each K elements to each group 57 | 58 | while (len > s1 ) { 59 | resultStr += "-" + cleanStr.substring(s1, s1 + K) 60 | s1 += K 61 | } 62 | return resultStr; 63 | }; 64 | 65 | console.log(licenseKeyFormatting("5F3Z-2e-9-w", 4)) // => 5F3Z-2E9W 66 | 67 | console.log(licenseKeyFormatting("2-5g-3-J", 2)) // => "2-5G-3J" -------------------------------------------------------------------------------- /longest-Common-Prefix.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/longest-common-prefix/description/ 2 | 3 | Write a function to find the longest common prefix string amongst an array of strings. 4 | 5 | Longest common prefix for a pair of strings S1 and S2 is the longest string S which is the prefix of both S1 and S2. 6 | As an example, longest common prefix of "abcdefgh" and "abcefgh" is "abc". 7 | */ 8 | 9 | /* A> First take the first string of the given array, and split it by ''. That is each separate character. 10 | B> Then compare character by character with the corresponding character of the next string elements of the passed-in array. 11 | C> And I can bring up reduce() method to access the successive strings of the given array. 12 | */ 13 | 14 | // My solution 15 | var longestCommonPrefix = function (strs) { 16 | if (strs.length === 0) { 17 | return ''; 18 | } 19 | 20 | return strs.reduce(function (accm, next) { 21 | var tmp = accm.split(''); 22 | // This tmp variable remains constant throughout the program, which is the first string element of the array split by '' 23 | var result = ''; 24 | 25 | for (var i = 0; i < tmp.length; i++) { 26 | if (tmp[i] !== next[i]) { 27 | break; 28 | } else 29 | result += tmp[i] 30 | } 31 | return result; 32 | }); 33 | } 34 | 35 | //Alternative Solution - slightly better speed. 36 | var longestCommonPrefixAlt = function (strs) { 37 | return strs.reduce((prev, next) => { 38 | let i = 0; 39 | while (prev[i] && next[i] && prev[i] === next[i]) { 40 | i++; 41 | } 42 | return prev.slice(0, i); 43 | }) 44 | } 45 | 46 | 47 | 48 | let myStr = ["geeks", "geek", "geezer", "geeksforgeeks"]; 49 | // console.log(longestCommonPrefix(myStr)); 50 | 51 | console.time("MySolution"); 52 | longestCommonPrefix(myStr); 53 | console.timeEnd("MySolution"); 54 | 55 | console.log("*******************************"); 56 | 57 | console.time("Alternative-1"); 58 | longestCommonPrefixAlt(myStr); 59 | console.timeEnd("Alternative-1"); -------------------------------------------------------------------------------- /longest_substring_without_repeating_char.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ 2 | 3 | Given a string, find the length of the longest substring without repeating characters. 4 | 5 | Examples: 6 | 7 | Given "abcabcbb", the answer is "abc", which the length is 3. 8 | 9 | Given "bbbbb", the answer is "b", with the length of 1. 10 | 11 | Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring, "pwke" is a subsequence and not a substring. */ 12 | 13 | /* 14 | For each iteration from i = 0 to i < s.length do the follwoing steps 15 | 16 | A> From the given string keep pushing the chars to a "newSubStr", till there's no repeating char. Note that this newSubStr is the string, that we will be calculating the length for. And for each loop of i from 0 to s.length 17 | 18 | B> When a char has already occurred previously (i.e. if (index !== -1 ) is true, then first I have to reset the "newSubStr" to start taking the characters from the next index and going upto the newSubStr.length because I can-not take a substring that has a repeating character. (And note that the newSubStr has been built only upto the current index value of i) 19 | 20 | And then push this char at this index position to the resetted-newSubStr value. 21 | 22 | C> And after all the above, at each iteration of the loop, we are reassigning the maxLen to be the max of maxLen till now and subArr.length. And by the end of all the iterations I am returning the final max. 23 | */ 24 | 25 | // SOLUTION-1 26 | var lengthOfLongestSubstring = function (s) { 27 | 28 | let newSubStr = [], maxLen = 0, index; 29 | 30 | for (let i = 0; i < s.length; i++) { 31 | 32 | index = newSubStr.indexOf(s[i]); 33 | 34 | if (index !== -1) { 35 | 36 | newSubStr = newSubStr.slice(index+1); //Note, for slice() If endIndex is omitted, slice() extracts to the end of the string, when I want to extract / slice till the end of the string, I dont need to pass the second argument. 37 | } 38 | 39 | newSubStr.push(s[i]); 40 | 41 | maxLen = Math.max(maxLen, newSubStr.length); 42 | 43 | } 44 | 45 | return maxLen; 46 | } 47 | 48 | // console.log(lengthOfLongestSubstring("abcabcbb")); // => 3 49 | // console.log(lengthOfLongestSubstring("bbbbb")); // => 1 50 | // console.log(lengthOfLongestSubstring("pwwkew")); // => 3 51 | 52 | // SOLUTION-2 - The same exact logic, only difference is, I am not using a separate variable index here. In the above I am first checking if this item is duplication (if duplicate then fist slice) and only then I am pushing to the newSubStr the char. But here, I am combining both these steps in below. 53 | 54 | lengthOfLongestSubstring_2 = s => { 55 | 56 | let max = 0, newSubStr = []; 57 | 58 | for (let i = 0; i < s.length; i++) { 59 | 60 | // If 'i' is duplicated newSubStr.indexOf(i) will return the current index of that i and I will start slicing from the next position. And if its not duplicated, I will staring slicing from 0-index position and all the way upto the last char of newSubStr. 61 | 62 | newSubStr = newSubStr.slice(newSubStr.indexOf(s[i]) + 1) 63 | max = Math.max(newSubStr.push(s[i]), max); // remember the push() returns the new length of the array after pushing 64 | } 65 | return max; 66 | 67 | } 68 | 69 | 70 | console.log(lengthOfLongestSubstring_2("abcabcbb")); // => 3 71 | console.log(lengthOfLongestSubstring_2("bbbbb")); // => 1 72 | console.log(lengthOfLongestSubstring_2("pwwkew")); // => 3 -------------------------------------------------------------------------------- /majority_element.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/majority-element/description/ 2 | 3 | Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times. 4 | 5 | You may assume that the array is non-empty and the majority element always exist in the array.*/ 6 | 7 | var majorityElement = function(nums) { 8 | 9 | var len = nums.length; 10 | 11 | if (len == 1) return nums[0]; 12 | 13 | // Empty hash to hold a key-value pair. The key is the majority-element, and the value being the number of times of occurrances of the majority element 14 | var majorElement = {}; 15 | 16 | for ( var i = 0; i < len; i++) { 17 | var currentElm = nums[i]; 18 | 19 | // If the current element already exist in the hash, then increment the count of it. Also check if the count has exceeded [n/2] after incrementing then just reuturn that element, and program execution stops here. 20 | 21 | if (majorElement.hasOwnProperty(currentElm)) { 22 | majorElement[currentElm]++; 23 | if (majorElement[currentElm] > len/2) return currentElm; 24 | } else { 25 | majorElement[currentElm] = 1; // Create the current element in the hash for the first time 26 | } 27 | } 28 | return "not found"; 29 | 30 | } 31 | 32 | var num = [1,1, 1, 1, 3,4,5]; 33 | console.log(majorityElement(num)); -------------------------------------------------------------------------------- /max-contiguous-subarray-general-Solution.js: -------------------------------------------------------------------------------- 1 | /* SOLUTION-2 - General Maximum subarray problem - NOTE - This solution does not consider any condition of that the final sub-array can NOT include any negaive numbers. In othere words, the its the final contiguous can have negative numbers in it. 2 | 3 | Find the contiguous subarray within a one-dimensional array of numbers which has the largest sum. For example, for the sequence of values −2, 1, −3, 4, −1, 2, 1, −5, 4; the contiguous subarray with the largest sum is 4, −1, 2, 1, with sum 6. */ 4 | 5 | maxContiguousSubArray = arr => { 6 | let globalMax = 0, 7 | currentMax = 0; 8 | 9 | for (let i = 0; i < arr.length; i++) { 10 | currentMax = Math.max(currentMax + arr[i], arr[i]); 11 | // console.log(currentMax); // this line is only for my own debugging 12 | globalMax = Math.max(globalMax, currentMax); 13 | } 14 | return globalMax; 15 | }; 16 | 17 | let myArr = [-2, 1, -3, 4, -1, 2, 1, -5, 4]; // => 6 18 | 19 | console.log(maxContiguousSubArray(myArr)); 20 | 21 | /*Explanation 22 | A> currentMax = Math.max(currentMax+arr[i], arr[i]) => This line effectively implements the requirement that the sub-array should be contiguous. 23 | 24 | It adds the current index elements with the positive summation of previous contiguous elemtents. So, it will sometime become negative if the current index no is a large negative no. 25 | 26 | And at any index, if this current index no is so large a positive no, that arr[i] > (currentMax + arr[i]) then effective, the calculation of Sum is effectively reset from this position - which is what I want. 27 | 28 | B> So, in the above test case, when i hits 3 where the element is 4 - currentMax becomes 4, i.e. sum calculation is freshly started from here for the next set of nos. 29 | 30 | C> But, we have to make sure, that as soon as the current index no is a negative one, and so ( currentMax + arr[i] < currentMax ) - that DOES NOT mean the current run of the sub-array is done upto the previous index. BECAUSE THE NEXT POSITIVE NO MAY BE VERY LARGE 31 | 32 | D) If instead I wrote the currentMax = Math.max(currentMax+arr[i], arr[i]) as below 33 | 34 | currentMax = Math.max(currentMax, currentMax + array[i]) 35 | 36 | Then, the return value will just be the sum of all positive values in the array, not the max sum of a contiguous subarray. 37 | 38 | E> the globalMax is just a comparison variable, to keep track of the largest value of currentMax till now. 39 | 40 | 41 | 42 | */ 43 | 44 | // For returnning the sub-array instead of the sum, and accetping only non-negative elements in the final contiguous sub-array, see my solutioin below 45 | // /home/paul/codes-Lap/js/challenges/Javascript-Interview_Challenges/InterviewBit/max-contiguous-subarray.js 46 | -------------------------------------------------------------------------------- /max-sum-subarray.js: -------------------------------------------------------------------------------- 1 | /* It is an adaptation of Kadane's algorithm; 2 | It has O(n) linear complexity; 3 | Using 'temp' and 'result' objects results in high readability and more concise code. */ 4 | 5 | const maxSequence = arr => { 6 | 7 | const allPositives = arr => arr.every(n => n > 0); 8 | const allNegatives = arr => arr.every(n => n < 0); 9 | 10 | if(arr.length === 0 || allNegatives(arr)) return 0; 11 | 12 | const temp = { start: 0, sum: 0 }; 13 | let result = { start: 0, end: 0, sum: 0 }; 14 | 15 | for (let i = 0; i < arr.length; i++) { 16 | temp.sum += arr[i]; 17 | 18 | if (temp.sum > result.sum) { 19 | result = { start: temp.start, end: i, sum: temp.sum }; 20 | } 21 | 22 | if (temp.sum < 0) { 23 | temp.sum = 0; 24 | temp.start = i + 1; 25 | } 26 | } 27 | 28 | return result; 29 | }; 30 | 31 | console.log(maxSequence([-2, -1, -3, -4, -1, -2, -1, -5, -4])); // 0 32 | console.log(maxSequence([])); // 0 33 | console.log(maxSequence([2, 1, 3, 4, 1, 2, 1, 5, 4])); // { start: 0, end: 8, sum: 23 } 34 | -------------------------------------------------------------------------------- /merge-sorted-array.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/merge-sorted-array/description/ 2 | 3 | Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. 4 | 5 | Note: 6 | You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m and n respectively.*/ 7 | 8 | // My solution 9 | 10 | var merge = function (nums1, m, nums2, n) { 11 | // Start the merging process from the end (last index) of the final merged array i.e. index no ( m + n - 1) 12 | while ( m > 0 && n > 0) { 13 | if (nums1[m - 1] > nums2[n - 1]) { 14 | nums1[ m + n - 1] = nums1[m - 1]; 15 | m--; 16 | } else { 17 | nums1[m + n - 1] = nums2[n - 1]; 18 | n--; 19 | } 20 | } 21 | 22 | // After the previous while loop ends completely, i.e. if there are more elements left in nums2 23 | while (n > 0) { 24 | nums1[m + n - 1] = nums2[n - 1]; 25 | n--; 26 | } 27 | return nums1.sort(); 28 | } 29 | 30 | /* A) Note, the original question specifically asked for not returning the final array, but just modifying the array in place. So, the line < return nums1; > was not there in my solution to Leetcode 31 | 32 | B) Explanation on why I am not running a separate while loop for m ( like for n) - Because, I merging nums2 to nums1 and finally returning nums1. So, for the case when m is larger than n, all the leftover elements are already there in the nums1. I dont need to take care of them separately. 33 | 34 | */ 35 | 36 | // console.log(merge([1,5,6], 3, [0,1,8,9], 4)); 37 | // console.log(merge([1,5,6, 4], 4, [0,1,8,], 3)); 38 | 39 | //*********************************************** 40 | //Alternative Solution-1 - Almost similar to the above, slightly shorter. 41 | merge1 = (nums1, m, nums2, n) => { 42 | while (m > 0 || n > 0) { 43 | if ( m > 0 && n > 0) { 44 | if (nums1[m - 1] > nums2[n - 1]) { 45 | nums1[ m + n - 1] = nums1[--m]; 46 | } else { 47 | nums1[ m + n - 1] = nums2[--n]; 48 | } 49 | } 50 | else if ( n > 0) { 51 | nums1[m + n - 1] = nums2[--n] 52 | } 53 | } 54 | return nums1.sort(); 55 | } 56 | console.log(merge1([1,5,6], 3, [0,1,8,9], 4)); 57 | // console.log(merge1([1,5,6, 4], 4, [0,1,8,], 3)); 58 | 59 | // Alternative-3 - Evern shorter 60 | 61 | merge2 = (nums1, m, nums2, n) => { 62 | 63 | let finalLen = m + n; 64 | m--; 65 | n--; 66 | 67 | /* From the above 2 solutions I can see there are 2 conditions when I will be adding nums1[m] elements to the final merged array. They are A) when nums1[m] > nums2[m] and B) n < 0. But in the above, I implement these 2 conditions in separately. Now, lets implement them together. */ 68 | 69 | while ( finalLen--) { 70 | if (n < 0 || nums1[m] > nums2[n]) { 71 | nums1[finalLen] = nums1[m--] 72 | // In above note, that because, I have already decremented m and n before the while loop, so, here inside the while loop, I am just doing a regular post-decrement (unlike the previous alternative sol). 73 | } else { 74 | nums1[finalLen] = nums2[n--] 75 | } 76 | } 77 | return nums1; 78 | } 79 | 80 | console.log(merge2([1,5,6], 3, [0,1,8,9], 4)); 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /merge-two-sorted-linked-lists.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/merge-two-sorted-lists/description/ 2 | 3 | Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. 4 | 5 | Example: 6 | 7 | Input: 1->2->4, 1->3->4 8 | Output: 1->1->2->3->4->4 9 | */ 10 | 11 | // Definition for singly-linked list. 12 | function ListNode(val) { 13 | this.val = val; 14 | this.next = null; 15 | } 16 | 17 | 18 | 19 | 20 | /*Break the list into 2 nodes of the ListNode class. Then execute the sort function on the values of the list elements, and make a new list. Return the head of the new list */ 21 | 22 | // My Solution 23 | var mergeTwoLists = function(l1, l2) { 24 | // Make a new list, being an empty array 25 | var result = []; 26 | 27 | while (l1) { 28 | result.push(new ListNode(l1.val)); 29 | l1 = l1.next; 30 | } 31 | 32 | while (l2) { 33 | result.push(new ListNode(l2.val)); 34 | l2 = l2.next; 35 | } 36 | 37 | result.sort(function(a, b) { 38 | return a.val - b.val; 39 | }); 40 | 41 | if(!result.length) return null; 42 | for(var i = 0; i < result.length -1; i++) 43 | result[i].next = result[i+1]; 44 | 45 | return result[0]; 46 | } 47 | 48 | 49 | // Alternative Solution - Here also I break the list into 2 nodes and then create a new a new list. 50 | var mergeTwoLists = function(l1, l2) { 51 | if(!l1) return l2; 52 | if(!l2) return l1; 53 | 54 | var head = null; 55 | 56 | if(l1.val < l2.val) { 57 | head = l1; 58 | l1 = l1.next; 59 | } else { 60 | head = l2; 61 | l2 = l2.next; 62 | } 63 | 64 | var newList = head; 65 | 66 | while(l1 && l2) { 67 | if(l1.val < l2.val) { 68 | newList.next = l1; 69 | l1 = l1.next; 70 | } else { 71 | newList.next = l2; 72 | l2 = l2.next; 73 | } 74 | newList = newList.next; 75 | } 76 | if(!l1) { 77 | newList.next = l2; 78 | } else { 79 | newList.next = l1; 80 | } 81 | return head; 82 | } -------------------------------------------------------------------------------- /palindrome-number.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/palindrome-number/description/ 2 | 3 | Determine whether an integer is a palindrome. Do this without extra space.*/ 4 | 5 | // SOLUTION - 1 // The logic is same as reverse_integer.js 6 | 7 | var isPalindrome = function (x) { 8 | // First reverse the string without using any sting method. 9 | var y = Math.abs(x); 10 | var result = 0; 11 | 12 | while (y > 0) { 13 | result = result * 10 + (y % 10); 14 | y = parseInt(y / 10); 15 | } 16 | return result === x; 17 | } 18 | 19 | console.log(isPalindrome(323)); 20 | 21 | // Alternative by reversing string. But this would require extra non-constant space for creating the string 22 | var isPalindrome1 = function(x) { 23 | return x.toString().split('').reverse().join('') === x.toString(); 24 | } 25 | 26 | console.log(isPalindrome1(323)); 27 | 28 | /* 29 | FIRST - I have to pick up the last digit and bring it forward 30 | 31 | So, I use modulo operator to hook to the last digit. The mod will return the remainder, i.e. the last digit for each iteration, starting with the last digit then the last to last and so on. 32 | 33 | So, in case of x = 123, after first iteration y % 10 will return 3, then 2, then 1 34 | 35 | SECOND - And then, I need to extract the rest of the digits. 36 | 37 | So I do, parseInt(y/10), which will always return an integer leaving out the last decimal positions. So for for my case of 123 ( parseInt(123/10) and then parseInt(12/10) and then parseInt(1/10)) will consecutively return 12, 1 and then 0 38 | 39 | So, for initial number 123, after the first execution of the iteration, the value of result will be like below 40 | 41 | 0 + 3 42 | (3 * 10) + 2 43 | (32 * 10 ) + 1 44 | 45 | 46 | **************************************** 47 | 1> The parseInt() function parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems). 48 | 49 | parseInt(string, radix); 50 | 51 | string - The value to parse. If the string argument is not a string, then it is converted to a string (using the ToString abstract operation). Leading whitespace in the string argument is ignored. 52 | 53 | radix An integer between 2 and 36 that represents the radix (the base in mathematical numeral systems) of the above mentioned string. 54 | 55 | Return value - An integer number parsed from the given string. If the first character cannot be converted to a number, NaN is returned. 56 | 57 | parseInt(15.99, 10); // => 15 58 | 59 | parseInt('15,123', 10); // => 15 60 | 61 | *********SO BASICALLY WHEN THE AGRUMENT IS A NUMBER parseInt() is equivalent to Math.floor()********* 62 | 63 | 2> parseInt() vs Math.round() 64 | https://stackoverflow.com/questions/8170865/math-round-vs-parseint 65 | 66 | A> parseInt() extracts a number from a string, e.g. 67 | 68 | parseInt('1.5') // => 1 69 | 70 | Math.round() rounds the number to the nearest whole number: 71 | 72 | Math.round('1.5') // => 2 73 | 74 | Math.round('1.4') // => 1 75 | 76 | 77 | 78 | B> parseInt() can get its number by removing extra text, e.g.: 79 | 80 | parseInt('12foo') // => 12 81 | 82 | However, Math.round will not: 83 | 84 | Math.round('12foo') // => NaN 85 | 86 | */ -------------------------------------------------------------------------------- /product-of-Array-Except-Self-GOOD-LONG-EXPLANATION.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/product-of-array-except-self/description/#_=_ 2 | 3 | This question came in a Google Interview - Senior Software Engineer Interview Mountain View-CA https://www.glassdoor.com/Interview/Given-an-array-of-numbers-replace-each-number-with-the-product-of-all-the-numbers-in-the-array-except-the-number-itself-w-QTN_9132.htm 4 | 5 | Given an array nums of n integers where n > 1, return an array output such that output[i] is equal to the product of all the elements of nums except nums[i]. 6 | 7 | Example: 8 | 9 | Input: [1,2,3,4] 10 | Output: [24,12,8,6] 11 | Note: Please solve it without division and in O(n). 12 | 13 | Follow up: 14 | Could you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.) 15 | 16 | */ 17 | 18 | productExceptSelf = arr => { 19 | 20 | if (arr.length === 0) return; 21 | 22 | let result = [] 23 | 24 | let left = 1 25 | 26 | /* calculate the forward array starting from 0-th index till end of the array. This will build the multiplication result for the left positions for each element of the final result array. 27 | 28 | After this for loop the result array will be [ 1, (1*1), (1*2), (2*3) ] - So this array's each element represent the all the left element's multiplication for each position of the final result array[]. 29 | 30 | So, given my original array [ 1, 2, 3, 4 ] 31 | for index-0 all left element's multiplication is 1 ( which is the intialization value of left) 32 | For index-1 all left element's multiplication is 1 33 | For index-2 all left element's multiplication is 2 * 1 = 2 34 | So, for index-0 all left element's multiplication is 2 * 3 = 6 35 | 36 | So for the forward traversal, I am never reaching the right-most element which is arr[3] - CONCEPTUALLY that makes sense, as for the final multiplication result for this position in result[] array, I have exclude this arr[3] element. MEANING FOR arr[3] POSITION, I WILL CONSIDER ALL THE MULTIPLICATION RESULT FROM THE LEFT POSITIONS BUT NO MULTIPLICATION POSITIONS FROM RIGHT. And because under this first for loop for forward array multiplication, I am actually building the left multiplication result. 37 | 38 | Means for the final result[] array, for this index position [3] I will be multiplying all the left element's cumulative multiplication results which is 6 with the initialization value of 'right' 39 | 40 | So, only in this way, I ensure, that this forward array-multiplications ONLY REPRESENTS THE MULTIPLICATION OF ALL THE LEFT ELEMENTS, BUT NOT THE CURRENT POSITION ELEMENT. The equation - finalResultArrEleme = All-left-Multiplication * All-right-multiplication 41 | 42 | */ 43 | for (let i = 0; i < arr.length; i++) { 44 | result[i] = left; 45 | left *= arr[i] 46 | } 47 | 48 | /* Now build the backward array-multiplication*/ 49 | 50 | let right = 1; 51 | 52 | for (let i = arr.length - 1; i >=0; i--) { 53 | // Unlike the previous for loop, here I have to multiply with the previous forward array elements. As that array's corresponding element will give me the multiplication result of the left elements for this position. 54 | result[i] = result[i] * right; 55 | right *= arr[i] 56 | } 57 | return result; 58 | } 59 | 60 | let input = [1,2,3,4] // => The Output should be [24,12,8,6] 61 | 62 | console.log(productExceptSelf(input)) 63 | 64 | /* GOOD EXPLANATION - 1 - https://yucoding.blogspot.com/2016/04/leetcode-question-product-of-array.html?showComment=1533484700200#c5983446391438689683 65 | 66 | This question has three requirements: 67 | 68 | no division 69 | O(n) time complexity 70 | O(1) space complexity 71 | 72 | What can be done within O(n) time? - Scan the whole array once (often from the start to the end). 73 | 74 | What about scan the array again? 75 | 76 | Yes. It is still O(n) time ( O(2n)=O(n) ). 77 | 78 | What about scan n times? 79 | 80 | No. It is O(n∗n)=O(n^2) 81 | 82 | From the question above, we know that, at least we could scan the array twice (or other countable number if needed.). 83 | 84 | OK, let's scan the array from start to end, e.g., [1,2,3,4] 85 | 86 | The accumulated products can then be saved: 87 | 88 | P_forward = [1, 1*2, 1*2*3, 1*2*3*4] = [1, 2, 6, 24] 89 | 90 | 91 | Let's get back to the problem, we need to get the product of all nums without current position, intuitively: 92 | nums = [1, 2, 3, 4], for position 2 where nums[2] = 3, the product we want to have can be viewed: 93 | 94 | left = 1*2 95 | right = 4 96 | 97 | p = left * right 98 | 99 | We already have the accumulated product from our first scanning, P_forward = [1, 2, 6, 24], which means, P_forward[i] = product from 0 to i. What about the product from i+1 to end? 100 | 101 | The backward product is computed by scanning the array backward: 102 | P_backward = [4, 4*3, 4*3*2, 4*3*2*1 ] 103 | P_backward = [4, 12, 24, 24] 104 | 105 | SO THE KEY POINT - PAUL - The significance of the P_forward is its taking care of the left side multiplication and P_backwards is taking care of the right side multiplication. And at each index position of the final result array, I have to multiply all the element of the left and all the elements on the right. Thats why I am building 2 arrays and multiplying them to get the final array. 106 | 107 | *** Note that, these products include the current element, so by adding a "1" in front of the product arrays will do fine: *** 108 | 109 | P_forward = [1, 1, 2, 6, 24] 110 | P_backward = [1, 4, 12, 24, 24] 111 | 112 | then, the final results can be easily computed: 113 | 114 | res[0] = P_forward[0] * P_backward[3] = 24 means (In original array -> product before [0] * product from last to [1]) i.e. ( 1 * 24) 115 | 116 | res[1] = P_forward[1] * P_backward[2] = 12 means (In original array -> product before [1] * product from last to [2]) i.e. ( 1 * 12 ) 117 | 118 | res[2] = P_forward[2] * P_backward[1] = 8 means (In original array -> produce before [2] * [ product from last to [3] means [3] itself ) i.e. ( 2 * 4 ) 119 | 120 | res[3] = P_forward[3] * P_backward[0] = 6 means ( In original array -> product before [3] * product after [3]) i.e. ( ) 121 | 122 | 123 | Few points in the above equation 124 | 125 | A) product before [0] >> there is nothing before [0] so, we have added just a dummy element which is 1. So product before [0] is 1 126 | 127 | B) product before [1] >> Means the first element of the original array ie. [0] 128 | 129 | res = [24, 12, 8, 6] 130 | 131 | 132 | Now the problem is solved but: Lets check whether I meet the O(1) space complexity condition - 133 | 134 | P_forward can be stored in the output array 135 | P_backward is actually not necessary, each time we compute one value, multiply it to correct P_forward, then the P_backward value can be overwritten for the next computation. 136 | Therefore, we have one output array of length n (which is not count as extra space as in the question description), one int for P_backward, one int for loop. It is O(1)! 137 | 138 | 139 | GOOD EXPLANATION - https://www.youtube.com/watch?v=vB-81TB6GUc 140 | */ -------------------------------------------------------------------------------- /product-of-Array-Except-Self-without-constraint.JS: -------------------------------------------------------------------------------- 1 | /* Same problem of Finding Product of Array Except Self Javascript - But without Space and Time complexity */ 2 | 3 | productOfArrElementsExceptSelf = arr => { 4 | 5 | let result = [], product; 6 | 7 | for (let i = 0; i < arr.length; i++) { 8 | // Super important step, I have to reset the product before the next i value is run 9 | // Else I will get a result of [ 24, 288, 2304, 13824 ], as it will take the previous multiplication value of product 10 | // And also conceptually, when I am keeping one element fixed and calculating the produce ot the other elements - that means 11 | // Before starting the next product calculation, I am assuming the initial product value is 1 12 | product = 1; 13 | for (let j = 0; j < arr.length; j++) { 14 | if (i !== j ) product *= arr[j] 15 | } 16 | result.push(product); 17 | } 18 | return result; 19 | } 20 | 21 | // console.log(productOfArrElementsExceptSelf([1, 2, 3, 4])) 22 | 23 | // More compact 24 | 25 | productOfArrElementsExceptSelf_1 = arr => { 26 | return arr.map((thisItem, index) => { 27 | return arr.reduce((product, value, j) => { 28 | return product * ( index === j ? 1 : value ) 29 | }, 1) // Note I am resetting the accumulator(i.e. the product) to 1, for each new element of the map() function 30 | }) 31 | } 32 | 33 | console.log(productOfArrElementsExceptSelf_1([1, 2, 3, 4])) 34 | 35 | /* Syntax of map function 36 | 37 | var new_array = arr.map(function callback(currentValue[, index[, array]]) { 38 | // Return element for new_array 39 | }[, thisArg]) 40 | 41 | 42 | callback - Function that produces an element of the new Array, taking three arguments: 43 | 44 | currentValue - The current element being processed in the array. 45 | 46 | indexOptional - The index of the current element being processed in the array. 47 | 48 | arrayOptional - The array map was called upon. 49 | 50 | thisArgOptional - Value to use as this when executing callback. 51 | */ -------------------------------------------------------------------------------- /remove-duplicates-from-sorted-array.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/ 2 | 3 | Given a sorted array, remove the duplicates in-place such that each element appear only once and return the new length. 4 | 5 | Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. 6 | 7 | Example: 8 | 9 | Given nums = [1,1,2], 10 | 11 | Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. 12 | It doesn't matter what you leave beyond the new length. 13 | */ 14 | 15 | /* My solution steps - 16 | A>> Because the array is sorted, duplicate elements will be side-by-side. 17 | B>> So, I will start from the last element of the array ( i = nums.length), moving left, by decrementing i. And with each non-duplicate element found, I will increment the "resultLength" variable by 1 18 | C>> For first iteration, i.e. the last element of the array I have to increment the resultLength anyway. Hence, the condition < if ( i === nums.length - 1) > Only for the first iteration of the for loop this will be satisfied and so resultLength will be incremented by 1 19 | */ 20 | var removeDuplicates = function(nums) { 21 | 22 | var resultLength = 0; 23 | 24 | for ( var i = nums.length; i--; ) { 25 | if ( i === nums.length - 1) { 26 | resultLength++; 27 | } 28 | else if ( nums[i] === nums[i + 1]) { 29 | nums.splice(i, 1); // This will remove 1 element from the position nums[i] 30 | } else { 31 | resultLength++ 32 | } 33 | } 34 | return resultLength; 35 | } 36 | 37 | 38 | console.log(removeDuplicates([1,1,2])); -------------------------------------------------------------------------------- /reverse_integer.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/reverse-integer/description/ 2 | 3 | Given a 32-bit signed integer, reverse digits of an integer. 4 | 5 | Input: 123 6 | Output: 321 7 | Example 2: 8 | 9 | Input: -123 10 | Output: -321 11 | Example 3: 12 | 13 | Input: 120 14 | Output: 21 15 | Note: 16 | Assume we are dealing with an environment which could only hold integers within the 32-bit signed integer range. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows. 17 | 18 | 'Overflows' here means the resultant number is more than the greatest number that can be handled in JS or less than the min number that can be handled in js 19 | 20 | The upper bound of a signed integer is not 2^32 - 1, but 2^31 - 1, since the first bit is the sign bit. 21 | And lower bound is -(2^31 - 1) 22 | */ 23 | 24 | // SOLUTION-1 My solution 25 | var reverse = function(x) { 26 | var reversedX = +Math.abs(x).toString().split('').reverse().join(''); 27 | return reversedX > 2147483647 ? 0 : x < 0 ? -reversedX : reversedX; 28 | } 29 | 30 | // console.log(reverse(123)); // => 321 31 | 32 | // console.log(reverse(-123)); // => -321 33 | 34 | // // SOLUTION-2 - Best Performing solution. And also if the Problems asks for not to use any string related methods. 35 | var reverseBest = function(x) { 36 | 37 | var y = Math.abs(x); 38 | var result = 0; 39 | 40 | while (y) { 41 | var result = (result * 10) + y % 10; 42 | y = parseInt(y / 10); 43 | // console.log(y); 44 | } 45 | 46 | 47 | x > 0 ? result = result : result = -result; 48 | if (result > 2147483648 || result < -2147483648) return 0; 49 | return result; 50 | } 51 | 52 | // console.log(reverseBest(123)); // => 321 53 | // console.log(reverseBest(-123)); // => -321 54 | // console.log(reverseBest( 1534236469 )) // => 0 55 | 56 | /*My note on the above best solution - 57 | 58 | FIRST - I have to pick up the last digit and bring it forward 59 | 60 | So, I use modulo operator to hook to the last digit. The mod will return the remainder, i.e. the last digit for each iteration, starting with the last digit then the last to last and so on. 61 | 62 | So, in case of x = 123, after first iteration y % 10 will return 3, then 2, then 1 63 | 64 | SECOND - And then, I need to extract the rest of the digits. 65 | 66 | So I do, parseInt(y/10), which will always return an integer leaving out the last decimal positions. So for for my case of 123 ( parseInt(123/10) and then parseInt(12/10) and then parseInt(1/10)) will consecutively return 12, 1 and then 0 67 | 68 | So, after the first execution of the iteration, the value of result will be like below 69 | 70 | 0 + 3 71 | (3 * 10) + 2 72 | (32 * 10 ) + 1 73 | 74 | 75 | **************************************** 76 | 1> The parseInt() function parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems). 77 | 78 | parseInt(string, radix); 79 | 80 | string - The value to parse. If the string argument is not a string, then it is converted to a string (using the ToString abstract operation). Leading whitespace in the string argument is ignored. 81 | 82 | radix An integer between 2 and 36 that represents the radix (the base in mathematical numeral systems) of the above mentioned string. 83 | 84 | Return value - An integer number parsed from the given string. If the first character cannot be converted to a number, NaN is returned. 85 | 86 | parseInt(15.99, 10); // => 15 87 | 88 | parseInt('15,123', 10); // => 15 89 | 90 | *********SO BASICALLY WHEN THE AGRUMENT IS A NUMBER parseInt() is equivalent to Math.floor()********* 91 | 92 | 2> parseInt() vs Math.round() 93 | https://stackoverflow.com/questions/8170865/math-round-vs-parseint 94 | 95 | A> parseInt() extracts a number from a string, e.g. 96 | 97 | parseInt('1.5') // => 1 98 | 99 | Math.round() rounds the number to the nearest whole number: 100 | 101 | Math.round('1.5') // => 2 102 | 103 | Math.round('1.4') // => 1 104 | 105 | 106 | 107 | B> parseInt() can get its number by removing extra text, e.g.: 108 | 109 | parseInt('12foo') // => 12 110 | 111 | However, Math.round will not: 112 | 113 | Math.round('12foo') // => NaN 114 | 115 | */ 116 | 117 | // SOLUTION-3 - Almost similar to SOL-1 except using toString() but anyway converting to string with ' 118 | 119 | const reverseNum = x => { 120 | 121 | let result = 0; 122 | 123 | if (x < 0) { 124 | // For this case, slice the string after the first "-" sign. Else I will get a NaN 125 | result = -(('' + x).slice(1).split('').reverse().join('')); 126 | } else { 127 | result = +(('' + x).split('').reverse().join('')); 128 | } 129 | 130 | // In split() and join() I have to pass the delimiter of an empty string as '' - Else tit will be an error. 131 | 132 | return (result < (-Math.pow(2,31)) || result > (Math.pow(2,31) -1) ) ? 0 : result 133 | // Note the syntax above for the ternary operator above as compared to the SOL-1 and 2. Here, I am using just a single return statement. And 134 | } 135 | 136 | console.log(reverseNum(123)); // => 321 137 | console.log(reverseNum(-123)); // => -321 138 | console.log(reverseNum( 1534236469 )) // => 0 139 | 140 | /* split() is a string’s prototype method that converts a string to an array. Providing an empty string as an argument means split by each character. So the resulting array would have each character as an element of the array. */ -------------------------------------------------------------------------------- /roman_to_integer.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/roman-to-integer/description/ 2 | 3 | Given a roman numeral, convert it to an integer. 4 | 5 | Input is guaranteed to be within the range from 1 to 3999.*/ 6 | 7 | /* The Algorithm - 8 | https://www.geeksforgeeks.org/converting-roman-numerals-decimal-lying-1-3999/ 9 | 10 | A number in Roman Numerals is a string of these symbols written in descending order(e.g. M’s first, followed by D’s, etc.). However, in a few specific cases, to avoid four characters being repeated in succession (such as IIII or XXXX), subtractive notation is often used as follows: 11 | 12 | I placed before V or X indicates one less, so four is IV (one less than 5) and 9 is IX (one less than 10). 13 | X placed before L or C indicates ten less, so forty is XL (10 less than 50) and 90 is XC (ten less than a hundred). 14 | C placed before D or M indicates a hundred less, so four hundred is CD (a hundred less than five hundred) and nine hundred is CM (a hundred less than a thousand). 15 | 16 | So we don't require mappings for numbers 4,9,40 etc because the Roman number theory tells us if the roman numeral is IV = 5-1 = 4, hence when the prefix is smaller than the succeeding number in that case you have to subtract the former number from the succeeding number to get the actual value 17 | 18 | 19 | Algorithm to convert Roman Numerals to Integer Number : 20 | 21 | A) Split the Roman Numeral string into Roman Symbols (character). 22 | 23 | B) Convert each symbol of Roman Numerals into the numerical value it represents. 24 | 25 | C) Take symbol one by one from starting from index 0: 26 | 27 | D) If the next-Item is bigger than then current-Item >> subtract this current-item by adding the value of next-Item to the running total. And increment i (the counting index) 28 | 29 | E) If current-Item of symbol is greater than or equal to the value of next symbol, then just add this value to the running total. 30 | 31 | F) In my below solution, in the second iteration ( i = 1 ), when I am comparing between C and M, after the condition nextItem > currentItme is satisfied, the i gets incremented inside this loop only. So the next iteraton starts ast i = 3 (NOT i = 2). 32 | That, is the next comparison will be between i = 3 and i = 4 i.e. between "I" and "V" ( and NOT between "M" and "I") 33 | 34 | */ 35 | 36 | var romanToInt = function(s) { 37 | 38 | var hashTable = { 39 | 40 | "I" : 1, 41 | "X" : 10, 42 | "C" : 100, 43 | "M" : 1000, 44 | "V" : 5, 45 | "L" : 50, 46 | "D" : 500 47 | 48 | }; 49 | 50 | var resultSum = 0; 51 | 52 | for (var i = 0; i < s.length; i++ ) { 53 | // console.log(i); 54 | 55 | var currentItem = hashTable[s[i]]; 56 | 57 | var nextItem = i + 1 === s.length ? 0 : hashTable[s[i + 1]]; 58 | 59 | if ( nextItem > currentItem ) { 60 | resultSum += nextItem - currentItem ; 61 | i++; 62 | } else { 63 | resultSum += currentItem; 64 | } 65 | } 66 | 67 | return resultSum; 68 | 69 | }; 70 | 71 | console.log(romanToInt("MCMIV")); // should return 1904 -------------------------------------------------------------------------------- /self-dividing-number.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/articles/self-dividing-numbers/ 2 | 3 | A self-dividing number is a number that is divisible by every digit it contains. 4 | 5 | For example, 128 is a self-dividing number because 128 % 1 == 0, 128 % 2 == 0, and 128 % 8 == 0. 6 | 7 | Also, a self-dividing number is not allowed to contain the digit zero. 8 | 9 | Given a lower and upper number bound, output a list of every possible self dividing number, including the bounds if possible. 10 | 11 | Example 1: 12 | Input: 13 | left = 1, right = 22 14 | Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22] 15 | Note: 16 | 17 | The boundaries of each input argument are 1 <= left <= right <= 10000.*/ 18 | 19 | function findAllSelfDividingNum(left, right) { 20 | 21 | let allSelfDiving = []; 22 | 23 | for (left ; left <= right; left++) { 24 | for (i = 0; i < left.toString().length; i++) { 25 | if ((left % left.toString().charAt(i) === 0) && (left.toString().charAt(i) !== 0)) { 26 | result = true; 27 | } else { 28 | result = false; 29 | break; // I am breaking it here, as there's no need to go on dividing more digits once I find one non-dividing digit. 30 | } 31 | } 32 | if (result) { 33 | allSelfDiving.push(left); 34 | } 35 | } 36 | return allSelfDiving; 37 | } 38 | 39 | // console.log(findAllSelfDividingNum(1, 10000)); 40 | 41 | /*Alternative solution 42 | A> Because t 43 | */ 44 | function findAllSelfDividingNum_Alt(left, right) { 45 | let result = []; 46 | for (var i = 0; i <= right; i++) { 47 | if(isSelfDivisingNum(i)) { 48 | result.push(i); 49 | } 50 | } 51 | return result; 52 | } 53 | /*A> Continually divide the number by 10 and peek at the last digit. Because the original given number can NOT have 0. 54 | B> If the number is divisible by 10 > then return false (i.e. NOT truthy i.e NOT !1) 55 | C> In the next iteraion divide the number by 10 and check for remainder again.*/ 56 | function isSelfDivisingNum(num) { 57 | let temp = num; 58 | 59 | if (!temp) return false; // If the number is 0 itself 60 | 61 | while (temp) { 62 | let remainder = temp % 10; 63 | temp = Math.floor(temp / 10); // For each iteration to reduce the original given number by dividing it by 10. 64 | 65 | if (!remainder) return false; // If its divisible by 10 return false 66 | /*Now check if the original given number is completely divisible by the right-most digit of the continously reduced number 67 | A> So if I take 216 > after first iteration, I will get ( 218 / 8) which will leave me a positive remainder. 68 | B> Meaning, if (num % remainder) will be true and so I will return false from my program. Means this number is NOT self-divising. */ 69 | if (num % remainder) return false; 70 | } 71 | return true; // If all the above false conditionals withing the while loop are not satisfied, then return true 72 | } 73 | 74 | console.log(findAllSelfDividingNum_Alt(1, 22)); -------------------------------------------------------------------------------- /shortest-distance-to-a-character.js: -------------------------------------------------------------------------------- 1 | /* https://leetcode.com/problems/shortest-distance-to-a-character/description/ 2 | Given a string S and a character C, return an array of integers representing the shortest distance from the character C in the string. 3 | 4 | Input: S = "loveleetcode", C = 'e' 5 | Output: [3, 2, 1, 0, 1, 0, 0, 1, 2, 2, 1, 0] 6 | 7 | So, You need to find shortest distance for EACH Character in the String 'S' to Character 'C'. And distance means the numerical distance of the index-number of the character C from the index-number of EACH of character in the string. 8 | 9 | S string length is in [1, 10000]. 10 | C is a single character, and guaranteed to be in string S. 11 | All letters in S and C are lowercase. 12 | */ 13 | 14 | var shortestToChar = function (S, C) { 15 | // first get the index-position of the character C 16 | let c_position = S.indexOf(C); 17 | 18 | // Create an empty array of length S.length > fill the array with the initial positional distance value from C (c_position - i) as the elements-value of this array. So, this becomes the initial-distance of each character of the array-element from the first occurrence of C. We need to update this initial-distance as I find more occurrence of C 19 | 20 | let resultElementDistance = Array(S.length).fill(null).map((u, i) => Math.abs(c_position - i)); 21 | 22 | 23 | // Run while loop updating c_position with the next occurrence of C 24 | while (c_position !== -1) { 25 | 26 | // Now note, the character C will occur multiple times in the given array. So the distance will need to be recalculated, and only after all the calculations are done, the minimum one should be returned 27 | // So, I start the search for C from c_position + 1. Given, I already know that c_position was already occupied by C (i.e. C's first occurrence). 28 | 29 | let next_c_position = S.indexOf(C, c_position + 1); 30 | 31 | /* A> Now given next_c_position is the second occurrence of C, I dont need to re-calculate the distance of all the characters to the left of c_position as that has already been calculated and remain constant. 32 | B> So, run a for loop to re-calculate the distance from each character to the right of next_c_position and if the new distance is smaller than earlier one, update resultElementDistance[i] with the new distance. 33 | */ 34 | 35 | for (var i = c_position + 1; i < S.length; i++) { 36 | let newDistance = Math.abs(next_c_position - i); 37 | if (resultElementDistance[i] > newDistance) { 38 | resultElementDistance[i] = newDistance; 39 | } 40 | } 41 | c_position = next_c_position; 42 | } 43 | return resultElementDistance; 44 | } 45 | 46 | // console.log(shortestToChar("loveleetcode", 'e')); 47 | 48 | /* Alternative solution 49 | A> Build an array 'allCIndexPositions' with only the index position value of C 50 | 51 | B> Lets say, 'allCIndexPositions' becomes [ 3, 5, 6, 11 ] 52 | 53 | C> Now I only have to find the minimum numerical difference of all other element's positional index value from each of these values i.e. 3, 5, 6 , 11 54 | 55 | */ 56 | var shortestToChar = function(S, C) { 57 | let all_CIndexPositions = S.split('').reduce((accumulator, element, index) => { 58 | if (element === C) { 59 | accumulator.push(index); 60 | } 61 | return accumulator; 62 | }, []); 63 | // console.log(all_CIndexPositions); 64 | let resultElementDistance = S.split('').reduce((accumulator, element, index) => { 65 | let thisElemIndex = index; 66 | 67 | let minThisElemDist = Math.min.apply(null, all_CIndexPositions.map((elementCIndex, index) => { 68 | return Math.abs(thisElemIndex - elementCIndex); 69 | })); 70 | accumulator.push(minThisElemDist); 71 | return accumulator; 72 | }, []); 73 | return resultElementDistance; 74 | } 75 | 76 | console.log(shortestToChar("loveleetcode", 'e')); -------------------------------------------------------------------------------- /string-to-integer-atoi-1.js: -------------------------------------------------------------------------------- 1 | /*Implement atoi to convert a string to an integer. 2 | 3 | Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases. 4 | 5 | Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front. 6 | 7 | Update (2015-02-10): 8 | The signature of the C++ function had been updated. If you still see your function signature accepts a const char * argument, please click the reload button to reset your code definition. 9 | */ 10 | 11 | /*// Solution-1 - Regexp match >> 12 | [+-]? -- Using the square bracket [], called character set - matches any one of the characters in the bracket. So in this case, it matches the plus or the minus. 13 | 14 | When ? immediately follows any of the other quantifiers (*, +, ?, {n}, {n,}, {n,m}), the matching pattern is non-greedy. That is it matches 0 or 1 time 15 | 16 | \d* - matches zero or more digits. 17 | 18 | The exec() method executes a search for a match in a specified string. Returns a result array, or null. 19 | 20 | So, the below regexp, will search for a match any digits starting with a single "+" or a "-" and return a result array of all the matches. In this case, I will only need the 0 index element of that array. 21 | */ 22 | var myAtoi = function (str) { 23 | 24 | var integer = /([+-]?\d*)/.exec(str.trim())[0]; 25 | 26 | // A nice use-case of chaining ternary operator 27 | return isNaN(+integer) ? 0 : +integer > 2147483647 ? 2147483647 : +integer < -2147483648 ? -2147483648 : +integer; 28 | 29 | } 30 | 31 | console.log(myAtoi("-2147483649")); 32 | 33 | // The "+" operator before a variable will returns the numeric representation of the object. It converts the variable to a number. 34 | 35 | // Solution-2 , and faster - Crude / dirty version of atoi 36 | 37 | var myAtoi1 = function(str) { 38 | return Math.max((Math.min((parseInt(str) || 0), 2147483647)), -2147483648); 39 | } 40 | 41 | console.log(myAtoi1("-2147483649")); 42 | 43 | /*In the above, (parseInt(str) || 0) - this line will return 0 incase str is a NaN . And then Math.min( 0, 2147483647 ) will return 0 again. 44 | 45 | And otherwise (when parseInt(str) is a number ) >> Math.min((parseInt(str) || 0), 2147483647) >> will return the correct result that we want. 46 | */ 47 | 48 | // Solution-3 - Crude / dirty version of atoi 49 | atoi_crude = str => { 50 | 51 | let finalInteger = parseInt(str); 52 | 53 | if (finalInteger > 2147483647 ) { 54 | finalInteger = 2147483647 55 | } else if ( finalInteger < -2147483648) { 56 | finalInteger = - 2147483648 57 | } 58 | 59 | return isNaN(finalInteger) ? 0 : finalInteger; 60 | } 61 | -------------------------------------------------------------------------------- /string-to-integer-atoi-2.js: -------------------------------------------------------------------------------- 1 | /* Convert a string to an integer in C, JavaScript, and Ruby 2 | 3 | Some Theory - A> The number system ranges from 48 to 59 in chartCodeAt() method 4 | 5 | console.log("0".charCodeAt("0")); // 48 6 | console.log("9".charCodeAt("0")); // 57 7 | 8 | B> JavaScript's highest integer value that a number can go to without losing precision? - he max safe integer is 231-1, or 2147483647. 9 | */ 10 | 11 | // SOLUTION WITHOUT USING REGEXP AND PARSEINT 12 | 13 | myAtoi = str => { 14 | 15 | let i = 0, numSign = '+', number = '', finalOutputNum = 0, base10Multiplier = 1; 16 | 17 | str = str.trim() // remove all whitespaces from both ends 18 | 19 | // First move i forward and update sign to take up '-' if '-' is found 20 | // And if a '+' is found just treat it, as if there was nothing before the number and check-out the next number to start building the number with the next loop 21 | if (str[0] === '+') { 22 | i++ 23 | } else if (str[0] === '-') { 24 | numSign = '-' 25 | i++ 26 | } 27 | 28 | // For the above code, I could just use Regexp, like my other solution in my other file. 29 | 30 | // Now traverse through the given string argument and build the number string. 31 | 32 | for (i ; i < str.length; i++) { 33 | 34 | if (str[i].charCodeAt(0) >= 48 && str[i].charCodeAt(0) <= 57) { 35 | number += str[i] 36 | } else { 37 | if (number === "") { 38 | return 0 39 | } else { 40 | break; 41 | } 42 | } 43 | } 44 | 45 | // From the above I have a string "number". Now without using parseInt() I will convert it to an integer 46 | for (i = (number.length - 1); i >=0; i--) { 47 | 48 | finalOutputNum += base10Multiplier * number[i]; 49 | base10Multiplier *= 10; 50 | 51 | if ( finalOutputNum > 2147483647 && numSign === '+' ) { 52 | return 2147483647 53 | } else if (finalOutputNum > 2147483648 && numSign === '-' ) { 54 | return -2147483648; 55 | } 56 | } 57 | 58 | return ( numSign === '-' ? (-1 * finalOutputNum) : finalOutputNum ) 59 | 60 | } 61 | 62 | console.log(myAtoi("+1")); // => 1 -------------------------------------------------------------------------------- /valid-parentheses.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/valid-parentheses/description/ 2 | 3 | Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. 4 | 5 | The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not.*/ 6 | 7 | /*Solution Algo - 8 | A) If I can match all of the passed-in parenthesis after traversing the string character by character, then return true. Else, if a single unmatched parenthesis remains, then return false. 9 | 10 | B> So, while, traversing the array, create an empty temporaray array to which I will push only unmatched parenthesis, which will be compared for the next iteraion. 11 | 12 | C> and all matched parenthesis are popped. 13 | */ 14 | 15 | var isValid = function(s) { 16 | var tempArray = []; 17 | 18 | s.split('').forEach(function(currentParenthesis) { 19 | var lastUnmatchedParenthesis = tempArray[tempArray.length - 1]; 20 | if ( lastUnmatchedParenthesis === "(" && currentParenthesis === ")" || 21 | lastUnmatchedParenthesis === "{" && currentParenthesis === "}" || 22 | lastUnmatchedParenthesis === "[" && currentParenthesis === "]" ) { 23 | return tempArray.pop(); 24 | } else { 25 | tempArray.push(currentParenthesis); 26 | } 27 | }); 28 | 29 | return tempArray.length === 0; 30 | 31 | } 32 | 33 | var str = "(){}[][" 34 | 35 | console.log(isValid((str))); 36 | 37 | -------------------------------------------------------------------------------- /zigzag-conversion.js: -------------------------------------------------------------------------------- 1 | /*https://leetcode.com/problems/zigzag-conversion/description/ 2 | 3 | The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility) 4 | 5 | P A H N 6 | A P L S I I G 7 | Y I R 8 | And then read line by line: "PAHNAPLSIIGYIR" 9 | Write the code that will take a string and make this conversion given a number of rows: 10 | 11 | string convert(string text, int nRows); 12 | 13 | convert("PAYPALISHIRING", 3) should return "PAHNAPLSIIGYIR".*/ 14 | 15 | /*Solution Logic 16 | 17 | 1 - I need to do here is to break down the input string in zigzag fashion visually, and recompose row by row. 18 | 19 | "P" `A Y- P "A" `L I- S "H" `I R- I "N" `G >> in ZigZag representation will be >> Noting the movement is as below 20 | 21 | P > A > Y > P > A > L > I > S > H > I > R > I > N > G 22 | 23 | P | A | H | N 24 | A P | L S | I I | G 25 | Y | I | R | 26 | 27 | Lets arrange the index position of the above arrangement as below.. 28 | 29 | 0 4 8 12 30 | 1 3 5 7 9 11 13 31 | 2 6 10 32 | 33 | Target of the program is to convert 34 | 35 | "P" A Y P "A" L I S "H" I R I "N" G >> "P" "A" "H" "N" A P L S I I G Y I R 36 | 37 | 38 | 2 - To distribute the elements so that the ZigZag is formed. we have to first calculate, periodSize or Gap (also called cycles). Which is the "Gap" in terms of positional index value (starting from 0) between successive "column" elements in the same row, in the string given as the argument to the function. 39 | 40 | Meaning in the given string "PAYPALISHIRING" which is in the ZigZag format, the in the first row, the Gap between first two successive elements "P" and "A" is 4 if they were arranged in the Non-ZigZag format. 41 | 42 | And the formulae to get periodSize or Gap is (2 * numOfRows - 2) i.e. 4 in this case. 43 | 44 | 45 | 3 - To understand the above with a general example - 46 | http://www.lifeincode.net/programming/leetcode-zigzag-conversion-java/ 47 | 48 | For example, when nRows = 4, we know the ZigZag should be like the following. 49 | 50 | 0 6 12 18 51 | 1 5 7 11 13 17 19 52 | 2 4 8 10 14 16 20 53 | 3 9 15 21 54 | 55 | Here, the "Gap" is 6 ( 4 * 2 - 2). In the formmulae ( numRows * 2 -2 ) the subtracting, 2 indicates there there are no numbers between the 4-number column in the first line and last line. And there is only one number between 4-number column in other lines. 56 | 57 | That is, without a ZigZag, from sequentially going from the first element of the first row, which is "0" here, to the second element of the first row (which is "6") here, I had to traverse 4 element down and then 4 elements up, giving me a Gap of 8. But because of the way Zigzag is formed, I am skipping the 2 inbetween number / positions. Hence the deduction by 2. 58 | 59 | 60 | 61 | 4 - The solution accumulates, the next element in each row one by one. So first it takes the starting character of the given string (i.e. s.charAt(0) ). Then the next character to add would be at position (0 + periodSize) ie. at charCode(4) , which is "A" here. 62 | 63 | Then the third character to add would be at position ( 0 + periodSize + periodSize ) i.e charCode(8) which is "H" here. 64 | 65 | In this way we get the first row "PAHN" 66 | 67 | 68 | 5 - But for the middle rows we have to start a second iterartion loop. Because, in the first and the last row the number of characters will be eaxtly equal to the size of the "period"/"cycles" - that is one element for each column. That is, there is no element between the "column" elements. 69 | 70 | But in all the middle rows, we have to insert one element between the "column" elements. This is resulting from the way a a ZigZag is formed by the ZigZag movement. 71 | 72 | 73 | 6 - When we go into the middle loop with i - 1 >> At this step of the iteration, each of the j and secondJ value will be calculated sequentially and added to result. 74 | 75 | 76 | 7 - for i (no of rows or row index ) when the second iteration starts, that is i = 1 >> the variable j takes that value for the first iteration (as j = i in the for loop) and adds that character to result. Thats why immediately after "PAHN" (the value of result after first iteration), I am getting "A" as the value of j and which is being added to result. 77 | 78 | But now, the the code for the mniddle row starts, as the condition ( i !==0 && i !== numRows -1) satisfies. So, after j is assigned the value of "A" the secondJ calculation will be executed and added to the result till now. 79 | 80 | 8 - We only visit each character in s once. So the complexity is only O(n). 81 | 82 | */ 83 | 84 | var convert = function(s, numRows) { 85 | var periodSize = (numRows * 2) - 2; 86 | var len = s.length; 87 | var result = ''; 88 | var i, j, secondJ; 89 | 90 | if (numRows === 1) { 91 | return s; 92 | } 93 | 94 | for (i = 0; i < numRows; i++) { 95 | for (j = i; j < len; j += periodSize) { 96 | result += s.charAt(j); 97 | 98 | 99 | // For middle rows 100 | if (i !== 0 && i !== (numRows - 1)) { 101 | secondJ = (j + periodSize ) - (2 * i); 102 | 103 | if (secondJ < len) { 104 | result += s.charAt(secondJ); 105 | } 106 | // console.log("index value of j is " + j); 107 | // console.log("index value of sedondJ is " + secondJ); 108 | } 109 | } 110 | } 111 | return result; 112 | } 113 | 114 | 115 | console.log(convert("PAYPALISHIRING", 3)); // should return "PAHNAPLSIIGYIR" 116 | 117 | /* 118 | convert('ABCDEF', 4) should return 'ABFCED' 119 | Row 1 -> A 120 | Row 2 -> B F 121 | Row 3 -> C E 122 | Row 4 -> D 123 | */ 124 | // console.log(convert('ABCDEF', 4)); 125 | 126 | 127 | /* 128 | convert('ABCDEF', 2) should returns 'ACEBDF' 129 | Row 1 -> A C E 130 | Row 2 -> B D F 131 | */ 132 | // console.log(convert('ABCDEF', 2)); --------------------------------------------------------------------------------