diff --git a/L-A/0014 Memoize II/MemoizeII.js b/L-A/0014 Memoize II/MemoizeII.js new file mode 100644 index 0000000..3d7f3c8 --- /dev/null +++ b/L-A/0014 Memoize II/MemoizeII.js @@ -0,0 +1,26 @@ + +const RES = Symbol("result"); + +/** + * @param {Function} fn + */ +function memoize(fn) { + const globalCache = new Map(); + + return (...params) => { + let currentCache = globalCache; + for(const param of params) { + if (!currentCache.has(param)) { + currentCache.set(param, new Map()); + } + currentCache = currentCache.get(param); + } + + if (currentCache.has(RES)) return currentCache.get(RES); + + const result = fn(...params); + + currentCache.set(RES, result); + return result; + } +} diff --git a/L-A/0014 Memoize II/README.md b/L-A/0014 Memoize II/README.md new file mode 100644 index 0000000..5e046c3 --- /dev/null +++ b/L-A/0014 Memoize II/README.md @@ -0,0 +1,80 @@ +# Memoize II +[LeetCode Problem]https://leetcode.com/problems/memoize-ii/ + +Given a function fn, return a memoized version of that function. + +A memoized function is a function that will never be called twice with the same inputs. Instead it will return a cached value. + +fn can be any function and there are no constraints on what type of values it accepts. Inputs are considered identical if they are === to each other. + +## Example 1: +```javascript +Input: +getInputs = () => [[2,2],[2,2],[1,2]] +fn = function (a, b) { return a + b; } +Output: [{"val":4,"calls":1},{"val":4,"calls":1},{"val":3,"calls":2}] +Explanation: +const inputs = getInputs(); +const memoized = memoize(fn); +for (const arr of inputs) { + memoized(...arr); +} + +For the inputs of (2, 2): 2 + 2 = 4, and it required a call to fn(). +For the inputs of (2, 2): 2 + 2 = 4, but those inputs were seen before so no call to fn() was required. +For the inputs of (1, 2): 1 + 2 = 3, and it required another call to fn() for a total of 2. +``` + +## Example 2: +```javascript +Input: +getInputs = () => [[{},{}],[{},{}],[{},{}]] +fn = function (a, b) { return ({...a, ...b}); } +Output: [{"val":{},"calls":1},{"val":{},"calls":2},{"val":{},"calls":3}] +Explanation: +Merging two empty objects will always result in an empty object. It may seem like there should only be 1 call to fn() because of cache-hits, however none of those objects are === to each other. +``` + + +## Example 3: +```javascript +Input: +getInputs = () => { const o = {}; return [[o,o],[o,o],[o,o]]; } +fn = function (a, b) { return ({...a, ...b}); } +Output: [{"val":{},"calls":1},{"val":{},"calls":1},{"val":{},"calls":1}] +Explanation: +Merging two empty objects will always result in an empty object. The 2nd and 3rd third function calls result in a cache-hit. This is because every object passed in is identical. +``` + +### Constraints: +```javascript +1 <= inputs.length <= 105 +0 <= inputs.flat().length <= 105 +inputs[i][j] != NaN +``` + +## Approach: +Map is perfect for storing single argument. Each consecutive argument must have cache based on previous argument, which will form a tree like structure, like this: +```javascript +fn(1,3,4) // { 1: { 3: { 4: {}}}}; +fn(1,4,3) // { 1: { 3: { 4: {}}, 4: { 3: {}}}}; +``` +The only problem, is how do we store our result. It's been never stated, that memoized function will be called with the same amount of arguments every time. We need a way to store our result anywhere on the path and also make sure that it will never be misteaken with argument. Here is example. +```javascript +fn(1,3) // { 1: { 3: 4}}; +-> 4 +fn(1) // { 1: { 3: 4}}; +-> { 3: 4 } // returning cache branch as result +``` +There are different aproaches to overcome this. But since every Symbol() call is guaranteed to return a unique Symbol we can use it to store actual result with guarantee, that it will never match any argument. + +## Problem Added By + +- [deveshidwivedi](https://github.com/deveshidwivedi) + + + +## Contributing +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. diff --git a/L-A/0015 Largest Prime Palindrome/LargestPrimePalindrome.js b/L-A/0015 Largest Prime Palindrome/LargestPrimePalindrome.js new file mode 100644 index 0000000..e7e2df6 --- /dev/null +++ b/L-A/0015 Largest Prime Palindrome/LargestPrimePalindrome.js @@ -0,0 +1,39 @@ +function isPrime(num) { + if (num <= 1) { + return false; + } + if (num <= 3) { + return true; + } + if (num % 2 === 0 || num % 3 === 0) { + return false; + } + let i = 5; + while (i * i <= num) { + if (num % i === 0 || num % (i + 2) === 0) { + return false; + } + i += 6; + } + return true; +} + +function isPalindrome(num) { + const numStr = num.toString(); + const reversedStr = numStr.split("").reverse().join(""); + return numStr === reversedStr; +} + +function largestPrimePalindrome(n) { + for (let i = n; i >= 2; i--) { + if (isPrime(i) && isPalindrome(i)) { + return i; + } + } + return null; // No prime palindrome found in the range +} + +// Test cases +console.log(largestPrimePalindrome(100)); // 7 +console.log(largestPrimePalindrome(50)); // 7 +console.log(largestPrimePalindrome(10)); // 7 diff --git a/L-A/0015 Largest Prime Palindrome/README.md b/L-A/0015 Largest Prime Palindrome/README.md new file mode 100644 index 0000000..3617356 --- /dev/null +++ b/L-A/0015 Largest Prime Palindrome/README.md @@ -0,0 +1,81 @@ +# 0015 Largest Prime Palindrome ( L-A ) + +## Problem + +Write a JavaScript function called largestPrimePalindrome that takes an integer **n** as input and returns the largest prime palindrome that is less than or equal to **n**. A prime palindrome is a number that is both prime and reads the same forward and backward. + +**Example** + +``` +If the input n is 100, the function should return 7 because the largest prime palindrome less than or equal to 100 is 7. + +If the input n is 50, the function should return 7 because 7 is the largest prime palindrome less than or equal to 50. + +If the input n is 10, the function should return 7 because 7 is the largest prime palindrome less than or equal to 10. +``` + +## Solutions + +```javascript +function isPrime(num) { + if (num <= 1) { + return false; + } + if (num <= 3) { + return true; + } + if (num % 2 === 0 || num % 3 === 0) { + return false; + } + let i = 5; + while (i * i <= num) { + if (num % i === 0 || num % (i + 2) === 0) { + return false; + } + i += 6; + } + return true; +} + +function isPalindrome(num) { + const numStr = num.toString(); + const reversedStr = numStr.split("").reverse().join(""); + return numStr === reversedStr; +} + +function largestPrimePalindrome(n) { + for (let i = n; i >= 2; i--) { + if (isPrime(i) && isPalindrome(i)) { + return i; + } + } + return null; // No prime palindrome found in the range +} + +// Test cases +console.log(largestPrimePalindrome(100)); // 7 +console.log(largestPrimePalindrome(50)); // 7 +console.log(largestPrimePalindrome(10)); // 7 +``` + +## How it works + +1. The isPrime function checks whether a given number is prime using a primality test that efficiently eliminates multiples of 2 and 3 and then checks for divisibility by numbers of the form 6k ± 1. + +2. The isPalindrome function checks whether a given number is a palindrome by converting it to a string, reversing the string, and comparing it to the original string. + +3. The largestPrimePalindrome function starts from the given number n and counts down to 2, checking each number in reverse order. It uses the isPrime and isPalindrome functions to find the largest prime palindrome in the given range. + +## References + +- [ChatGPT](https://chat.openai.com/) + +## Problem Added By + +- [Tipchan](https://github.com/tsongtheng) + +## Contributing + +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. diff --git a/L-A/0015 Longest Valid Parentheses/LongestValidParentheses.js b/L-A/0015 Longest Valid Parentheses/LongestValidParentheses.js new file mode 100644 index 0000000..b19384a --- /dev/null +++ b/L-A/0015 Longest Valid Parentheses/LongestValidParentheses.js @@ -0,0 +1,8 @@ +var longestValidParentheses = function(S) { + let stack = [-1], ans = 0 + for (let i = 0; i < S.length; i++) + if (S[i] === '(') stack.push(i) + else if (stack.length === 1) stack[0] = i + else stack.pop(), ans = Math.max(ans, i - stack[stack.length-1]) + return ans +}; \ No newline at end of file diff --git a/L-A/0015 Longest Valid Parentheses/README.md b/L-A/0015 Longest Valid Parentheses/README.md new file mode 100644 index 0000000..60a6ddb --- /dev/null +++ b/L-A/0015 Longest Valid Parentheses/README.md @@ -0,0 +1,60 @@ +# Longest Valid Parentheses +[LeetCode Problem]https://leetcode.com/problems/longest-valid-parentheses/description/ + +Given a string containing just the characters '(' and ')', return the length of the longest valid (well-formed) parentheses substring. + +## Example 1 +``` +Input: s = "(()" +Output: 2 +Explanation: The longest valid parentheses substring is "()". +``` + +## Example 2: +``` +Input: s = ")()())" +Output: 4 +Explanation: The longest valid parentheses substring is "()()". +``` + +## Example 3: +``` +Input: s = "" +Output: 0 +``` + +### Constraints: +```javascript +0 <= s.length <= 3 * 104 +s[i] is '(', or ')' +``` + +## Approach: +One of the key things to realize about valid parentheses strings is that they're entirely self-satisfied, meaning that while you can have one substring that is entirely inside another, you can't have two substrings that only partially overlap. + +This means that we can use a greedy O(N) time complexity solution to this problem without the need for any kind of backtracking. In fact, we should be able to use a very standard stack-based valid parentheses string algorithm with just three very minor modifications. + +In a stadard valid parentheses string algorithm, we iterate through the string (S) and push the index (i) of any '(' to our stack. Whenever we find a ')', we match it with the last entry on the stack and pop said entry off. We know the string is not valid if we find a ')' while there are no '(' indexes in the stack with which to match it, and also if we have leftover '(' in the stack when we reach the end of S. + +For this problem, we will need to add in a step that updates our answer (ans) when we close a parentheses pair. Since we stored the index of the '(' in our stack, we can easily find the difference between the ')' at i and the last entry in the stack, which should be the length of the valid substring which was just closed. + +But here we run into a problem, because consecutive valid substrings can be grouped into a larger valid substring (ie, '()()' = 4). So instead of counting from the last stack entry, we should actually count from the second to last entry, to include any other valid closed substrings since the most recent '(' that will still remain after we pop the just-matched last stack entry off. + +This, of course, brings us to the second and third changes. Since we're checking the second to last stack entry, what happens in the case of '()()' when you close the second valid substring yet there's only the one stack entry left at the time? + +To avoid this issue, we can just wrap the entire string in another imaginary set of parentheses by starting with stack = [-1], indicating that there's an imaginary '(' just before the beginning of the string at i = 0. + +The other issue is that we will want to continue even if the string up to i becomes invalid due to a ')' appearing when the stack is "empty", or in this case has only our imaginary index left. In that case, we can just effectively restart our stack by updating our imaginary '(' index (stack[0] = i) and continue on. + +Then, once we reach the end of S, we can just return ans. + +## Problem Added By + +- [himanshukoshti](https://github.com/himanshukoshti) + + + +## Contributing +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. diff --git a/L-B/0026 Calculate Tip/CalculateTip.js b/L-B/0026 Calculate Tip/CalculateTip.js new file mode 100644 index 0000000..1443820 --- /dev/null +++ b/L-B/0026 Calculate Tip/CalculateTip.js @@ -0,0 +1,9 @@ +function calculateTip(totalCost, tipPercentage) { + // Calculate the tip amount by multiplying totalCost by tipPercentage divided by 100 + const tipAmount = (totalCost * tipPercentage) / 100; + return tipAmount; +} + +// Test cases +console.log(calculateTip(50, 15)); // 7.5 +console.log(calculateTip(75, 20)); // 15 diff --git a/L-B/0026 Calculate Tip/README.md b/L-B/0026 Calculate Tip/README.md new file mode 100644 index 0000000..45af127 --- /dev/null +++ b/L-B/0026 Calculate Tip/README.md @@ -0,0 +1,56 @@ +# 0026 Calculate Tip ( L-B ) + +## Problem + +You are at a restaurant, and you want to calculate the tip for your meal. Write a JavaScript function called **calculateTip** that takes two inputs: the total cost of the meal and the tip percentage.Your function should calculate the tip amount and return it. + +**Example** + +``` +If the total cost is $50 and the tip percentage is 15%, the function should return $7.5 because 15% of $50 is $7.5. + +If the total cost is $75 and the tip percentage is 20%, the function should return $15 because 20% of $75 is $15. +``` + +- **_You can assume that the tip percentage is provided as a whole number (e.g., 15 for 15%) and that the total cost is a positive number._** + +**Here's an example of how the function should work:** + +```javascript +console.log(calculateTip(50, 15)); // 7.5 +console.log(calculateTip(75, 20)); // 15 +``` + +## Solutions + +```javascript +function calculateTip(totalCost, tipPercentage) { + // Calculate the tip amount by multiplying totalCost by tipPercentage divided by 100 + const tipAmount = (totalCost * tipPercentage) / 100; + return tipAmount; +} + +// Test cases +console.log(calculateTip(50, 15)); // 7.5 +console.log(calculateTip(75, 20)); // 15 +``` + +## How it works + +1. We define a function calculateTip that takes two parameters: totalCost (the total cost of the meal) and tipPercentage (the percentage of the tip to be calculated). + +2. Inside the function, we calculate the tip amount by multiplying totalCost by tipPercentage divided by 100. This is because tip percentages are usually provided as whole numbers (e.g., 15 for 15%). + +## References + +- [ChatGPT](https://chat.openai.com/) + +## Problem Added By + +- [Tipchan](https://github.com/tsongtheng) + +## Contributing + +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. diff --git a/L-B/0026 FileExtension/FileExtension.js b/L-B/0026 FileExtension/FileExtension.js new file mode 100644 index 0000000..6987c7f --- /dev/null +++ b/L-B/0026 FileExtension/FileExtension.js @@ -0,0 +1,17 @@ +function extractFileExtension(fileName) { + // Split the file name into an array of strings at the dot character. + const splitFileName = fileName.split('.'); + + // Check if the split file name array has more than one element. + if (splitFileName.length > 1) { + // Get the last element in the array, which is the file extension. + const fileExtension = splitFileName.pop(); + + // Return the file extension. + return fileExtension; + } + // The file name does not have an extension, so return an empty string. + return ''; +} + +module.exports = extractFileExtension; diff --git a/L-B/0026 FileExtension/FileExtension.test.js b/L-B/0026 FileExtension/FileExtension.test.js new file mode 100644 index 0000000..86bdb7f --- /dev/null +++ b/L-B/0026 FileExtension/FileExtension.test.js @@ -0,0 +1,40 @@ + +const extractFileExtension = require('./FileExtension') + +describe('extractFileExtension', () => { + it('should return the file extension when given a valid file name', () => { + expect(extractFileExtension('example.txt')).toBe('txt'); + expect(extractFileExtension('document.docx')).toBe('docx'); + expect(extractFileExtension('image.jpg')).toBe('jpg'); + }); + + it('should return an empty string when given a file name without an extension', () => { + expect(extractFileExtension('README')).toBe(''); + expect(extractFileExtension('LICENSE')).toBe(''); + }); + + it('should return an empty string when given an empty string', () => { + expect(extractFileExtension('')).toBe(''); + }); +}); + +/* +test output: + PASS ./FileExtension.test.js + extractFileExtension + √ should return the file extension when given a valid file name (4 ms) + √ should return an empty string when given a file name without an extension (1 ms) + √ should return an empty string when given an empty string + +Test Suites: 1 passed, 1 total +Tests: 3 passed, 3 total +Snapshots: 0 total +Time: 0.958 s, estimated 1 s +Ran all test suites. +*/ + +/* +Testing with Jest global installation: +> npm install -g jest +> jest +*/ diff --git a/L-B/0026 FileExtension/README.md b/L-B/0026 FileExtension/README.md new file mode 100644 index 0000000..d69f24a --- /dev/null +++ b/L-B/0026 FileExtension/README.md @@ -0,0 +1,46 @@ +# Get the file extension + +## Problem + +Write a function that takes a string and returns the file extension, which is the string after the last dot (.) in the string. If there is no dot in the string, return empty string. + +## Solution + +```javascript +function extractFileExtension(fileName) { + // Split the file name into an array of strings at the dot character. + const splitFileName = fileName.split("."); + + // Check if the split file name array has more than one element. + if (splitFileName.length > 1) { + // Get the last element in the array, which is the file extension. + const fileExtension = splitFileName.pop(); + + // Return the file extension. + return fileExtension; + } + // The file name does not have an extension, so return an empty string. + return ""; +} +``` + +## How it works + +- The `extractFileExtension` function takes a string as an argument. +- The `split` method is used to split the string into an array of strings at the dot character. +- The `pop` method is used to get the last element in the array, which is the file extension. +- The file extension is returned. + +## References + +- [String.prototype.split()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) + +## Problem Added By + +- [GitHub](https://github.com/aladin002dz) + +## Contributing + +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. diff --git a/L-B/0026 FileExtension/jest.config.json b/L-B/0026 FileExtension/jest.config.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/L-B/0026 FileExtension/jest.config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/L-B/0027 Remove duplicates/README.md b/L-B/0027 Remove duplicates/README.md new file mode 100644 index 0000000..5e79830 --- /dev/null +++ b/L-B/0027 Remove duplicates/README.md @@ -0,0 +1,62 @@ +# 0027 removeDuplicates ( L-B ) + +## Problem +Write a function that removes duplicate values from the given input. +- If the input is an array, return a new array with unique values. +- If the input is a string, return a new string with duplicate characters removed. +- The original order must be preserved. + +## Solution +```js +function removeDuplicates(input) { + let unique = []; + for (let i = 0; i < input.length; i++) { + if (!unique.includes(input[i])) { + unique.push(input[i]); + } + } + if(typeof(input) === "string"){ + unique = unique.toString().replace(/,/g, ''); + } + console.log(unique); + return unique; +} +``` + +## Test Cases +```js +removeDuplicates([2, 4, 8, 4, 2, 6, 9, 2, 6, 8, 10]); +// Output: [2, 4, 8, 6, 9, 10] + +removeDuplicates([1, 1, 1, 4, 0, 6, -2, 2, 6, 7, 10]); +// Output: [1, 4, 0, 6, -2, 2, 7, 10] + +removeDuplicates("zoom"); +// Output: "zom" + +removeDuplicates("hello world"); +// Output: "helo wrd" +``` + +## How it works +- Create an empty array called unique +- Loop through each character or element in the input +- Check if the current value already exists in unique +- If it does not exist, we add it to unique +- After the loop: +- If the input is a string, we convert the array into a string +- Remove commas using replace +- Finally, return the result + +## References +- [MDN – Array.prototype.includes()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) +- [MDN – typeof operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) + + +## Problem Added By +- [GitHub](https://github.com/rimsha-shoukat) + +## Contributing +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. diff --git a/L-B/0027 Remove duplicates/removeDuplicates.js b/L-B/0027 Remove duplicates/removeDuplicates.js new file mode 100644 index 0000000..29f6dba --- /dev/null +++ b/L-B/0027 Remove duplicates/removeDuplicates.js @@ -0,0 +1,18 @@ +function removeDuplicates(input) { + let unique = []; + for (let i = 0; i < input.length; i++) { + if (!unique.includes(input[i])) { + unique.push(input[i]); + } + } + if(typeof(input) === "string"){ + unique = unique.toString().replace(/,/g, ''); + } + console.log(unique); + return unique; +} + +removeDuplicates([2, 4, 8, 4, 2, 6, 9, 2, 6, 8, 10]); +removeDuplicates([1, 1, 1, 4, 0, 6, -2, 2, 6, 7, 10]); +removeDuplicates("zoom"); +removeDuplicates("hello world"); \ No newline at end of file diff --git a/L-I/0011 DNA_Matching/DNA_Matching.js b/L-I/0011 DNA_Matching/DNA_Matching.js new file mode 100644 index 0000000..9c511b3 --- /dev/null +++ b/L-I/0011 DNA_Matching/DNA_Matching.js @@ -0,0 +1,22 @@ +function dnaMatch(dna1, dna2) { + // Check if the lengths of the two DNA sequences are different + if (dna1.length !== dna2.length) { + return false; // Different lengths, not a match + } + + // Iterate through each character of the DNA sequences + for (let i = 0; i < dna1.length; i++) { + // Compare characters at the current position + if (dna1[i] !== dna2[i]) { + return false; // Characters don't match, not a match + } + } + + // If we reach this point, all characters match, so it's a match + return true; +} + +// Test cases +console.log(dnaMatch("ACGT", "ACGT")); // true +console.log(dnaMatch("ACGT", "ACTG")); // false +console.log(dnaMatch("AACT", "AACC")); // false diff --git a/L-I/0011 DNA_Matching/README.md b/L-I/0011 DNA_Matching/README.md new file mode 100644 index 0000000..c125365 --- /dev/null +++ b/L-I/0011 DNA_Matching/README.md @@ -0,0 +1,78 @@ +# 0011 DNA_Matching ( L-I ) + +## Problem + +You are given two DNA sequences as strings, representing the genetic code of two individuals. Each DNA sequence consists of a series of characters, where each character can be one of four options: 'A' (adenine), 'C' (cytosine), 'G' (guanine), or 'T' (thymine). + +Write a JavaScript function called dnaMatch that takes these two DNA sequences as input and returns true if they are a match and false otherwise. Two DNA sequences are considered a match if they have the same characters in the same order. + +**Example** + +``` +If the input DNA sequences are "ACGT" and "ACGT", the function should return true because they are an exact match. +If the input DNA sequences are "ACGT" and "ACTG", the function should return false because the order of characters is different. +If the input DNA sequences are "AACT" and "AACC", the function should return true because some characters do not match. +``` + +**Here's an example of how the function should work:** + +```javascript +console.log(dnaMatch("ACGT", "ACGT")); // true +console.log(dnaMatch("ACGT", "ACTG")); // false +console.log(dnaMatch("AACT", "AACC")); // false +``` + +## Solutions + +```javascript +function dnaMatch(dna1, dna2) { + // Check if the lengths of the two DNA sequences are different + if (dna1.length !== dna2.length) { + return false; // Different lengths, not a match + } + + // Iterate through each character of the DNA sequences + for (let i = 0; i < dna1.length; i++) { + // Compare characters at the current position + if (dna1[i] !== dna2[i]) { + return false; // Characters don't match, not a match + } + } + + // If we reach this point, all characters match, so it's a match + return true; +} + +// Test cases +console.log(dnaMatch("ACGT", "ACGT")); // true +console.log(dnaMatch("ACGT", "ACTG")); // false +console.log(dnaMatch("AACT", "AACC")); // false +``` + +## How it works + +1. The `dnaMatch` function takes two input arguments: `dna1` and `dna2`, which are the two DNA sequences we want to compare. + +2. First, it checks if the lengths of `dna1` and `dna2` are different using the `if (dna1.length !== dna2.length)` conditional statement. If they have different lengths, the function immediately returns `false` because sequences of different lengths cannot be a match. + +3. If the lengths are the same, the function proceeds to compare the characters of the two DNA sequences. + +4. It enters a `for` loop that iterates through the characters of the sequences. The loop is controlled by the variable `i`, which starts at 0 and goes up to `dna1.length - 1`. This loop allows us to compare characters at the same position in both sequences. + +5. Inside the loop, the code compares the characters at the current position `i` using the conditional statement `if (dna1[i] !== dna2[i])`. If the characters at position `i` are not the same in both sequences, the function immediately returns `false` because it found a mismatch. + +6. If the loop completes without finding any mismatches, meaning it has compared all characters in both sequences, the function returns `true`. This indicates that the two DNA sequences are identical and, therefore, a match. + +## References + +- [ChatGPT](https://chat.openai.com/) + +## Problem Added By + +- [Tipchan](https://github.com/tsongtheng) + +## Contributing + +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. diff --git a/L-I/0011 ThreeSum/README.md b/L-I/0011 ThreeSum/README.md new file mode 100644 index 0000000..b4547d9 --- /dev/null +++ b/L-I/0011 ThreeSum/README.md @@ -0,0 +1,127 @@ +# 0011 ThreeSum ( L-I ) + +## Problem +Three Sum (3SUM) + +Given an array nums of n integers, are there elements  `a, b, c`   in nums such that   `a + b + c = target` ? Find all unique triplets in the array which gives the sum is equal to  `target`  . + + + +## Solution + +```javascript +// 1. Brute Force Solution +const threeSum_brute_Force = (nums, target) => { + let result = []; + for (let i = 0; i < nums.length; i++) { + for (let j = i + 1; j < nums.length; j++) { + for (let k = j + 1; k < nums.length; k++) { + if (nums[i] + nums[j] + nums[k] === target) { + result.push([nums[i], nums[j], nums[k]]); + } + } + } + } + return result; +} + +// 2. Using a hash table +const threeSum_hash_table = (nums, target) => { + let result = []; + const hash = {}; + for (let i = 0; i < nums.length; i++) { + for (let j = i + 1; j < nums.length; j++) { + const complement = target - (nums[i] + nums[j]); + if (complement in hash) { + result.push([nums[i], nums[j], complement]); + } else { + hash[nums[j]] = true; + } + } + } + + return result; +} + +// 3. Two Pointer Technique +const threeSum_two_pointer = (nums, target) => { + let result = []; + nums.sort((a, b) => a - b); + for (let i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] === nums[i - 1]) continue; + let left = i + 1; + let right = nums.length - 1; + while (left < right) { + const sum = nums[i] + nums[left] + nums[right]; + if (sum === target) { + result.push([nums[i], nums[left], nums[right]]); + while (left < right && nums[left] === nums[left + 1]) left++; + while (left < right && nums[right] === nums[right - 1]) right--; + left++; + right--; + } else if (sum < target) { + left++; + } else { + right--; + } + } + } + return result; +} +``` + +## How it works +### 1. Brute Force Steps + +1. Initialize an empty array result to store the unique triplets that sum to the target value. + +2. Use three nested loops to iterate through the elements of the nums array. The outermost loop (indexed by i) iterates from the first element to the second-to-last element. + +3. The second loop (indexed by j) iterates from the element after the i-th element to the second-to-last element. + +4. The innermost loop (indexed by k) iterates from the element after the j-th element to the last element of the nums array. + +5. Within the innermost loop, check if the sum of the elements at indices i, j, and k is equal to the target value. + +6. If the sum is equal to the target, create a triplet by selecting the elements at these indices (nums[i], nums[j], nums[k]) and push it into the result array. + +7. Continue iterating through the loops to find all such triplets. + +8. Finally, return the result array containing all unique triplets that sum to the target value. + +### 2. Hash Table Steps + +1. Initialize an empty array result to store the unique triplets. +2. Create an empty hash table hash to store the values encountered in the inner loop. +3. Use two nested loops to iterate through the nums array. +4. Calculate the complement by subtracting the sum of nums[i] and nums[j] from the target. +5. Check if the complement exists in the hash table. +6. If found, add [nums[i], nums[j], complement] to the result array. +7. If not found, store nums[j] in the hash table. +8. Return the result array containing all unique triplets that sum to the target value. + +### 3. Two Pointer Technique Steps + +1. Sort the nums array in ascending order. +2. Iterate through the sorted array with a loop, selecting an element nums[i] as the first element of a potential triplet. +3. Use two pointers, left and right, to search for a pair of elements that sum up to the complement of nums[i] (i.e., target - nums[i]). +4. If found, add [nums[i], nums[left], nums[right]] to the result array, and move both pointers while skipping duplicates. +5. Continue the iteration until all unique triplets that sum to the target are found. +6. Return the result array containing all unique triplets. + + +## References +- [Wikipedia](https://en.wikipedia.org/wiki/3SUM) +- [Leetcode](https://leetcode.com/problems/3sum/) + + +## Problem Added By +- [PortFolio](https://femil-savaliya.netlify.app) +- [GitHub](https://www.github.com/Femil32) +- [LinkedIn](https://www.linkedin.com/in/femil-savaliya) + + +## Contributing +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. \ No newline at end of file diff --git a/L-I/0011 ThreeSum/threeSum.js b/L-I/0011 ThreeSum/threeSum.js new file mode 100644 index 0000000..17cdb52 --- /dev/null +++ b/L-I/0011 ThreeSum/threeSum.js @@ -0,0 +1,58 @@ +// 1. Brute Force Solution +const threeSum_brute_Force = (nums, target) => { + let result = []; + for (let i = 0; i < nums.length; i++) { + for (let j = i + 1; j < nums.length; j++) { + for (let k = j + 1; k < nums.length; k++) { + if (nums[i] + nums[j] + nums[k] === target) { + result.push([nums[i], nums[j], nums[k]]); + } + } + } + } + return result; +} + +// 2. Using a hash table +const threeSum_hash_table = (nums, target) => { + let result = []; + const hash = {}; + for (let i = 0; i < nums.length; i++) { + for (let j = i + 1; j < nums.length; j++) { + const complement = target - (nums[i] + nums[j]); + if (complement in hash) { + result.push([nums[i], nums[j], complement]); + } else { + hash[nums[j]] = true; + } + } + } + + return result; +} + +// 3. Two Pointer Technique +const threeSum_two_pointer = (nums, target) => { + let result = []; + nums.sort((a, b) => a - b); + for (let i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] === nums[i - 1]) continue; + let left = i + 1; + let right = nums.length - 1; + while (left < right) { + const sum = nums[i] + nums[left] + nums[right]; + if (sum === target) { + result.push([nums[i], nums[left], nums[right]]); + while (left < right && nums[left] === nums[left + 1]) left++; + while (left < right && nums[right] === nums[right - 1]) right--; + left++; + right--; + } else if (sum < target) { + left++; + } else { + right--; + } + } + } + return result; +} \ No newline at end of file diff --git a/L-I/0012 Length converter/README.md b/L-I/0012 Length converter/README.md new file mode 100644 index 0000000..82560ba --- /dev/null +++ b/L-I/0012 Length converter/README.md @@ -0,0 +1,79 @@ +# 0012 lengthConverter ( L-I ) + +## Problem +Create a function that converts a given length value from one unit to another. +The function should: +- Accept a numeric length +- Accept a fromUnit and toUnit +- Support common metric and imperial units +- Return the converted value rounded to 5 decimal places +- Throw an error if an invalid unit is provided + +## Supported Units +- meters +- kilometers +- centimeters +- millimeters +- inches +- feet +- yards +- miles + +## Solution +```js +function lengthConverter(length, fromUnit, toUnit) { + const units = { + "meters": 1, + "kilometers": 1000, + "centimeters": 0.01, + "millimeters": 0.001, + "inches": 0.0254, + "feet": 0.3048, + "yards": 0.9144, + "miles": 1609.34 + }; + + if (!units[fromUnit] || !units[toUnit]) { + throw new Error("Invalid unit"); + } + const meters = length * units[fromUnit]; + console.log((meters / units[toUnit]).toFixed(3)); + return (meters / units[toUnit]).toFixed(3); +} +``` + +## Test Cases +```js +removeDuplicates([2, 4, 8, 4, 2, 6, 9, 2, 6, 8, 10]); +// Output: [2, 4, 8, 6, 9, 10] + +removeDuplicates([1, 1, 1, 4, 0, 6, -2, 2, 6, 7, 10]); +// Output: [1, 4, 0, 6, -2, 2, 7, 10] + +removeDuplicates("zoom"); +// Output: "zom" + +removeDuplicates("hello world"); +// Output: "helo wrd" +``` + +## How it works +- Define a units object where each unit is mapped to its value in meters +- Validate both fromUnit and toUnit +- The input length is first converted into meters +- Then we convert meters into the target unit +- The result is rounded to 5 decimal places using toFixed(5) +- Finally, the converted value is returned + +## References +- [Wikipedia – Unit conversion](https://en.wikipedia.org/wiki/Unit_conversion) +- [MDN – JavaScript Objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects) + + +## Problem Added By +- [GitHub](https://github.com/rimsha-shoukat) + +## Contributing +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. \ No newline at end of file diff --git a/L-I/0012 Length converter/lengthConverter.js b/L-I/0012 Length converter/lengthConverter.js new file mode 100644 index 0000000..d6a78f1 --- /dev/null +++ b/L-I/0012 Length converter/lengthConverter.js @@ -0,0 +1,29 @@ +function lengthConverter(length, fromUnit, toUnit) { + const units = { + "meters": 1, + "kilometers": 1000, + "centimeters": 0.01, + "millimeters": 0.001, + "inches": 0.0254, + "feet": 0.3048, + "yards": 0.9144, + "miles": 1609.34 + }; + + if (!units[fromUnit] || !units[toUnit]) { + throw new Error("Invalid unit"); + } + + const meters = length * units[fromUnit]; + console.log((meters / units[toUnit]).toFixed(2)); + return (meters / units[toUnit]).toFixed(2); +} + +lengthConverter(100, "meters", "kilometers"); +lengthConverter(5, "miles", "feet"); +lengthConverter(12, "inches", "centimeters"); +lengthConverter(2500, "centimeters", "meters"); +lengthConverter(3, "kilometers", "miles"); +lengthConverter(10, "feet", "yards"); +lengthConverter(5000, "millimeters", "meters"); +lengthConverter(2, "yards", "inches"); \ No newline at end of file