JavaScript Coding Test Course, Checking the Intersection of Line Segments

Hello everyone! Today we will discuss one of the frequently encountered problems in JavaScript coding tests: ‘Determining if line segments intersect’. This problem is often asked in interviews and is very helpful in developing the ability to understand geometric concepts and implement them in code.

Problem Description

This problem is about determining whether two given line segments intersect. Each segment is defined by two points: segment A is represented by points A1(x1, y1) and A2(x2, y2), while segment B is represented by points B1(x3, y3) and B2(x4, y4). We need to determine whether these two segments intersect.

Input

  • A1: (x1, y1)
  • A2: (x2, y2)
  • B1: (x3, y3)
  • B2: (x4, y4)

Output

If they intersect, the output should be true; otherwise, it should return false.

Examples

Input Example

    A1: (1, 1), A2: (4, 4)
    B1: (1, 4), B2: (4, 1)
  

Output Example

    true
  

Approach to the Problem

To solve this problem, we need to utilize some geometric concepts and algorithms. We will introduce two methods to determine whether the line segments intersect. The first method uses the area of a polygon, while the second utilizes the concept of the cross product of vectors.

1. Determining intersection using the cross product

To determine if the segments intersect, we use the cross product of vectors. If the cross product of two direction vectors A and B is greater than 0, they are on one side; if less than 0, they are on the opposite side.

Equation of a line

    Let's define line segments A and B:
    A: [(x1, y1), (x2, y2)]
    B: [(x3, y3), (x4, y4)]
  

Cross product formula

The following cross product formula can be used for segments AB and AC:

    cross(A, B) = (A.x * B.y - A.y * B.x)
  

2. Determining intersection between a segment and a line

When given a segment, we can use another technique to determine if a specific line intersects the segment. This fundamentally involves reading the line defined by the endpoints of the segments and calculating the intersection.

Implementation Code

Now, let’s implement the actual code using the methods described above.


    function isIntersect(A1, A2, B1, B2) {
      const orientation = (p, q, r) => {
        const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
        if (val === 0) return 0; // collinear
        return (val > 0) ? 1 : 2; // clock or counterclockwise
      };
      
      const onSegment = (p, q, r) => {
        return (
          q[0] <= Math.max(p[0], r[0]) &&
          q[0] >= Math.min(p[0], r[0]) &&
          q[1] <= Math.max(p[1], r[1]) &&
          q[1] >= Math.min(p[1], r[1])
        );
      };
      
      const o1 = orientation(A1, A2, B1);
      const o2 = orientation(A1, A2, B2);
      const o3 = orientation(B1, B2, A1);
      const o4 = orientation(B1, B2, A2);
      
      if (o1 !== o2 && o3 !== o4) return true;
      if (o1 === 0 && onSegment(A1, B1, A2)) return true;
      if (o2 === 0 && onSegment(A1, B2, A2)) return true;
      if (o3 === 0 && onSegment(B1, A1, B2)) return true;
      if (o4 === 0 && onSegment(B1, A2, B2)) return true;

      return false;
    }

    // Example usage
    const A1 = [1, 1],
          A2 = [4, 4],
          B1 = [1, 4],
          B2 = [4, 1];

    console.log(isIntersect(A1, A2, B1, B2)); // true
  

Code Explanation

First, the orientation function determines the directionality of the three given points (p, q, r). This helps determine the intersection of segments A and B.

Next, the onSegment function checks if the point q lies on the segment pr. After confirming the intersection, further checks are performed for specific cases (when all three points coincide).

Time Complexity

The time complexity of this algorithm is O(1) since the intersection can be determined with just one comparison.

Conclusion

In this tutorial, we explored an algorithm to determine the intersection of line segments using JavaScript. I hope this helps enhance your understanding of geometric problems and coding skills. I wish you the best in your interview preparation, and I look forward to seeing you in the next lesson!

Javascript Coding Test Course, Interval Sum

Hello! In this tutorial, we will explore the “range sum” problem, which is frequently featured in JavaScript coding tests, in depth. The range sum problem involves efficiently calculating the sum of a specific range within a given sequence, and it can be solved using various optimization techniques. The range sum problems we will discuss can be particularly time-consuming when the size of the array is large, so it’s essential to design a more efficient algorithm.

Problem Introduction

Here is a problem related to range sums:

Problem Description

An array of integers arr and several pairs of integers (l, r) are given. Each pair represents the starting point l and endpoint r of a range. Write a program to calculate the sum of arr[l] + arr[l + 1] + ... + arr[r]. The length of the array and the number of pairs are as follows:

  • 1 ≤ arr.length ≤ 106
  • 1 ≤ l, rarr.length
  • 0 ≤ arr[i] ≤ 109

For example, if the array is arr = [1, 2, 3, 4, 5] and the pair (1, 3) is given, the range sum is arr[1] + arr[2] + arr[3] = 2 + 3 + 4 = 9.

Approach to the Problem

To solve this problem efficiently, simply using loops to calculate the sum for each range is not appropriate. The reason is that in the worst-case scenario, it would have a time complexity of O(N * M), which can lead to exponential time increases if the size of the data is large. Instead, we can use a more effective approach.

Preprocessing Technique: Prefix Sum Array

One way to solve the range sum problem is to create a Prefix Sum Array. Using a prefix sum array allows us to calculate the sum of a range in O(1) time. The definition of the prefix sum array is as follows:

prefix[i] = arr[0] + arr[1] + ... + arr[i-1]

Thus, the sum of the range (l, r) can be calculated as:

sum(l, r) = prefix[r + 1] - prefix[l]

This allows us to compute the range sum for each pair in O(1) time. The overall time complexity of the algorithm is O(N + M), where N is the size of the array and M is the number of pairs.

Implementation Steps

Now, let’s implement the JavaScript code that solves the problem using the prefix sum array.

Step 1: Create the Prefix Sum Array


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

Step 2: Calculate the Range Sum


function rangeSum(prefix, l, r) {
    return prefix[r + 1] - prefix[l];
}

Step 3: Implement the Main Function


function calculateRangeSums(arr, queries) {
    const prefix = createPrefixSum(arr);
    const results = [];
    for (let [l, r] of queries) {
        results.push(rangeSum(prefix, l - 1, r - 1)); // 1-based to 0-based
    }
    return results;
}

// Example usage
const arr = [1, 2, 3, 4, 5];
const queries = [[1, 3], [2, 5], [0, 2]];
const results = calculateRangeSums(arr, queries);
console.log(results); // [9, 14, 6]

Results Analysis

The above code is a program that efficiently calculates and outputs the range sum for each query based on the given array and queries. As a result, it can quickly compute range sums and does not suffer performance degradation depending on the size of the array or the number of queries.

Time Complexity

The time complexity of this algorithm is as follows:

  • Creating the prefix sum array: O(N)
  • Processing each query: O(1) (If you combine processing all M queries, it becomes O(M))

As a result, the overall time complexity is O(N + M), which is very efficient.

Conclusion

Now we have learned how to efficiently solve the range sum problem using a prefix sum array. Since range sum problems are frequently featured topics in coding tests, understanding and utilizing optimization techniques like this is important. Practice solving various types of problems!

Additional Practice Problems

Try practicing the following variant problems:

  • Problems that find the maximum value of the range instead of the sum
  • Problems that find the product of the range (note that division operations may need to be considered)
  • Consider how to handle different queries (e.g., range increment, decrement, etc.)

Based on the above content, I hope you solve various problems. Thank you!

JavaScript Coding Test Course, Queue Management

Problem Description

There is height information for a group of students. You need to specify one student among them
and arrange the line so that this student stands at the front.
In this case, students shorter than the specified student must stand behind, and
the order of students with the same height must remain unchanged.
Write an algorithm that satisfies these conditions for lining up the students.

Input Format

    An array containing the heights of students (e.g., [160, 170, 165, 180, 175])
    Height of the specified student (e.g., 170)
    

Output Format

    An array of the lined-up students' heights (e.g., [170, 160, 165, 180, 175])
    

Problem Solving Process

Step 1: Understand the Problem

The crux of the problem is to place the specified height student at the front of the given array, while
sorting the remaining students by height, maintaining their original order. This problem can primarily be solved using stable sorting.
The algorithm we will implement includes the following steps.

Step 2: Analyze a Simple Example

For example, if the input is [160, 170, 165, 180, 175] and 170,
the lined-up result should be [170, 160, 165, 180, 175]. The key point to note is
that when multiple students have the same height, their order must be preserved.

Step 3: Develop a Solution Strategy

The solution method is as follows.

  1. Find the student with the specified height in the given array and add that student as the first element of the result array.
  2. Add the remaining students to the result array while maintaining their original order, excluding students with the same height.
  3. Finally, return the modified array.

Step 4: Implement JavaScript Code

Based on the above strategy, I will write a JavaScript function. This function will take two parameters and
serve to move the specified height student to the front.

function lineUpStudents(students, targetHeight) {
    // Declare an array to store the result
    let result = [];

    // First, add the student corresponding to targetHeight
    const targetStudents = students.filter(height => height === targetHeight);
    result.push(...targetStudents);

    // Add the remaining students (maintaining original order)
    const otherStudents = students.filter(height => height !== targetHeight);
    result.push(...otherStudents);

    return result;
}
        

Step 5: Test and Validate the Code

I will run a few test cases to confirm that the function works correctly.

console.log(lineUpStudents([160, 170, 165, 180, 175], 170)); // [170, 160, 165, 180, 175]
console.log(lineUpStudents([160, 160, 165, 170, 180], 160)); // [160, 160, 165, 170, 180]
console.log(lineUpStudents([180, 170, 160, 150], 160)); // [160, 180, 170, 150]
        

Step 6: Complexity Analysis

The time complexity of this algorithm is O(n). This is because we iterate through the given array once.
The space complexity is also O(n) since a separate result array is created.

Conclusion

In this tutorial, we learned how to solve the problem of lining up students based on their height information
using JavaScript.
Maintaining a stable sort by height was the key to this problem.
Such problems are very important as they frequently appear in coding tests.
Practicing various variations of this problem can also be good preparation for developing algorithmic thinking.

JavaScript Coding Test Course, Calculating Interval Sum 2

Problem Description

The interval sum problem is one of the common types encountered in algorithm problems. In this lecture, we will address the second problem of calculating the interval sum. We will learn how to efficiently calculate the interval sum between two points in a given array.

Problem:
Given an integer array A and a query array queries, compute the interval sum from the l-th to the r-th index of array A for each query (l, r).

The array indexing starts from 0, the size of the array is N, and the number of queries is Q.

Input Format

1. The first line contains the size of the array A, N (1 ≤ N ≤ 106).

2. The second line contains the elements of array A. (A[i] is an integer, -109A[i] ≤ 109)

3. The third line contains the number of queries Q (1 ≤ Q ≤ 105).

4. The next Q lines contain each query (l, r). (0 ≤ lr < N)

Output Format

For each query, output the interval sum on a new line.

Example

    Input:
    5
    1 2 3 4 5
    3
    0 2
    1 4
    2 2

    Output:
    6
    14
    3
    

Solution Process

The first step to efficiently obtain the interval sum is to create a prefix sum array. The prefix sum array stores the sum of the elements up to each index in the array, allowing us to calculate the interval sum in O(1) time.

Creating the Prefix Sum Array

The prefix sum array prefix is defined as follows:

prefix[0] = A[0],

prefix[i] = prefix[i-1] + A[i] (for 1 ≤ i < N)

With this prefix sum array, the interval sum A[l] + ... + A[r] can be calculated as follows:

sum(l, r) = prefix[r] - prefix[l - 1] (provided l > 0)

In the case where l = 0, we handle it as sum(0, r) = prefix[r].

Implementation

Now, let’s write the code to create the prefix sum array and calculate the interval sum for each query. Below is the implementation in JavaScript:

    
    function rangeSum(A, queries) {
        const N = A.length;
        const prefix = new Array(N);
        prefix[0] = A[0];
        
        // Create the prefix sum array
        for (let i = 1; i < N; i++) {
            prefix[i] = prefix[i - 1] + A[i];
        }

        const result = [];
        // Process queries
        for (const [l, r] of queries) {
            if (l === 0) {
                result.push(prefix[r]);
            } else {
                result.push(prefix[r] - prefix[l - 1]);
            }
        }

        return result;
    }

    // Example input
    const A = [1, 2, 3, 4, 5];
    const queries = [[0, 2], [1, 4], [2, 2]];
    console.log(rangeSum(A, queries)); // [6, 14, 3]
    
    

Time Complexity Analysis

Creating the prefix sum array takes O(N) time, and each query can be processed in O(1). Therefore, the overall time complexity of the algorithm is O(N + Q). This is an efficient solution that satisfies the input conditions of the given problem.

Conclusion

In this lecture, we learned how to calculate the interval sum. We learned to use the prefix sum array to compute the interval sum in O(1) time. This approach can also be applied to solving other similar problems, which will be very helpful in studying algorithms.

JavaScript Coding Test Course, Fast Forward with Time Machine

Coding tests are becoming mandatory for more and more companies, and JavaScript is one of the most popular languages in web development.
In this course, we will solve commonly occurring algorithm problems found in coding tests using JavaScript.
Today’s topic is the problem ‘Fast Travel with a Time Machine’.

Problem Description

You are a scientist who can operate a time machine. The time machine can move to a specific time, and
given two integers a and b, you need to calculate the minimum time (number of moves) it takes to move from a to b.
The time machine follows these rules:

  • You can add 1 or subtract 1 from your current position.
  • You can double your current position.

Write a function that calculates the minimum number of moves required to travel from a to b for given a and b.

Input Format

– Two integers a (0 ≤ a ≤ 105), b (0 ≤ b ≤ 105) are given.

Output Format

– Output the minimum number of moves required to travel from a to b as an integer.

Examples

        Input: a = 2, b = 9
        Output: 4
    
        Input: a = 5, b = 22
        Output: 7
    

Approach to Solve the Problem

To solve this problem, we will use BFS (Breadth-First Search). BFS is an algorithm suitable for finding the shortest path,
exploring all possible states from the given state to find the shortest move sequence to reach the target state.
In this case, each state represents a time the time machine could occupy.

Step 1: Prepare to Use BFS Algorithm

To implement BFS, we will use a queue. First, we add the starting position a to the queue.
Then, we will repeat adding all possible moves to the queue until we reach the target position b.
The possible moves from each position are as follows:

  • Add 1 to the current position
  • Subtract 1 from the current position
  • Double the current position

We will keep track of the number of moves taken for each move until we reach the target position, and output the count when we reach the target.

Step 2: Implement the Code


function minimumMoves(a, b) {
    if (a >= b) return a - b; // If a is greater than or equal to b, determine moves by simply subtracting the difference
    const queue = [[a, 0]]; // [current position, number of moves]
    const visited = new Set(); // Record visited positions
    visited.add(a); // Mark the starting position as visited

    while (queue.length > 0) {
        const [current, moves] = queue.shift(); 

        // Possible moves
        const nextMoves = [current - 1, current + 1, current * 2]; 

        for (let next of nextMoves) {
            if (next === b) return moves + 1; // Return move count when the target position is reached
            if (next < 0 || next > 100000 || visited.has(next)) continue; // Only for valid range and unvisited positions
            visited.add(next); // Mark the next position as visited
            queue.push([next, moves + 1]); // Add the next position and move count to the queue
        }
    }
}
    

Step 3: Analyze Algorithm Complexity

The time complexity of the algorithm is O(n).
In the worst case, we need to explore all possible positions, which corresponds to O(n),
and the space complexity is also O(n). This complexity arises from the space needed for the queue and visited records.

Step 4: Optimization Possibilities

This algorithm is already based on BFS, which explores the shortest path
and does not require additional optimization. However, depending on the situation,
DFS (Depth-First Search) could also be applied, but BFS is more effective for this problem.

Step 5: Conclusion

Through the ‘Fast Travel with a Time Machine’ problem, we have briefly understood the principle of BFS and learned how to solve a problem using JavaScript.
In this way, various problems can be solved, and it is crucial to master basic algorithms to achieve good results in coding tests.

Additional Resources

– To further study the BFS algorithm and practice various problem-solving, we recommend the following resources.