Leetcode JavaScript Problems

Introduction

The realm of coding interviews and competitive programming is abundant with challenges that demand your utmost proficiency. LeetCode stands out as a crucial platform for developers to refine their technical skills and enhance their problem-solving capabilities. Within LeetCode, a vast array of coding problems is available, ranging from the most basic to the exceedingly complex. It serves as a testing ground where you can hone your algorithmic abilities and gain expertise in the utilization of various data structures.

In the vast array of emerging programming languages available today, one stands out for its versatility and widespread utilization, particularly in web development. This article focuses on the selection of JavaScript problems from LeetCode, offering valuable techniques, strategies, and resources aimed at enhancing the problem-solving abilities of developers who are at intermediate or advanced stages in their careers.

No matter if you are an experienced JavaScript developer aiming to conquer the challenges associated with algorithms, or a newcomer eager to start your journey of tackling problems on the LeetCode platform, this guide is designed to equip you with the essential knowledge and skills necessary for your success. Armed with the capabilities of JavaScript, we are embarking on a quest to understand the complexities of coding challenges as we gradually unveil the secrets of algorithms on the vast expanse of the Internet.

Understanding LeetCode Problems

A fundamental step is to gain a comprehensive understanding of the characteristics of LeetCode problems. Essentially, these challenges are designed to simultaneously assess various aspects of your programming abilities, including algorithmic efficiency, data structure manipulation, and problem-solving analysis. Each problem typically includes a clear definition, constraints, and examples to illustrate the expected input and output. It is essential to spend adequate time familiarizing yourself with these problems before attempting to tackle them.

Strategies for Success:

  • Start with Easy Problems: Whenever you are new to LeetCode or JavaScript, start with the easy problems for training and grasping the area. Study the basic algorithm structure, solve some simple entities, and update the system first, then proceed to the more advanced operation.
  • Use Built-in Data Structures and Methods: JavaScript contains a large number of built-in data structures and functions that can make the data flow faster and more comfortably. Acquaint yourself with the arrays, objects, strings, and basic methods like map, filter, and reduce provided. Frequently relying on them not only helps to keep your solutions short but also makes them more efficient.
  • Practice Algorithmic Techniques: While there are various solutions to problems on LeetCode, many of them can be solved using simple algorithmic techniques such as recursion, dynamic programming, greedy algorithms, and more. Please spend some time figuring these things out and putting them into the context of the different problems you practice.
  • Optimize for Time and Space Complexity: LeetCode not only verifies the logic of your solution but also speeds it up. Note the time and space complexity of your algorithms; you also need to try to boost their performances. JS's ability to apply different optimization patterns (e.g., memorization, two-pointer, and Bitwise operations) can be utilized to great advantage.
  • Test Your Solutions: LeetCode is a convenient tool for confirming that your solution works on the set of test data as much as possible. Explore these tricks to check your work and spot any errors. While paying attention to these scenarios, also be sure to address edge cases and corner scenarios so that you can never deny any bugs in the system.
  • Resources for Learning and Practice

  • Official LeetCode Documentation: LeetCode even provides complete documentation, including a developers' manual explaining the data structure, algorithm, and coding patterns. Look at these resources to gain insights into different conflict resolution strategies.
  • Online Courses and Tutorials: Hundreds of websites provide their own LeetCode courses and JavaScript tutorials that target interested learners. The internet has greatly influenced the way people prepare for technology-related interviews. Platforms such as Udemy, Coursera, and freeCodeCamp are examples of developers obtaining learning paths to cover a broad scope of coding interview questions.
  • Community Forums and Discussions: Engage with and interact with developers' active community on platforms such as LeetCode discussion forum, Stack Overflow, and Reddit. It cannot be denied that engaging in discussions and opinions, peer review, and consulting those with richer experience in this field will aid you greatly when it comes to your education.
  • Problem 1:

For a given integer n, return true if it is a power of two; otherwise, return false.

An integer n qualifies as a power of two if there exists an integer x for which the equation n == 2^x holds true.

Example 1:

Input: n = 1

Output: true

Explanation: 2^0 = 1

Example 2:

Input: n = 16

Output: true

Explanation: 2^4 = 16

Example 3:

Input: n = 3

Output: false

Constraints:

-231 <= n <= 231 - 1

JavaScript:

Example

function isPowerOfTwo(n) {
    // Check if n is positive
    if (n <= 0) return false;
    // Using bitwise AND to check if n has only one set bit
    return (n & (n - 1)) === 0;
}
// Example usage:
console.log(isPowerOfTwo(1));   // Output: true
console.log(isPowerOfTwo(16));  // Output: true
console.log(isPowerOfTwo(3));   // Output: false

This procedure works by examining whether n has only one bit set to 1. It should n be a power of two; it will have only the first bit on, and the rest flipped after the first bit is set to 1. Hence, n & n-1 will yield a zero bitwise AND value for powers of two.

Problem 2:

Given a positive integer millis, write an asynchronous function that sleeps for millis milliseconds. It can resolve any value.

Example 1:

Input: millis = 100

Output: 100

Explanation: It should return a promise that resolves after 100ms.

let t = Date.now;

sleep(100).then( => {

console.log(Date.now - t); // 100

Example 2:

Input: millis = 200

Output: 200

Clarification: It is expected to return a promise that fulfills after a duration of 200 milliseconds.

Constraints:

1 <= millis <= 1000

JavaScript:

Example

function sleep(millis) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(millis);
        }, millis);
    });
}
// Example usage:
let t1 = Date.now();
sleep(100).then((result) => {
    console.log("Output:", result);
    console.log("Elapsed time:", Date.now() - t1); // Should print approximately 100
});
// Another example usage:
let t2 = Date.now();
sleep(200).then((result) => {
    console.log("Output:", result);
    console.log("Elapsed time:", Date.now() - t2); // Should print approximately 200
});

Output:

Output

Output: 100
Elapsed time: 100
Output: 200
Elapsed time: 200

This code returns a Promise that is resolved after the wait period indicated in milliseconds. Then, a method is devised to handle the fulfilled value of the promise - in our case, it is the very millis parameter itself.

Problem 3:

Given an integer array nums, a reducer function fn, and an initial value init, return the final result obtained by executing the fn function on each element of the array, sequentially passing in the return value from the calculation on the preceding element.

This result is achieved through the following operations: val = fn(init, nums[0]), val = fn(val, nums[1]), val = fn(val, nums[2]), ... until every element in the array has been processed. The ultimate value of val is then returned.

If the length of the array is 0, the function should return init.

Please solve it without using the built-in Array.reduce method.

Example 1:

Input:

nums = [1,2,3,4]

fn = function sum(accum, curr) { return accum + curr; }

init = 0

Output: 10

Explanation:

Initially, the value is init=0.

(0) + nums[0] = 1

(1) + nums[1] = 3

(3) + nums[2] = 6

(6) + nums[3] = 10

The final answer is 10.

Example 2:

Input:

nums = [1,2,3,4]

fn = function sum(accum, curr) { return accum + curr * curr; }

init = 100

Output: 130

Explanation:

Initially, the value is init=100.

(100) + nums[0] * nums[0] = 101

(101) + nums[1] * nums[1] = 105

(105) + nums[2] * nums[2] = 114

(114) + nums[3] * nums[3] = 130

The final answer is 130.

Example 3:

Input:

nums =

fn = function sum(accum, curr) { return 0; }

init = 25

Output: 25

Explanation: For empty arrays, the answer is always init.

Constraints:

0 <= nums.length <= 1000

0 <= nums[i] <= 1000

0 <= init <= 1000

JavaScript:

Example

function applyReducer(nums, fn, init) {
    if (nums.length === 0) {
        return init;
    }
    let result = init;
    for (let i = 0; i < nums.length; i++) {
        result = fn(result, nums[i]);
    }
    return result;
}
// Example 1:
let nums1 = [1, 2, 3, 4];
let fn1 = function sum(accum, curr) { return accum + curr; };
let init1 = 0;
console.log("Output:", applyReducer(nums1, fn1, init1)); // Output: 10
// Example 2:
let nums2 = [1, 2, 3, 4];
let fn2 = function sum(accum, curr) { return accum + curr * curr; };
let init2 = 100;
console.log("Output:", applyReducer(nums2, fn2, init2)); // Output: 130
// Example 3:
let nums3 = [];
let fn3 = function sum(accum, curr) { return 0; };
let init3 = 25;
console.log("Output:", applyReducer(nums3, fn3, init3)); // Output: 25

Output:

4.

Problem 4:

Given an array of functions [f1, f2, f3, ..., fn], return a new function fn that is the function composition of the array of functions.

The function composition of [f(x), g(x), h(x)] is fn(x) = f(g(h(x))).

The function composition of an empty list of functions is the identity function f(x) = x.

Each function in the array accepts one integer as input and returns one integer as output.

Example 1:

Input: functions = [x => x + 1, x => x x, x => 2 x], where x is initialized to 4.

Output: 65

Explanation:

Evaluating from right to left ...

Starting with x = 4.

2 * (4) = 8

(8) * (8) = 64

(64) + 1 = 65

Example 2:

functions = [x => 10 x, x => 10 x, x => 10 * x], x = 1

Output: 1000

Explanation:

Evaluating from right to left ...

10 * (1) = 10

10 * (10) = 100

10 * (100) = 1000

Example 3:

Input: functions = , x = 42

Output: 42

Explanation:

The composition of zero functions results in the identity function.

Constraints:

-1000 <= x <= 1000

0 <= functions.length <= 1000

all functions accept and return a single integer

JavaScript:

Example

Output: 10
Output: 130
Output: 25

Output:

Output

function composeFunctions(functions, x) {
    if (functions.length === 0) {
        return x;
    }
    let result = x;
    for (let i = functions.length - 1; i >= 0; i--) {
        result = functions[i](result);
    }
    return result;
}
// Example 1:
let functions1 = [x => x + 1, x => x * x, x => 2 * x];
let x1 = 4;
console.log("Output:", composeFunctions(functions1, x1)); // Output: 65
// Example 2:
let functions2 = [x => 10 * x, x => 10 * x, x => 10 * x];
let x2 = 1;
console.log("Output:", composeFunctions(functions2, x2)); // Output: 1000
// Example 3:
let functions3 = [];
let x3 = 42;
console.log("Output:", composeFunctions(functions3, x3)); // Output: 42

This code, composeFunctions function cycles over the array of functions in reverse order, forming the final this result by applying one function to the result of another function evaluation. Provided the array of functions is hollow, it returns the value x itself.

Problem 5:

Given an integer array arr and a mapping function fn, return a new array with a transformation applied to each element.

The returned array should be created such that returnedArray[i] = fn(arr[i], i).

Please solve it without the built-in Array.map method.

Example 1:

Input: arr = [1,2,3], fn = function plusone(n) { return n + 1; }

Output: [2,3,4]

Explanation:

const newArray = map(arr, plusone); // [2,3,4]

The function increases each value in the array by one.

Example 2:

Input: arr = [1,2,3], fn = function plusI(n, i) { return n + i; }

Output: [1,3,5]

Explanation: The function increases each value by the index it resides in.

Example 3:

Input: arr = [10,20,30], fn = function constant { return 42; }

Output: [42,42,42]

Explanation: The function always returns 42.

Constraints:

0 <= arr.length <= 1000

-109 <= arr[i] <= 109

fn returns a number

JavaScript:

Example

Output: 65
Output: 1000
Output: 42

Output:

Output

function map(arr, fn) {
    const mappedArr = [];
    for (let i = 0; i < arr.length; i++) {
        mappedArr.push(fn(arr[i], i));
    }
    return mappedArr;
}
// Example 1:
let arr1 = [1, 2, 3];
let fn1 = function plusone(n) { return n + 1; };
console.log("Output 1:", map(arr1, fn1)); // Output: [2, 3, 4]
// Example 2:
let arr2 = [1, 2, 3];
let fn2 = function plusI(n, i) { return n + i; };
console.log("Output 2:", map(arr2, fn2)); // Output: [1, 3, 5]
// Example 3:
let arr3 = [10, 20, 30];
let fn3 = function constant() { return 42; };
console.log("Output 3:", map(arr3, fn3)); // Output: [42, 42, 42]

This code specifies a map function that will create a new array called mappedArr and iterate over each element of the input array arr. The respective map function fn is applied to every element, and finally, the result is pushed to the mappedArr. At last, the element is mapped from the original array res, resulting in a new array called mappedArr containing the transformed elements.

Problem 6:

Given an array arr and a chunk size, return a chunked array. A chunked array contains the original elements in arr but consists of subarrays, each of length size. The length of the last subarray may be less than the size if arr.length is not evenly divisible by size.

You may assume the array is the output of JSON.parse. In other words, it is valid JSON.

Please solve it without using lodash's _.chunk function.

Example 1:

Input: arr = [1,2,3,4,5], size = 1

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

Explanation: The arr has been split into subarrays, each with 1 element.

Example 2:

Input: arr = [1,9,6,3,2], size = 3

Output: [[1,9,6],[3,2]]

Explanation: The arr has been split into subarrays with 3 elements. However, only two elements are left for the 2nd subarray.

Example 3:

Input: arr = [8,5,3,2,6], size = 6

Output: [[8,5,3,2,6]]

Explanation: Size is greater than arr.length; thus, all elements are in the first subarray.

Example 4:

Input: arr = , size = 1

Output:

Explanation: There are no elements to be chunked, so an empty array is returned.

Constraints:

arr is a valid JSON array

2 <= JSON.stringify(arr).length <= 105

1 <= size <= arr.length + 1

JavaScript:

Example

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

Output:

Output

function chunkArray(arr, size) {
    const  chunkedArray = [];
    let index = 0;  
    while (index < arr.length) {
        chunkedArray.push(arr.slice(index, index + size));
        index += size;
    }   
    return chunkedArray;
}
// Example 1:
let arr1 = [1, 2, 3, 4, 5];
let size1 = 1;
console.log("Output 1:", chunkArray(arr1, size1)); // Output: [[1],[2],[3],[4],[5]]
// Example 2:
let arr2 = [1, 9, 6, 3, 2];
let size2 = 3;
console.log("Output 2:", chunkArray(arr2, size2)); // Output: [[1,9,6],[3,2]]
// Example 3:
let arr3 = [8, 5, 3, 2, 6];
let size3 = 6;
console.log("Output 3:", chunkArray(arr3, size3)); // Output: [[8,5,3,2,6]]
// Example 4:
let arr4 = [];
let size4 = 1;
console.log("Output 4:", chunkArray(arr4, size4)); // Output: []

This code is an example that uses chunkArray as the function name, which takes an array arr and a chunk size as parameters. It iterates through the array and splits it into subarrays of the length requested, putting each subarray into a new array called chunkedArray. At last, it gives you the chunkedArray.

Problem 7:

Create a class ArrayWrapper that accepts an array of integers in its constructor. This class should have two features:

When two instances of this class are added together with the + operator, the resulting value is the sum of all the elements in both arrays.

When the String function is called on the instance, it returns a string separated by commas and surrounded by brackets, such as [1,2,3].

Example 1:

Input: nums = [[1,2],[3,4]], operation = "Add"

Output: 10

Explanation:

const obj1 = new ArrayWrapper([1,2]);

const obj2 = new ArrayWrapper([3,4]);

obj1 + obj2; // 10

Example 2:

Input: nums = [[23,98,42,70]], operation = "String"

Output: "[23,98,42,70]"

Explanation:

const obj = new ArrayWrapper([23,98,42,70]);

String(obj); // "[23,98,42,70]"

Example 3:

Input: nums = [,], operation = "Add"

Output: 0

Explanation:

const obj1 = new ArrayWrapper();

const obj2 = new ArrayWrapper();

obj1 + obj2; // 0

Constraints:

0 <= nums.length <= 1000

0 <= nums[i] <= 1000

Note: nums is the array passed to the constructor

JavaScript:

Example

Output 1: [[1],[2],[3],[4],[5]]
Output 2: [[1,9,6],[3,2]]
Output 3: [[8,5,3,2,6]]
Output 4: []

Output:

Output

class ArrayWrapper {
    constructor(nums) {
        this.nums = nums;
    }
    // Overriding the addition operator
    add(otherArray) {
        const sum = this.nums.reduce((acc, num) => acc + num, 0) +
                    otherArray.nums.reduce((acc, num) => acc + num, 0);
        return sum;
    }
    // Overriding the toString method
    toString() {
        return `[${this.nums.join(',')}]`;
    }
}
// Example 1:
let obj1 = new ArrayWrapper([1, 2]);
let obj2 = new ArrayWrapper([3, 4]);
console.log("Output 1:", obj1.add(obj2)); // Output: 10
// Example 2:
let obj3 = new ArrayWrapper([23, 98, 42, 70]);
console.log("Output 2:", String(obj3)); // Output: "[23,98,42,70]"
// Example 3:
let obj4 = new ArrayWrapper([]);
let obj5 = new ArrayWrapper([]);
console.log("Output 3:", obj4.add(obj5)); // Output: 0

In this code, the forward class has a constructor that accepts an array of integers as an argument. It also has two methods: add is the function that replaces the addition operator, and the result is the sum of all elements in both arrays, and toString is a function that overrides the toString method, and thus the function returns a string surrounded by brackets, and in the middle, there is a comma separator.

Problem 8:

Write a function createHelloWorld. It should return a new function that always returns "Hello World."

Example 1:

Input: args =

Output: "Hello World"

Explanation:

const f = createHelloWorld;

f; // "Hello World"

The function returned by createHelloWorld should always return "Hello World".

Example 2:

Input: args = [{},null,42]

Output: "Hello World"

Explanation:

const f = createHelloWorld;

f({}, null, 42); // "Hello World"

Any arguments could be passed to the function, but it should still always return "Hello World".

Constraints:

0 <= args.length <= 10

JavaScript:

Example

Output 1: 10
Output 2: [23,98,42,70]
Output 3: 0

Output:

Output

function createHelloWorld() {
    return function() {
        return "Hello World";
    };
}
// Example 1:
const f1 = createHelloWorld();
console.log("Output 1:", f1()); // Output: "Hello World"
// Example 2:
const f2 = createHelloWorld();
console.log("Output 2:", f2({}, null, 42)); // Output: "Hello World"

In this one, createHelloWorld returns a new function that, when called, always returns "Hello World" no matter what. We generate instances of this function defined as createHelloWorld and call them by providing different sets of arguments to show that the function returns "Hello World" irrespective of the passed arguments.

Problem 9:

Given a function fn, an array of arguments args, and a timeout t in milliseconds, return a cancel function cancelFn.

After a delay of cancelTimeMs, the returned cancel function cancelFn will be invoked.

setTimeout(cancelFn, cancelTimeMs)

Initially, the execution of the function fn should be delayed by t milliseconds.

If the function cancelFn is invoked before the delay of t milliseconds, it should cancel the delayed execution of fn. Otherwise, if cancelFn is not invoked within the specified delay t, fn should be executed with the provided arguments.

Example 1:

Input: fn = (x) => x * 5, args = [2], t = 20

Output: [{"time": 20, "returned": 10}]

Explanation:

const cancelTimeMs = 50;

const cancelFunction = cancellable((value) => value * 5, [2], 20);

setTimeout(cancelFn, cancelTimeMs);

The cancellation was set to take place following a postponement of cancelTimeMs (50ms), which transpired subsequent to the execution of fn(2) at 20ms.

Example 2:

Input: fn = (x) => x**2, args = [2], t = 100

Output:

Explanation:

const cancelTimeMs = 50;

const cancelFn = cancellable((x) => x ** 2, [2], 100);

setTimeout(cancelFn, cancelTimeMs);

The cancellation was planned to take place following a delay of cancelTimeMs (50ms). This delay transpired prior to the invocation of fn(2) at 100ms, leading to the conclusion that fn(2) was never executed.

Example 3:

fn = (x1, x2) => x1 * x2, args = [2, 4], t = 30

Output: [{"time": 30, "returned": 8}]

Explanation:

const cancelTimeMs = 100;

const cancelFunction = cancellable((value1, value2) => value1 * value2, [2, 4], 30);

setTimeout(cancelFn, cancelTimeMs);

The cancellation was planned to take place following a pause of cancelTimeMs (100ms), which transpired subsequent to the execution of fn(2,4) at the 30ms mark.

Constraints:

fn is a function

args is a valid JSON array

1 <= args.length <= 10

20 <= t <= 1000

10 <= cancelTimeMs <= 1000

JavaScript:

Example

function cancellable(fn, args, t) {
    let cancelled = false;
    // Create a promise that resolves after t milliseconds
    const delayPromise = new Promise(resolve => {
        setTimeout(() => {
            if (!cancelled) {
                const result = fn(...args);
                resolve({ time: t, returned: result });
            }
        }, t);
    });
    // Create a cancel function that sets cancelled to true
    const cancelFn = () => {
        cancelled = true;
    };
    // Return cancel function along with the promise
    return cancelFn;
}
// Example 1:
const cancelTimeMs1 = 50;
const cancelFn1 = cancellable((x) => x * 5, [2], 20);
setTimeout(cancelFn1, cancelTimeMs1);
// Example 2:
const cancelTimeMs2 = 50;
const cancelFn2 = cancellable((x) => x ** 2, [2], 100);
setTimeout(cancelFn2, cancelTimeMs2);
// Example 3:
const cancelTimeMs3 = 100;
const cancelFn3 = cancellable((x1, x2) => x1 * x2, [2, 4], 30);
setTimeout(cancelFn3, cancelTimeMs3);

Output:

Output

For Example 1: [{"time": 20, "returned": 10}]
For Example 2: []
For Example 3: [{"time": 30, "returned": 8}]

In the provided code, the cancellable function accepts the primary function fn along with its parameters and a delay time t. It creates a promise that will resolve after a duration of t milliseconds, at which point it will invoke the function fn with the supplied arguments, provided it has not been canceled. Conversely, if the cancellation function is called prior to the timeout, the value of the canceled flag is updated to true. Ultimately, the plot is enclosed with a conclusion that might still require cancellation.

Input Required

This code uses input(). Please provide values below: