Open In App

Check if the given array can be constructed uniquely from the given set of subsequences

Last Updated : 10 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr of distinct elements and a list of subsequences seqs of the array, the task is to check whether the given array can be uniquely constructed from the given set of subsequences.
Examples: 
 

Input : arr[] = {1, 2, 3, 4}, seqs[][] = {{1, 2}, {2, 3}, {3, 4}} 
Output: Yes 
Explanations: The sequences [1, 2], [2, 3], and [3, 4] can uniquely reconstruct 
the original array {1, 2, 3, 4}. 
Input: arr[] = {1, 2, 3, 4}, seqs[][] = {{1, 2}, {2, 3}, {2, 4}} 
Output: No 
Explanations : The sequences [1, 2], [2, 3], and [2, 4] cannot uniquely reconstruct 
{1, 2, 3, 4}. There are two possible sequences that can be constructed from the given sequences: 
1) {1, 2, 3, 4} 
2) {1, 2, 4, 3} 
 

 

Approach: 
In order to solve this problem we need to find the Topological Ordering of all the array elements and check if only one topological ordering of the elements exists or not, which can be confirmed by the presence of only single source at every instant while finding the topological ordering of elements.
Below is the implementation of the above approach: 
 

C++




// C++ program to Check if 
// the given array can be constructed
// uniquely from the given set of subsequences
 
#include <bits/stdc++.h>
using namespace std;
 
bool canConstruct(vector<int> originalSeq,
                vector<vector<int> > sequences)
{
    vector<int> sortedOrder;
    if (originalSeq.size() <= 0) {
        return false;
    }
 
    // Count of incoming edges for every vertex
    unordered_map<int, int> inDegree;
 
    // Adjacency list graph
    unordered_map<int, vector<int> > graph;
    for (auto seq : sequences) {
        for (int i = 0; i < seq.size(); i++) {
            inDegree[seq[i]] = 0;
            graph[seq[i]] = vector<int>();
        }
    }
 
    // Build the graph
    for (auto seq : sequences) {
        for (int i = 1; i < seq.size(); i++) {
            int parent = seq[i - 1], child = seq[i];
            graph[parent].push_back(child);
            inDegree[child]++;
        }
    }
 
    // if ordering rules for all the numbers
    // are not present
    if (inDegree.size() != originalSeq.size()) {
        return false;
    }
 
    // Find all sources i.e., all vertices
    // with 0 in-degrees
    queue<int> sources;
    for (auto entry : inDegree) {
        if (entry.second == 0) {
            sources.push(entry.first);
        }
    }
 
    // For each source, add it to the sortedOrder
    // and subtract one from all of in-degrees
    // if a child's in-degree becomes zero
    // add it to the sources queue
    while (!sources.empty()) {
 
        // If there are more than one source
        if (sources.size() > 1) {
 
            // Multiple sequences exist
            return false;
        }
 
        // If the next source is different from the origin
        if (originalSeq[sortedOrder.size()] !=
                                sources.front()) {
            return false;
        }
        int vertex = sources.front();
        sources.pop();
        sortedOrder.push_back(vertex);
        vector<int> children = graph[vertex];
        for (auto child : children) {
 
            // Decrement the node's in-degree
            inDegree[child]--;
            if (inDegree[child] == 0) {
                sources.push(child);
            }
        }
    }
 
    // Compare the sizes of sortedOrder
    // and the original sequence
    return sortedOrder.size() == originalSeq.size();
}
 
int main(int argc, char* argv[])
{
    vector<int> arr = { 1, 2, 6, 7, 3, 5, 4 };
    vector<vector<int> > seqs = { { 1, 2, 3 },
                                { 7, 3, 5 },
                                { 1, 6, 3, 4 },
                                { 2, 6, 5, 4 } };
    bool result = canConstruct(arr, seqs);
    if (result)
        cout << "Yes" << endl;
    else
        cout << "No" << endl;
}


Java




// Java program to Check if
// the given array can be constructed
// uniquely from the given set of subsequences
import java.io.*;
import java.util.*;
 
class GFG {
 
    static boolean canConstruct(int[] originalSeq,
                                int[][] sequences)
    {
        List<Integer> sortedOrder
            = new ArrayList<Integer>();
        if (originalSeq.length <= 0) {
            return false;
        }
 
        // Count of incoming edges for every vertex
        Map<Integer, Integer> inDegree
            = new HashMap<Integer, Integer>();
 
        // Adjacency list graph
        Map<Integer, ArrayList<Integer> > graph
            = new HashMap<Integer, ArrayList<Integer> >();
        for (int[] seq : sequences)
        {
            for (int i = 0; i < seq.length; i++)
            {
                inDegree.put(seq[i], 0);
                graph.put(seq[i], new ArrayList<Integer>());
            }
        }
 
        // Build the graph
        for (int[] seq : sequences)
        {
            for (int i = 1; i < seq.length; i++)
            {
                int parent = seq[i - 1], child = seq[i];
                graph.get(parent).add(child);
                inDegree.put(child,
                             inDegree.get(child) + 1);
            }
        }
 
        // if ordering rules for all the numbers
        // are not present
        if (inDegree.size() != originalSeq.length)
        {
            return false;
        }
 
        // Find all sources i.e., all vertices
        // with 0 in-degrees
        List<Integer> sources = new ArrayList<Integer>();
        for (Map.Entry<Integer, Integer> entry :
             inDegree.entrySet())
        {
            if (entry.getValue() == 0)
            {
                sources.add(entry.getKey());
            }
        }
 
        // For each source, add it to the sortedOrder
        // and subtract one from all of in-degrees
        // if a child's in-degree becomes zero
        // add it to the sources queue
        while (!sources.isEmpty())
        {
 
            // If there are more than one source
            if (sources.size() > 1)
            {
 
                // Multiple sequences exist
                return false;
            }
 
            // If the next source is different from the
            // origin
            if (originalSeq[sortedOrder.size()]
                != sources.get(0))
            {
                return false;
            }
            int vertex = sources.get(0);
            sources.remove(0);
            sortedOrder.add(vertex);
            List<Integer> children = graph.get(vertex);
            for (int child : children)
            {
 
                // Decrement the node's in-degree
                inDegree.put(child,
                             inDegree.get(child) - 1);
                if (inDegree.get(child) == 0)
                {
                    sources.add(child);
                }
            }
        }
 
        // Compare the sizes of sortedOrder
        // and the original sequence
        return sortedOrder.size() == originalSeq.length;
    }
   
    // Driver code
    public static void main(String[] args)
    {
        int[] arr = { 1, 2, 6, 7, 3, 5, 4 };
        int[][] seqs = { { 1, 2, 3 },
                         { 7, 3, 5 },
                         { 1, 6, 3, 4 },
                         { 2, 6, 5, 4 } };
        boolean result = canConstruct(arr, seqs);
        if (result)
            System.out.println("Yes");
        else
            System.out.println("No");
    }
}
 
// This code is contributed by jitin


Python3




# Python 3 program to Check if
# the given array can be constructed
# uniquely from the given set of subsequences
 
def canConstruct(originalSeq, sequences):
    sortedOrder = []
    if (len(originalSeq) <= 0):
        return False
 
    # Count of incoming edges for every vertex
    inDegree = {i : 0 for i in range(100)}
     
    # Adjacency list graph
    graph = {i : [] for i in range(100)}
    for seq in sequences:
        for i in range(len(seq)):
            inDegree[seq[i]] = 0
            graph[seq[i]] = []
 
    # Build the graph
    for seq in sequences:
        for i in range(1, len(seq)):
            parent = seq[i - 1]
            child = seq[i]
            graph[parent].append(child)
            inDegree[child] += 1
     
    # If ordering rules for all the numbers
    # are not present
    if (len(inDegree) != len(originalSeq)):
        return False
 
    # Find all sources i.e., all vertices
    # with 0 in-degrees
    sources = []
    for entry in inDegree:
        if (entry[1] == 0):
            sources.append(entry[0])
             
    # For each source, add it to the sortedOrder
    # and subtract one from all of in-degrees
    # if a child's in-degree becomes zero
    # add it to the sources queue
    while (len(sources) > 0):
         
        # If there are more than one source
        if (len(sources)  > 1):
             
            # Multiple sequences exist
            return False
             
        # If the next source is different from the origin
        if (originalSeq[len(sortedOrder)] != sources[0]):
            return False
        vertex = sources[0]
        sources.remove(sources[0])
        sortedOrder.append(vertex)
        children = graph[vertex]
        for child in children:
             
            # Decrement the node's in-degree
            inDegree[child] -= 1
            if (inDegree[child] == 0):
                sources.append(child)
 
    # Compare the sizes of sortedOrder
    # and the original sequence
    return len(sortedOrder) == len(originalSeq)
 
if __name__ == '__main__':
    arr = [ 1, 2, 6, 7, 3, 5, 4 ]
    seqs = [[ 1, 2, 3 ],
            [ 7, 3, 5 ],
            [ 1, 6, 3, 4 ],
            [ 2, 6, 5, 4 ]]
    result = canConstruct(arr, seqs)
    if (result):
        print("Yes")
    else:
        print("No")
 
# This code is contributed by Bhupendra_Singh


C#




using System;
using System.Collections.Generic;
 
class GFG {
    // Function to check if the given array can be
    // constructed uniquely from the given set of
    // subsequences
    static bool CanConstruct(int[] originalSeq,
                             int[][] sequences)
    {
        // List to store the sorted order of elements in the
        // original sequence
        List<int> sortedOrder = new List<int>();
 
        // If the original sequence is empty, return false
        if (originalSeq.Length <= 0) {
            return false;
        }
 
        // Count of incoming edges for every vertex
        Dictionary<int, int> inDegree
            = new Dictionary<int, int>();
 
        // Adjacency list graph
        Dictionary<int, List<int> > graph
            = new Dictionary<int, List<int> >();
        foreach(int[] seq in sequences)
        {
            // Initialize the in-degree and graph data
            // structures for each element in the sequence
            for (int i = 0; i < seq.Length; i++) {
                inDegree[seq[i]] = 0;
                graph[seq[i]] = new List<int>();
            }
        }
 
        // Build the graph
        foreach(int[] seq in sequences)
        {
            for (int i = 1; i < seq.Length; i++) {
                int parent = seq[i - 1], child = seq[i];
                graph[parent].Add(child);
                inDegree[child] = inDegree[child] + 1;
            }
        }
 
        // If ordering rules for all the numbers are not
        // present, return false
        if (inDegree.Count != originalSeq.Length) {
            return false;
        }
 
        // Find all sources i.e., all vertices with 0
        // in-degrees
        List<int> sources = new List<int>();
        foreach(KeyValuePair<int, int> entry in inDegree)
        {
            if (entry.Value == 0) {
                sources.Add(entry.Key);
            }
        }
 
        // For each source, add it to the sortedOrder and
        // subtract one from all of in-degrees If a child's
        // in-degree becomes zero, add it to the sources
        // queue
        while (sources.Count > 0) {
            // If there are more than one source, multiple
            // sequences exist and return false
            if (sources.Count > 1) {
                return false;
            }
 
            // If the next source is different from the
            // original sequence, return false
            if (originalSeq[sortedOrder.Count]
                != sources[0]) {
                return false;
            }
            int vertex = sources[0];
            sources.RemoveAt(0);
            sortedOrder.Add(vertex);
            List<int> children = graph[vertex];
            foreach(int child in children)
            {
                // Decrement the node's in-degree
                inDegree[child] = inDegree[child] - 1;
                if (inDegree[child] == 0) {
                    sources.Add(child);
                }
            }
        }
 
        // Compare the sizes of sortedOrder and the original
        // sequence
        return sortedOrder.Count == originalSeq.Length;
    }
 
    // Driver code
    static void Main(string[] args)
    {
        int[] arr = { 1, 2, 6, 7, 3, 5, 4 };
        int[][] seqs = { new int[] { 1, 2, 3 },
                         new int[] { 7, 3, 5 },
                         new int[] { 1, 6, 3, 4 },
                         new int[] { 2, 6, 5, 4 } };
        bool result = CanConstruct(arr, seqs);
        if (result)
            Console.WriteLine("Yes");
        else
            Console.WriteLine("No");
    }
}


Javascript




<script>
 
// JavaScript program to Check if
// the given array can be constructed
// uniquely from the given set of subsequences
function canConstruct(originalSeq, sequences)
{
    let sortedOrder = [];
    if (originalSeq.length <= 0) {
        return false;
    }
 
    // Count of incoming edges for every vertex
    let inDegree = new Map();
 
    // Adjacency list graph
    let graph = new Array(100).fill(0).map(()=>[]);
    for (let seq of sequences) {
        for (let i = 0; i < seq.length; i++) {
            inDegree.set(seq[i] , 0);
            graph[seq[i]] = [];
        }
    }
 
    // Build the graph
    for (let seq of sequences) {
        for (let i = 1; i < seq.length; i++) {
            let parent = seq[i - 1], child = seq[i];
            graph[parent].push(child);
            if(inDegree.has(child))
                inDegree.set(child,inDegree.get(child)+1);
            else
                inDegree.set(child,1);
        }
    }
 
    // if ordering rules for all the numbers
    // are not present
    if (inDegree.length != originalSeq.length) {
        return false;
    }
 
    // Find all sources i.e., all vertices
    // with 0 in-degrees
    let sources = [];
    for (let [entry,res] of inDegree) {
        if (res== 0) {
            sources.push(entry);
        }
    }
 
    // For each source, add it to the sortedOrder
    // and subtract one from all of in-degrees
    // if a child's in-degree becomes zero
    // add it to the sources queue
    while (sources.length > 0) {
 
        // If there are more than one source
        if (sources.length > 1) {
 
            // Multiple sequences exist
            return false;
        }
 
        // If the next source is different from the origin
        if (originalSeq[sortedOrder.length] !=
                                sources[0]) {
            return false;
        }
        let vertex = sources.shift();
        sortedOrder.push(vertex);
        let children = graph[vertex];
        for (let child of children) {
 
            // Decrement the node's in-degree
            if(inDegree.has(child)){
                inDegree.set(child,inDegree.get(child)-1);
            }
            if (inDegree.get(child) == 0) {
                sources.push(child);
            }
        }
    }
 
    // Compare the sizes of sortedOrder
    // and the original sequence
    return sortedOrder.length == originalSeq.length;
}
 
// driver code
 
let arr = [ 1, 2, 6, 7, 3, 5, 4 ];
let seqs = [ [ 1, 2, 3],
             [ 7, 3, 5],
             [ 1, 6, 3, 4],
             [ 2, 6, 5, 4]];
let result = canConstruct(arr, seqs);
if (result)
    document.write("Yes","</br>");
else
    document.write("No","</br>");
 
 
// This code is contributed by shinjanpatra
 
</script>


Output: 

No

 

Time complexity : 
The time complexity of the above algorithm will be O(N+E), where ‘N’ is the number of elements and ‘E’ is the total number of the rules. Since, at most, each pair of numbers can give us one rule, we can conclude that the upper bound for the rules is O(M) where ‘M’ is the count of numbers in all sequences. So, we can say that the time complexity of our algorithm is O(N + M).
Auxiliary Space : O(N+ M), since we are storing all possible rules for each element.
 



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads