Open In App

CSES Solutions – Collecting Numbers II

Last Updated : 15 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array that contains each number between 1 to n exactly once. Your task is to collect the numbers from 1 to n in increasing order. On each round, you go through the array from left to right and collect as many numbers as possible. Given m operations that swap two numbers in the array, your task is to report the number of rounds after each operation.

Examples:

Input: n = 5, m = 3, values[] = {4, 2, 1, 5, 3}, swaps[][] = {{2, 3}, {1, 5}, {2,3}}
Output:
2
3
4
Explanation:

  • In the 1st operation after swapping the values of 2nd and 3rd position the array is {4, 1, 2, 5, 3}. We can collect 1, 2, 3 in the 1st round and 4, 5 in the 2nd round. Hence, the answer is 2.
  • In the 2nd operation after swapping the values of 1st and 5th position the array is {3, 1, 2, 5, 4}. We can collect 1, 2 in the 1st round, 3, 4 in the 2nd round and 5 in the 3rd round. Hence, the answer is 3.
  • In the 3rd operation after swapping the values of 2nd and 3rd position the array is {3, 2, 1, 5, 4}. We can collect 1 in the 1st round, 2 in the 2nd round, 3, 4 in the 3rd round and 5 in the 4th round. Hence, the answer is 4.

Input: n = 4, m = 1, values[] = {4, 2, 3, 1}, swaps[][] = {{1, 4}}
Output: 1
Explanation: After the first swap operation, the array will be {1, 2, 3, 4}. We can collect 1, 2, 3 and 4 in the first round only.

Approach: To solve the problem, follow the idea below:

The idea is to calculate the number of inversions, where values[i] > values[j] and position[i] < position[j], between adjacent elements. This will give us the number of rounds required to collect all numbers from 1 to n in the given order. Count the number of inversions formed by given order of elements. Begin the operation. Since only the adjacent elements (the previous and next element of the current element) are affected, we store them in a set if they exist. Then subtract from the count, the inversions formed by our current set as there may be some elements that don’t form an inversion after the swap and if they form they’ll be counted. Next, we swap the elements, update the positions, and again count and add the inversions by adjacent elements to our existing count. This approach reduces the time complexity by checking only the neighboring elements.

Step-by-step algorithm:

  • Create a vector to store the positions of each value in the array.
  • Initialize a count variable to 1.
  • Iterate over the array from 1 to n-1.
  • If there is an inversion i.e. the position of the current value is greater than the position of the next value, increment the count.
  • Declare a set to store the pairs of values that will be updated in each swap operation.
  • Update the count before the swap, subtract from the count, the inversions formed by our current set as there may be some elements that don’t form an inversion after the swap and if they form they’ll be counted.
  • Swap the values at the given positions.
  • Update the positions of the swapped values.
  • Count and add the inversions by adjacent elements to our existing count.
  • Add the count to the result vector.
  • Clear the set for the next operation.
  • Return the result.

Below is the implementation of the algorithm:

C++
// C++ code
#include <bits/stdc++.h>
using namespace std;

vector<int>
collectingnumbersII(int n, int m, vector<int>& values,
                    vector<vector<int> >& swaps)
{
    // Make the array 1-indexed
    values.insert(values.begin(), 0);
    vector<int> res;
    vector<int> position(n + 1);

    // Store the positions of the values
    for (int i = 1; i <= n; i++)
        position[values[i]] = i;

    // Calculate the initial number of rounds
    int count = 1;
    for (int i = 1; i < n; i++)
        // Increase the count if there is an inversion i.e.
        // if the position of i is greater than the position
        // of i+1
        count += (position[i] > position[i + 1]);

    // Declare a set to store the pairs of values that will
    // be updated
    set<pair<int, int> > updatedPairs;

    for (int i = 0; i < m; i++) {
        // Declare two integers l and r to store the
        // positions to be swapped
        int l = swaps[i][0], r = swaps[i][1];

        // Insert the pairs of values that will be updated
        // into the set
        if (values[l] + 1 <= n)
            updatedPairs.insert(
                { values[l], values[l] + 1 });
        if (values[l] - 1 >= 1)
            updatedPairs.insert(
                { values[l] - 1, values[l] });
        if (values[r] + 1 <= n)
            updatedPairs.insert(
                { values[r], values[r] + 1 });
        if (values[r] - 1 >= 1)
            updatedPairs.insert(
                { values[r] - 1, values[r] });

        // Update the count before the swap
        for (auto swapped : updatedPairs)
            // Subtract from the count, the inversions
            // formed by our current set as there may be
            // some elements that don’t form an inversion
            // after the swap and if they form they'll be
            // counted.
            count -= position[swapped.first]
                     > position[swapped.second];

        // Perform the swap
        swap(values[l], values[r]);

        // Update the position of the value at position l
        position[values[l]] = l;
        // Update the position of the value at position r
        position[values[r]] = r;

        // Update the count after the swap
        for (auto swapped : updatedPairs)
            // Count and add the inversions by adjacent
            // elements to our existing count.
            count += position[swapped.first]
                     > position[swapped.second];

        // Add the count to the result vector.
        res.push_back(count);

        // Clear the set for the next operation
        updatedPairs.clear();
    }
    // Return result
    return res;
}

// Driver Code
int main()
{
    int n = 5, m = 3;
    vector<int> values = { 4, 2, 1, 5, 3 };
    vector<vector<int> > swaps
        = { { 2, 3 }, { 1, 5 }, { 2, 3 } };
    vector<int> res
        = collectingnumbersII(n, m, values, swaps);

    for (auto i : res)
        cout << i << "\n";

    return 0;
}
Java
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Main {
    public static List<Integer> GFG(int n, int m, int[] values, int[][] swaps) {
        // Make the array 1-indexed
        List<Integer> res = new ArrayList<>();
        int[] position = new int[n + 1];

        // Store the positions of the values
        for (int i = 1; i <= n; i++) {
            position[values[i]] = i;
        }

        // Calculate the initial number of rounds
        int count = 1;
        for (int i = 1; i < n; i++) {
            // Increase the count if there is an inversion i.e.
            // if the position of i is greater than the position
            // of i+1
            count += position[i] > position[i + 1] ? 1 : 0;
        }

        // Declare a set to store the pairs of the values that will
        // be updated
        Set<List<Integer>> updatedPairs = new HashSet<>();
        for (int i = 0; i < m; i++) {
            int l = swaps[i][0];
            int r = swaps[i][1];

            // Insert the pairs of the values that will be updated
            // into the set
            if (values[l] + 1 <= n) {
                updatedPairs.add(List.of(values[l], values[l] + 1));
            }
            if (values[l] - 1 >= 1) {
                updatedPairs.add(List.of(values[l] - 1, values[l]));
            }
            if (values[r] + 1 <= n) {
                updatedPairs.add(List.of(values[r], values[r] + 1));
            }
            if (values[r] - 1 >= 1) {
                updatedPairs.add(List.of(values[r] - 1, values[r]));
            }

            // Update the count before the swap
            for (List<Integer> swapped : updatedPairs) {
                count -= position[swapped.get(0)] > position[swapped.get(1)] ? 1 : 0;
            }

            // Perform the swap
            int temp = values[l];
            values[l] = values[r];
            values[r] = temp;

            // Update the position of value at position l
            position[values[l]] = l;
            position[values[r]] = r;

            // Update the count after the swap
            for (List<Integer> swapped : updatedPairs) {
                count += position[swapped.get(0)] > position[swapped.get(1)] ? 1 : 0;
            }

            // Add the count to result list
            res.add(count);
            updatedPairs.clear();
        }
        // Return result
        return res;
    }

    // Driver Code
    public static void main(String[] args) {
        int n = 5, m = 3;
        int[] values = {0, 4, 2, 1, 5, 3}; // Make the array 1-indexed
        int[][] swaps = {{2, 3}, {1, 5}, {2, 3}};
        List<Integer> res = GFG(n, m, values, swaps);
        for (int i : res) {
            System.out.println(i);
        }
    }
}
Python
def GFG(n, m, values, swaps):
    # Make the array 1-indexed
    values.insert(0, 0)
    res = []
    position = [0] * (n + 1)
    # Store the positions of the values
    for i in range(1, n + 1):
        position[values[i]] = i
    # Calculate the initial number of rounds
    count = 1
    for i in range(1, n):
        # Increase the count if there is an inversion i.e.
        # if the position of i is greater than the position
        # of i+1
        count += position[i] > position[i + 1]
    # Declare a set to the store the pairs of the values that will
    # be updated
    updated_pairs = set()
    for i in range(m):
        l, r = swaps[i]
        # Insert the pairs of the values that will be updated
        # into the set
        if values[l] + 1 <= n:
            updated_pairs.add((values[l], values[l] + 1))
        if values[l] - 1 >= 1:
            updated_pairs.add((values[l] - 1, values[l]))
        if values[r] + 1 <= n:
            updated_pairs.add((values[r], values[r] + 1))
        if values[r] - 1 >= 1:
            updated_pairs.add((values[r] - 1, values[r]))
        # Update the count before the swap
        for swapped in updated_pairs:
            count -= position[swapped[0]] > position[swapped[1]]
        # Perform the swap
        values[l], values[r] = values[r], values[l]
        # Update the position of value at position l
        position[values[l]] = l
        position[values[r]] = r
        # Update the count after the swap
        for swapped in updated_pairs:
            count += position[swapped[0]] > position[swapped[1]]
        # Add the count to result list.
        res.append(count)
        updated_pairs.clear()
    # Return result
    return res
# Driver Code
if __name__ == "__main__":
    n, m = 5, 3
    values = [4, 2, 1, 5, 3]
    swaps = [[2, 3], [1, 5], [2, 3]]
    res = GFG(n, m, values, swaps)
    for i in res:
        print(i)
JavaScript
function GFG(n, m, values, swaps) {
    // Make the array 1-indexed
    values.unshift(0);
    let res = [];
    let position = new Array(n + 1).fill(0);

    // Store the positions of the values
    for (let i = 1; i <= n; i++) {
        position[values[i]] = i;
    }

    // Calculate the initial number of rounds
    let count = 1;
    for (let i = 1; i < n; i++) {
        // Increase the count if there is an inversion i.e.
        // if the position of i is greater than the position
        // of i+1
        count += position[i] > position[i + 1];
    }

    // Declare a set to store the pairs of the values that will
    // be updated
    let updatedPairs = new Set();
    for (let i = 0; i < m; i++) {
        let [l, r] = swaps[i];
        // Insert the pairs of the values that will be updated
        // into the set
        if (values[l] + 1 <= n) {
            updatedPairs.add([values[l], values[l] + 1]);
        }
        if (values[l] - 1 >= 1) {
            updatedPairs.add([values[l] - 1, values[l]]);
        }
        if (values[r] + 1 <= n) {
            updatedPairs.add([values[r], values[r] + 1]);
        }
        if (values[r] - 1 >= 1) {
            updatedPairs.add([values[r] - 1, values[r]]);
        }
        // Update the count before the swap
        for (let swapped of updatedPairs) {
            count -= position[swapped[0]] > position[swapped[1]];
        }
        // Perform the swap
        [values[l], values[r]] = [values[r], values[l]];
        // Update the position of value at position l
        position[values[l]] = l;
        position[values[r]] = r;
        // Update the count after the swap
        for (let swapped of updatedPairs) {
            count += position[swapped[0]] > position[swapped[1]];
        }
        // Add the count to result list
        res.push(count);
        updatedPairs.clear();
    }
    // Return result
    return res;
}

// Driver Code
let n = 5, m = 3;
let values = [4, 2, 1, 5, 3];
let swaps = [[2, 3], [1, 5], [2, 3]];
let res = GFG(n, m, values, swaps);
for (let i of res) {
    console.log(i);
}

Output
2
3
4

Time Complexity: O(n), where n is the size of the array.
Auxiliary Space: O(n), where n is the size of the array.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads