kotlin coding test course, bridge building

This article will discuss the “Bridge Construction” problem, which is frequently encountered in coding tests using Kotlin. First, we will introduce the problem, explain the algorithm, and then implement the code to find the optimal solution.

Problem Description

The problem is as follows: We want to calculate the number of ways to move an object falling from the ceiling while maintaining the height of a bridge on which multiple laser beams are horizontally placed. The approach is to find similar forms of movement possibilities and implement a rotating table that maintains the height of the bridge.

Input

  • Integer N: Total length of the bridge (1 <= N <= 1000)
  • Integer M: Number of obstacles on the bridge (0 <= M <= 100)
  • For M lines, the position and height information of obstacles are given. Each line consists of two integers X and H, where X is the position of the obstacle (1 <= X <= N), and H is the height of the obstacle at that position.

Output

Returns the number of ways an object can travel on the bridge.

Problem Approach

To solve this problem, we first need a data structure to store the state of the bridge. It should be able to store whether an obstacle exists at each position of the bridge and its height. Typically, such problems can be solved using dynamic programming.

Step 1: Designing Data Structure

We can use an array to store the heights of the bridge. We will declare an array of length N for the bridge and set the obstacle heights as initial values at each position.

Step 2: Defining Movement Conditions

We can approach this in the form of dynamic programming by judging the conditions under which an object can move. The object must maintain a constant height based on the observed obstacle heights.

Code Implementation

Now, let’s implement the actual code based on these processes. Below is the code written in Kotlin:


fun main() {
    val n = readLine()!!.toInt()
    val m = readLine()!!.toInt()
    val heights = IntArray(n + 1)

    for (i in 0 until m) {
        val (x, h) = readLine()!!.split(" ").map { it.toInt() }
        heights[x] = h
    }

    var totalWays = 1
    for (i in 1..n) {
        if (heights[i] > 0) {
            totalWays *= (heights[i] + 1) // Includes obstacles
        }
    }

    println(totalWays)
}
    

Code Explanation

The above code takes input from the user for the length of the bridge N, the number of obstacles M, and the position and height of each obstacle, storing them in an array. It then calculates the possible number of ways based on the heights of the obstacles by iterating over each position. For each existing obstacle, it multiplies the number of possible ways by the corresponding height to derive the final result.

Results and Analysis

After executing the code above, we obtain all possible ways the object can progress on the bridge. This problem can be solved simply using an array, and the time complexity is optimized to O(N + M).

Conclusion

In this article, we covered the “Bridge Construction” problem using Kotlin. Solving algorithmic problems greatly enhances practical problem-solving skills. I encourage you to improve your skills by tackling various problems!

Additional Practice Problems

Furthermore, try the following additional practice problems by modifying this problem:

  • A problem that calculates the number of ways that satisfy specific height conditions within a certain range instead of the height of obstacles
  • Implement an algorithm to find the optimal path by increasing or decreasing the length of the bridge

Through various approaches to problem-solving, I hope you further develop your skills!

kotlin coding test course, calculating the area of a polygon

In today’s lecture, we will explain the problem of calculating the area of a polygon. This problem is one of the frequently asked questions in coding tests, and we will learn how to implement an algorithm to calculate the area when given various shapes of polygons.

Problem Description

Write an algorithm to calculate the area of a polygon formed by given multiple points. The points are represented as coordinates on a 2D plane, and it is assumed that the points are given in either clockwise or counterclockwise order.

Example Input

    4
    0 0
    4 0
    4 3
    0 4
    

Example Output

    14.0
    

Here, the area is determined by the coordinates of the vertices that make up the polygon. In the above example, the given points are the vertices of a polygon consisting of (0,0), (4,0), (4,3), and (0,4). In this case, the area of the polygon is 14.0.

Algorithm Explanation

There are various methods to calculate the area of a polygon, but one commonly used method is the ‘Shoelace Formula’. Using this formula, the area can be calculated with a time complexity of O(n).

Shoelace Formula

The Shoelace Formula is expressed as follows:

A = 0.5 * | ∑(xiyi+1 - xi+1yi) |

Here, xi and yi are the x and y coordinates of the i-th vertex of the polygon. When the polygon has n vertices, i increments from 0 to n-1. The last vertex closes back to the first vertex (i.e., when increasing i+1, it wraps around to n).

Problem Solving Process

1. Processing Input Data

First, we need to read the number of vertices and the vertex coordinates of the polygon provided as input. In Kotlin, we can use a list to store the coordinates.

kotlin coding test course, sorting digits in descending order

In coding tests, a deep understanding of algorithms and data structures is required. In this course, we will explore the features and useful functions of Kotlin while solving an algorithm problem called “Sorting Digits in Descending Order”.

Problem Description

Reconstruct the number by sorting the digits of a given integer N in descending order. Return the number after sorting the digits. The integer N is between 0 and 231-1.

For example:

  • Input: 118372 → Output: 873211
  • Input: 2143 → Output: 4321
  • Input: 0 → Output: 0

Solution Process

Step 1: Understanding the Problem

The first step in solving the problem is to accurately understand the given problem. The input is in the form of an integer, and what we need to do is separate this integer into its digits and sort them in descending order. After sorting the digits, we need to combine them back into an integer and return it.

Step 2: Extracting Each Digit

We can convert the integer into a string to easily access each digit. Each character in the string represents a digit of the original integer, and we can use this to extract the digits.

Step 3: Sorting the Digits

To sort the digits, we can use Kotlin’s built-in function. We can use the sortedDescending() function to sort the digits in descending order.

Step 4: Combining the Sorted Digits

We need to convert the sorted digits back into an integer as our final result. We concatenate each digit to form a single string and then convert it back into an integer to return it.

Step 5: Implementing the Final Code


fun solution(N: Int): Int {
    // Convert integer N to string
    val strN = N.toString()
    
    // Sort the digits in descending order
    val sortedDigits = strN.toCharArray().sortedDescending()
    
    // Combine the sorted digits back into a single string
    val resultStr = sortedDigits.joinToString("")
    
    // Convert string to integer and return
    return resultStr.toInt()
}
            

Example Test

To test the solution we have written, we will execute each test case.


fun main() {
    println(solution(118372)) // 873211
    println(solution(2143))   // 4321
    println(solution(0))      // 0
}
            

When the above code is executed, each integer is expected to be printed in descending order as intended.

Time Complexity and Space Complexity

The time complexity of the algorithm used here is O(d log d), where d is the number of digits. There is a logarithmic time complexity due to the sorting of the digits. The space complexity is O(d), as an array is used to store the digits.

Conclusion

Through this course, we learned how to leverage Kotlin’s powerful features and concise syntax for solving algorithm problems. The digit sorting problem serves as a good starting point that can be extended to other algorithm problems. It is important to practice solving more problems to familiarize oneself with various algorithms and data structures.

I hope this helps you in preparing for coding tests. Stay tuned for the next course!

Kotlin coding test course, breadth-first search

1. Problem Description

This problem is to find the shortest path between two nodes in a given graph. The graph is presented in the form of an adjacency list, providing the number of nodes and the information of nodes connected to each node. Your goal is to output the shortest path from a specific start node to a specific target node.

Problem


Input:
- First line: Number of vertices N (1 ≤ N ≤ 1000)
- Second line: Number of edges M (0 ≤ M ≤ 10000)
- Next M lines: Edge information (A B) - A and B represent the two connected nodes

- The last line gives the start node S and the target node T.

Output:
- Print the list of nodes in the path from S to T. If there is no path, print "PATH NOT FOUND!".

2. Problem Approach

This problem can be solved using a typical BFS algorithm. BFS is a breadth-first search method that explores nodes close to the start node first. This allows for finding the shortest path. The main characteristics of the BFS algorithm are as follows:

  • It explores all nodes at the same depth, guaranteeing the shortest path.
  • Implemented using a queue, it theoretically has a time complexity of O(V + E), where V is the number of nodes and E is the number of edges.

BFS Algorithm Steps

  • Initialization: Mark the start node as visited and initialize distances. Insert the start node into the queue.
  • Exploration Process: Repeat while the queue is not empty. Remove a node from the queue and add unvisited adjacent nodes to the queue.
  • Path Tracking: Record the parent node of each node to allow for path tracking later.

3. Kotlin Code Implementation

Now, let’s implement BFS in Kotlin according to the approach above. Refer to the code below to see how to solve the given problem.


import java.util.*

data class Edge(val to: Int, val weight: Int)

fun bfs(graph: List>, start: Int, target: Int): List? {
    val queue: Queue = LinkedList()
    val visited = BooleanArray(graph.size)
    val parent = IntArray(graph.size) { -1 }  // Track parent nodes
    queue.add(start)
    visited[start] = true

    while (queue.isNotEmpty()) {
        val current = queue.poll()

        // Trace back the path if the target node is found
        if (current == target) {
            return tracePath(parent, start, target)
        }

        for (edge in graph[current]) {
            if (!visited[edge.to]) {
                visited[edge.to] = true
                parent[edge.to] = current // Set parent node
                queue.add(edge.to)
            }
        }
    }
    return null // No path found
}

fun tracePath(parent: IntArray, start: Int, target: Int): List {
    val path = mutableListOf()
    var current = target

    while (current != start) {
        path.add(current)
        current = parent[current]
    }
    path.add(start)
    path.reverse()  // Reverse the list as it was added in reverse order
    return path
}

fun main() {
    val scanner = Scanner(System.`in`)
    val n = scanner.nextInt()
    val m = scanner.nextInt()
    val graph = List(n) { mutableListOf() }

    // Create the graph
    for (i in 0 until m) {
        val a = scanner.nextInt() - 1
        val b = scanner.nextInt() - 1
        graph[a].add(Edge(b, 1)) // Undirected graph, so add both ways
        graph[b].add(Edge(a, 1))
    }

    val start = scanner.nextInt() - 1
    val target = scanner.nextInt() - 1
    val result = bfs(graph, start, target)

    if (result != null) {
        println(result.joinToString(" "))
    } else {
        println("PATH NOT FOUND!")
    }
}

4. Example Input and Output

Example 1


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

Output:
1 3 5

Example 2


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

Output:
PATH NOT FOUND!

5. Conclusion

In this tutorial, we addressed the problem of finding the shortest path between two nodes in a graph using breadth-first search (BFS). Due to the ease of exploration provided by BFS, it is widely useful in many algorithmic problems. It is essential to develop the ability to effectively utilize BFS to solve problems in actual exams or coding tests.

Now, we encourage you to tackle various problems using BFS. Enhance your understanding of algorithms through implementation in Kotlin, and develop the skills that can also be applied in real-world scenarios!

Kotlin coding test course, calculating the remainder sum

Problem Description

You are given an array A consisting of N integers and an integer M, and you need to find the sum of the remainders of all elements in array A when divided by M. This will enhance your understanding of the properties of remainders and how to handle arrays efficiently, as well as improve your ability to use loops and conditionals in Kotlin.

Input Format

  • The first line contains the size of the array N (1 ≤ N ≤ 10^6) and the integer M (1 ≤ M ≤ 1000).
  • The second line contains N integers A1, A2, …, AN. (0 ≤ Ai ≤ 109)

Output Format

Print the sum of the remainders of all elements in array A when divided by M.

Example

    Input:
    5 3
    1 2 3 4 5

    Output:
    1
    

Problem Solving Process

To solve this problem, we can approach it by dividing each element of array A by M and summing all the remainders. This approach has a time complexity of O(N), making it very efficient and feasible within the given constraints.

Step-by-Step Procedure

  • Store the values of N and M that are received as input.
  • Receive the elements of array A as input.
  • Calculate the remainders of all elements divided by M and obtain their sum.
  • Print the result.

Kotlin Code Implementation

The following code is a Kotlin program that implements all the above procedures:

    fun main() {
        // Input
        val (n, m) = readLine()!!.split(" ").map { it.toInt() }
        val a = readLine()!!.split(" ").map { it.toInt() }

        // Calculate remainder sum
        var remainderSum = 0
        for (i in 0 until n) {
            remainderSum += a[i] % m
        }

        // Print result
        println(remainderSum)
    }
    

Code Explanation

In the above code, readLine() is used to receive input from the user. The first line inputs the array size N and M, while the second line inputs the elements of array A. Then, a for loop is used to calculate the remainders of all elements in A when divided by M and accumulates them in the remainderSum variable. Finally, the sum of the calculated remainders is printed.

Complexity Analysis

The time complexity of this problem is O(N) since all elements of the array are visited once. Furthermore, the space complexity is O(1), as only one additional variable is used to store the result, making it very efficient.

Optimization

The structure of the given problem is approached in the most optimized manner, and there is no need for further optimization. This is because all elements are iterated through only once to obtain the result.

Conclusion

This course has taught us how to efficiently handle arrays through the problem of calculating the sum of remainders, as well as the basic input/output and loop usage in Kotlin. Practicing such foundational problems will greatly help in building the basics for coding tests. I hope you continue to solve various problems and enhance your skills.