Javascript Coding Test Course, Selection Sort

1. Introduction

In coding tests and algorithm problem-solving, sorting algorithms are an essential topic to learn. Among various methods of sorting arrays, Selection Sort is considered a good algorithm to learn in the initial stages due to its simple implementation and intuitive process. In this tutorial, we will explore the concept and principles of Selection Sort, as well as how to implement it in JavaScript in detail.

2. What is Selection Sort?

Selection Sort is a simple algorithm for sorting arrays that operates by repeatedly finding the smallest (or largest) value in the given array and swapping it with the current position. This algorithm works by dividing the process into sorted and unsorted sections with each iteration.

2.1. How It Works

Selection Sort operates as follows:

  • Starting from the first element of the array, find the smallest element among the remaining elements and swap it with the first element.
  • Repeat the same process starting from the second element, swapping the second element with the smallest element among the second and subsequent elements.
  • Continue this process until the last element of the array.

2.2. Time Complexity of Selection Sort

The time complexity of Selection Sort is O(n²) in both the worst and average cases. This means that performance can degrade sharply depending on the size of the array. Therefore, Selection Sort is most suitable for use with small datasets.

3. Implementing Selection Sort

In this section, we will implement Selection Sort in JavaScript.

3.1. Basic Implementation

The code below is a basic JavaScript function implementing Selection Sort:


function selectionSort(arr) {
    const n = arr.length;

    for (let i = 0; i < n - 1; i++) {
        // Initialize the current index (i) as a candidate
        let minIndex = i;

        // Scan the remaining array to find the index of the smallest element
        for (let j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j; // Update minIndex if a smaller value is found
            }
        }

        // Swap the candidate minimum value with the current position (i)
        // Swap only if the current position is not the minimum
        if (minIndex !== i) {
            [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
        }
    }

    return arr;
}

// Example usage
const unsortedArray = [64, 25, 12, 22, 11];
const sortedArray = selectionSort(unsortedArray);
console.log(sortedArray); // [11, 12, 22, 25, 64]
    

3.2. Code Explanation

The code above is a function that uses the Selection Sort algorithm. Let’s analyze the function step by step:

  1. const n = arr.length;: This calculates the length of the array.
  2. for (let i = 0; i < n - 1; i++): The first loop iterates through each element of the array.
  3. let minIndex = i;: This initializes the index of the current smallest value.
  4. for (let j = i + 1; j < n; j++): The second loop iterates through the remaining array to find the index of the smallest element.
  5. if (arr[j] < arr[minIndex]) { minIndex = j; }: If the current element of the array is less than the current minimum, it updates the index of the minimum value.
  6. if (minIndex !== i) { [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]; }: Finally, if the minimum value is not at the current index, it performs the swap.

4. Optimized Selection Sort

The basic Selection Sort can be optimized. By reducing unnecessary swaps, we can improve performance slightly. For instance, adding a check to see if sorting is already complete and terminating the loop when no further swaps are needed can enhance performance. The code below shows the optimized Selection Sort:


function optimizedSelectionSort(arr) {
    const n = arr.length;
    let isSorted = true;

    for (let i = 0; i < n - 1; i++) {
        let minIndex = i;

        for (let j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
                isSorted = false; // Remember that a swap will occur
            }
        }

        if (minIndex !== i) {
            [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
        }

        // Exit the loop if the array is already sorted
        if (isSorted) break;
    }

    return arr;
}

// Example usage
const unsortedArray = [64, 25, 12, 22, 11];
const sortedArray = optimizedSelectionSort(unsortedArray);
console.log(sortedArray); // [11, 12, 22, 25, 64]
    

4.1. Optimization Explanation

The optimized Selection Sort function uses let isSorted = true; in the initialization stage to track whether the array is sorted. After each iteration, if an actual swap occurs in the array, this flag is set to false. If no swap occurs in the current iteration, it indicates that the array is fully sorted, and the loop is exited.

5. Practical Example

Let me show you an example of sorting actual data using Selection Sort, such as sorting student grade data. This can help compare students’ scores or provide necessary information.


const students = [
    { name: "Emily", score: 85 },
    { name: "David", score: 92 },
    { name: "Sophie", score: 76 },
    { name: "John", score: 89 },
    { name: "Max", score: 90 },
];

function selectionSortByScore(arr) {
    const n = arr.length;
    for (let i = 0; i < n - 1; i++) {
        let minIndex = i;
        for (let j = i + 1; j < n; j++) {
            if (arr[j].score < arr[minIndex].score) {
                minIndex = j;
            }
        }
        if (minIndex !== i) {
            [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
        }
    }
    return arr;
}

const sortedStudents = selectionSortByScore(students);
console.log(sortedStudents);
    

5.1. Practical Example Explanation

The code above demonstrates how to sort an array based on students’ scores. Each student is represented as an object with a name and score, and the selectionSortByScore function sorts them in ascending order of scores and provides the output.

6. Conclusion

Selection Sort is a simple implementation that is very useful for beginners to understand the basic principles of algorithms. However, due to its O(n²) time complexity, its efficiency decreases with large datasets, and it is recommended to use better algorithms such as Quick Sort or Merge Sort in real production environments. Nevertheless, building a foundation in algorithms through Selection Sort is an important learning process. I hope this knowledge will be of great help in preparing for coding tests.

JavaScript Coding Test Course, Calculating the Amount of Water

In this lecture, we will address the problem of ‘Calculating the Amount of Water’, which is commonly featured in coding tests, using JavaScript. This problem will provide a great opportunity to learn various algorithm design patterns and utilize arrays effectively.

Problem Definition

The problem is to calculate the amount of water that can be collected when it rains, given an array of heights of bars. The heights of the bars are provided as each element of the array.

For example, if the array is [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1], the amount of water that can be collected is 6. Visually representing how water is stored between each bar in this example is as follows:

Water Storage Visualization

Approaches to Solve the Problem

There are various methods that can be used to solve this problem. The two most commonly used approaches are as follows.

  1. Two Pointers Method

    This method progresses by moving two pointers inwards from both ends. Each pointer tracks the height from the left and right, allowing calculation of positions where water can accumulate.

  2. Dynamic Programming

    This method involves finding the tallest bar from both left and right at each position, using the shorter of the two to calculate the amount of water. However, this method has the drawback of using a lot of additional memory.

Solving the Problem with JavaScript

First, let’s implement the code using the two pointers method. We will create an algorithm that starts from both ends of the array and moves towards the center to calculate the amount of water.

Code Example


function trap(height) {
    if (height.length === 0) return 0;

    let left = 0;
    let right = height.length - 1;
    let leftMax = 0;
    let rightMax = 0;
    let waterTrapped = 0;

    while (left < right) {
        if (height[left] < height[right]) {
            if (height[left] >= leftMax) {
                leftMax = height[left];
            } else {
                waterTrapped += leftMax - height[left];
            }
            left++;
        } else {
            if (height[right] >= rightMax) {
                rightMax = height[right];
            } else {
                waterTrapped += rightMax - height[right];
            }
            right--;
        }
    }

    return waterTrapped;
}

            

The above function takes the height array as input and calculates the amount of water that can be collected after it rains.

Code Explanation

Let’s take a step-by-step look at the above code:

  1. Initialization: left is initialized to 0, and right is initialized to the last index of the array (length – 1). leftMax and rightMax store the maximum heights from their respective directions. waterTrapped indicates the final amount of water collected.
  2. Loop Execution: The loop runs until left is less than right. In each iteration, the heights from the left and right are compared to calculate the amount of water from the lower side.
  3. Water Calculation: If the height from the left is lower, it compares the maximum height on the left with the current height to calculate the amount of water that can be stored. Similarly, the same operation is performed on the right side.
  4. Return Result: After all loops are completed, it returns the waterTrapped variable to output the final result.

Code Testing

Now, let’s test the algorithm we’ve written. We can verify the performance of the function through several examples like the following:


console.log(trap([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])); // 6
console.log(trap([4, 2, 0, 3, 2, 5])); // 9
console.log(trap([])); // 0
console.log(trap([1, 0, 1])); // 1

            

Each output should match the predicted amount of water. The following results will be displayed:

  • trap([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]) – 6
  • trap([4, 2, 0, 3, 2, 5]) – 9
  • trap([]) – 0
  • trap([1, 0, 1]) – 1

Performance Analysis

The algorithm above has a time complexity of O(n) and a space complexity of O(1). This means that the execution time and space required are proportional to the size of the input array. Therefore, it works efficiently even with large amounts of data.

If dynamic programming is used, it requires an additional array to store heights, resulting in a space complexity of O(n). However, the time complexity remains O(n) as well.

Conclusion

In this lecture, we discussed the ‘Calculating the Amount of Water’ problem and introduced how to solve it using JavaScript. By using the two pointers algorithm, we effectively tackled the problem and also conducted code implementation and performance analysis.

This problem includes important concepts that can be applied to other algorithm problems, so practicing other similar problems can further enhance your algorithm skills.

This concludes the JavaScript coding test lecture. I hope it helps you improve your coding skills!

Javascript Coding Test Course, Let’s Try DDR

Many companies evaluate the algorithm and problem-solving abilities of applicants through coding tests. In this article, we will solve an algorithm problem that implements the DDR (Dance Dance Revolution) game using JavaScript.

This article will detail the understanding of the problem, solution methods, code writing, and testing process.

Problem Description

Here is a simple version of the DDR game. The game proceeds in the following format.

The user must press the corresponding keys based on the four arrows shown below:

  • ↑ (Up)
  • ↓ (Down)
  • ← (Left)
  • → (Right)

The goal of the game is to score points by accurately pressing the keys in the order of the given arrow inputs. If a wrong arrow is pressed, the user loses points.

You need to write a function that receives user input and calculates the score when given n arrows. This function adds 1 point for each correct input matching the answer sequence and subtracts 1 point for each incorrect input.

Input Format

        - Arrow array: ["↑", "↓", "←", "→"]
        - User input array: ["↑", "↑", "←", "→", "↓"]
        

Output Format

Returns the user’s final score.

Problem Solving Process

To solve this problem, let’s first design the algorithm. The steps to solve the problem are as follows.

  1. Declare the arrow array and user input array.
  2. Initialize a variable to maintain the score.
  3. Iterate over user inputs and compare each input with the correct answers.
  4. If the input is correct, increase the score by 1; if incorrect, decrease it by 1.
  5. After checking all inputs, return the final score.

Now that the algorithm is clear, let’s write the code.

Code Implementation


function calculateScore(correctArrows, userArrows) {
    let score = 0;

    for (let i = 0; i < userArrows.length; i++) {
        if (userArrows[i] === correctArrows[i]) {
            score += 1; // Correct
        } else {
            score -= 1; // Incorrect
        }
    }

    return score; // Return final score
}

// Example usage
const correctArrows = ["↑", "↓", "←", "→"];
const userArrows = ["↑", "↑", "←", "→", "↓"];

const finalScore = calculateScore(correctArrows, userArrows);
console.log("Final score is:", finalScore);
        

Code Explanation

Let’s explain the code step by step.

1. Function Definition

The function calculateScore takes the arrow array and user input array as parameters. It initializes the score variable to 0 for score calculation.

2. Checking with Loop

Using a for loop, we iterate through the user input array. We check if each user’s input matches the correct arrows.

If they match, we add 1 point; if they do not match, we subtract 1 point.

3. Return Final Score

After checking all user inputs, we return the score value. This value is the final score.

Code Testing

To verify that the code works correctly, let’s create some test cases.

Test Case 1


const correct1 = ["↑", "↓", "←", "→"];
const user1 = ["↑", "↓", "←", "→"];

console.log("Test Case 1 - Score:", calculateScore(correct1, user1)); // 4
        

Test Case 2


const correct2 = ["↑", "↓", "←", "→"];
const user2 = ["↑", "↑", "←", "→", "↓"];

console.log("Test Case 2 - Score:", calculateScore(correct2, user2)); // 2
        

Test Case 3


const correct3 = ["↑", "↓", "←", "→"];
const user3 = ["→", "→", "→", "→"];

console.log("Test Case 3 - Score:", calculateScore(correct3, user3)); // -4
        

Conclusion

In this article, we solved a basic algorithm problem of the DDR game using JavaScript. We were able to solidify the basics of JavaScript through basic problem-solving methods and code writing.

This simple algorithm problem is one of the common types of problems that appear in interviews. Therefore, it’s beneficial to solve many similar problems and develop your own coding style. Thank you!

JavaScript Coding Test Course, Finding the Sum of Intervals 3

October 5, 2023

1. Problem Introduction

The Range Sum Query 3 problem is a type of problem that you often encounter in algorithm problem-solving processes, especially demonstrating efficiency when calculating sums of large datasets.
This problem deals with methods to quickly calculate the sum of a specific interval through queries.
Computing the range sum algorithmically is particularly useful for database-related problems.
Today, we will analyze various techniques to solve this problem and try to solve it using JavaScript.

2. Problem Description

Given an array A with length N, when a positive integer query M is provided,
each query consists of two integers i and j, and we need to find the value of
A[i] + A[i+1] + ... + A[j]. There can be up to 100,000 queries, and each number in A can be up to 1,000,000.
In other words, we need to efficiently calculate the sums of ranges based on the given array A and the queries.

3. Problem Solving Strategy

To solve the range sum problem, we will use two main methods.
– First, the basic method which uses a double loop to calculate the sum for each query.
– Second, a method that pre-computes the range sums and quickly derives results during the queries.
In particular, the second method allows us to obtain query results in O(1) time through O(N) preprocessing.
Thus, this will help us solve the problem more efficiently.

4. Basic Method (O(N) x M)

This method is very intuitive, but its time complexity is O(N * M).
The implementation of this approach is as follows.


function simpleRangeSum(A, queries) {
    const results = [];
    for (let [i, j] of queries) {
        let sum = 0;
        for (let k = i; k <= j; k++) {
            sum += A[k];
        }
        results.push(sum);
    }
    return results;
}
        

This code calculates the sum at the respective index for each query by iterating through it. However, under the constraints of the problem,
this method is inefficient. Therefore, we need to move on to a more efficient approach.

5. Efficient Method (O(N) + O(1) per Query)

In exploring the efficient method, we start by creating an array to store the range sums of the original array.
First, the process of creating the range sum array is needed. Once the range sum array is created,
the result of each query can be obtained simply by taking the difference of two cumulative sums.


function prefixSum(A) {
    const prefix = new Array(A.length + 1).fill(0);
    for (let i = 0; i < A.length; i++) {
        prefix[i + 1] = prefix[i] + A[i];
    }
    return prefix;
}

function rangeSum(A, queries) {
    const prefix = prefixSum(A);
    const results = [];
    for (let [i, j] of queries) {
        results.push(prefix[j + 1] - prefix[i]);
    }
    return results;
}
        

In the above implementation, the prefixSum function calculates the cumulative sums for the entire dataset and stores them in the prefix array.
After that, each query can derive the range sum in O(1) time. This method is
very efficient as it can process queries in O(N) + O(1).

6. Code Explanation

Analyzing the code above, we first create an empty array with one more than the length of the array in the prefixSum function,
and compute the cumulative sums for each index of this array. Through this cumulative sum array,
the rangeSum function quickly calculates the range sum by taking the starting index i and ending index j from the given queries.

Now, when considering the large number of queries, we need to be mindful of the time complexity,
as the solution above is very efficient in this regard.
The unnecessary loops during the processing of each query were key,
and deriving the results through this process improved performance.

7. Example Test

Let’s test the code above with an example.
The array A = [1, 2, 3, 4, 5] and the queries are
[[0, 2], [1, 3], [2, 4]].


const A = [1, 2, 3, 4, 5];
const queries = [[0, 2], [1, 3], [2, 4]];
const results = rangeSum(A, queries);
console.log(results); // [6, 9, 12]
        

The results of the above test correctly yield the cumulative sums for each query. By testing, we can confirm that our code is functioning accurately,
which is an essential process for ensuring correctness.

8. Conclusion

The Range Sum Query 3 problem is an excellent example that demonstrates a variety of algorithm problem-solving skills.
Solving the range sum problem through preprocessing is commonly used in everyday data processing tasks.
Based on what we learned today, I hope you have developed the ability to solve similar problems and gained insight on how to structure algorithms when faced with problems.
I encourage you to continue building your problem-solving experience through JavaScript.

JavaScript Coding Test Course, Sorting Numbers 2

JavaScript Coding Test Course – Sorting Numbers 2

In this course, we will deeply analyze the algorithm problem called ‘Sorting Numbers 2’ and explain the step-by-step process to solve it. We will look into how to solve the problem using JavaScript along with its definition.

Problem Definition

The problem is as follows. Given a set of numbers, write a program to sort these numbers in ascending order. Please note that the number of inputs can be up to 10,000. Below, we will provide the exact input and output formats along with examples.

Input

The first line contains the number of integers N (1 ≤ N ≤ 10,000). Then, N lines follow, each containing a single integer. This integer will be between -1,000,000 and 1,000,000, inclusive.

Output

The integers received as input must be printed in ascending order, one per line.

Example Input

5
5
3
2
1
4

Example Output

1
2
3
4
5

Problem Approach

The key to this problem is sorting the N given integers. There are many methods available, but it is important to choose an efficient sorting algorithm. In JavaScript, you can typically use the Array.sort() method.

The Array.sort() method performs string sorting by default, so a comparison function is necessary to sort actual numbers. Care is needed when using the built-in sort() method in JavaScript, especially considering time complexity when processing a large amount of numbers.

Solution Method

Let’s step through the process of solving the problem.

  1. Prepare the input data.

    First, you need to declare variables necessary for reading the input data presented by the problem and store the data in an array. At this time, we will use JavaScript’s Array to store the numbers dynamically.

  2. Sort the input numbers.

    Use the Array.sort() method to sort the input array. Define a comparison function to allow for number comparison.

  3. Output the sorted numbers.

    Use a function or method to print the values of the sorted array, outputting one number per line.

JavaScript Code Implementation

Based on the solution methods mentioned above, the JavaScript code can be implemented as follows:


function sortNumbers(input) {
  const N = parseInt(input[0]); // The first line is the number of integers
  const numbers = input.slice(1, N + 1).map(Number); // Convert the remaining N numbers to integers and store in an array

  numbers.sort((a, b) => a - b); // Sort in ascending order

  return numbers.join('\\n'); // Return sorted numbers to print one per line
}

// Example input
const input = [
  '5',
  '5',
  '3',
  '2',
  '1',
  '4'
];

console.log(sortNumbers(input)); // Output the result

Code Explanation

Let us look more closely at each part of the code:

  • Input Handling: parseInt(input[0]) is used to retrieve the number of integers from the first line. input.slice(1, N + 1) selects the numbers excluding the first line, and map(Number) converts the string array to a number array.
  • Sorting: numbers.sort((a, b) => a - b) compares two numbers and sorts them in ascending order. It returns a - b so that if the first argument is less than the second, it returns a negative number, if greater, a positive number, and if equal, 0.
  • Output Handling: join('\\n') connects each element of the array with a newline character to create a string that can be printed.

Test Cases

You can consider several test cases using the defined code:

Test Case 1

Input:
5
5
3
2
1
4

Output:
1
2
3
4
5

Test Case 2

Input:
4
10
30
20
40

Output:
10
20
30
40

Test Case 3

Input:
3
-1
-5
2

Output:
-5
-1
2

Final Words

In this course, we have learned how to solve the algorithm problem ‘Sorting Numbers 2’. Various sorting algorithms can be utilized, but it is essential to select an appropriate algorithm based on the scope and requirements of the problem. Furthermore, leveraging JavaScript’s powerful features allows for efficient implementation.

We will continue to share methods for solving various algorithm problems, so please stay tuned. Enhance your skills in well-organized problem-solving to open the door to employment!