GeeksforGeeks » Interview Questions

Google Interview Question for Software Engineer/Developer about Data Structure

(11 posts)
  1. shiva
    guest
    Posted 10 months ago #

    Design a data structure that can be used instead of an array and avoids the "high-cost" (i.e. O(n)) of initializing the array. the data structure ought to holds n items and supports the following operations in O(1) time:
    * Init – Initializes the data structure to empty.
    * Set(i, x) – Sets item x at index i in the data structure.
    * Get(i) – Gets the item stored in index i (or 'empty' if nothing is there).
    Remark: the data structure should use O(n) space.

  2. Venki
    Moderator
    Posted 10 months ago #

    Standard vector implementation can serve the purpose. Amortized complexity is constant.

  3. shiva
    guest
    Posted 10 months ago #

    @venki can you explain where r u using O(n) space & how u are init in O(1) ??

  4. abc
    guest
    Posted 10 months ago #

    Use three un-initialized array, instead of one. The first array will
    contain the actual elements of array, while the other two will
    be used to ensure the validity of an entry.

    A[1..n] --- contains actual elements of array
    B [1..n] --- contains pointer to the third array
    C [1..n] --- contains pointer to the second array
    size -- number of valid entries in A

    Invariant: For each index i, if A[i] has been assigned then
    B[i] < size, and C[B[i]] = i;

    Init:
        size = 0;
    
    Set(i, x):
        p = B[i];
        if (p >= size || C[p] != i) // a new entry
       {
            C[size] = i;
            B[i] = size;
            size++;
       }
       A[i] = x;
    
    Get (i) :
        p = B[i];
        if ( p >= size || C[p] != i)  // unassigned index
            generate some error;
        else
             return A[i];
  5. rajcools
    Member
    Posted 10 months ago #

    @abc i didnt understand the need of three arrays this pointer indirection from one array to other i am not able to fathom.

    and in your intialize function setting size to 0 does this suffice as initialising?
    ill expect something as
    a[]={0};

  6. abc
    guest
    Posted 10 months ago #

    '
    Get (i) :
    p = B[i];
    if ( p >= size || C[p] != i) // unassigned index
    generate some error;
    else
    return A[i];
    '

    If the array is initialized to value y, then in this part instead of
    generating error, one should return y.

    The two arrays B and C are only to ensure, whether a location
    has been assigned a value other than y (which was assigned
    during initialization). Since, we cannot initialize the array due
    to complexity constraints, this is one way to ensure whether
    a particular index contains user assigned value or garbage.

  7. rajcools
    Member
    Posted 10 months ago #

    @abc makes sense :)

  8. rajcools
    Member
    Posted 10 months ago #

    @abc on second thought cant we do it with only 1 array and one bit vector. Bit vector will help us track whether value in array is initialized or garbage

    for ex
    A[i] is the array and b is the bit vector having number of bits equal to number of element in array when we initialise ith elemnt in array we set corresponding bit to 1 in bit vector.... size is ofcourse there for initialising the data structure to empty..
    what say?

  9. abc
    guest
    Posted 10 months ago #

    To rajcools:

    But then again you have the problem that you cannot initialize the
    bit-vector due to complexity constraints. That means you cannot
    be sure whether an entry in the vector is genuine, or garbage.

  10. Nachiket Bhagwat
    guest
    Posted 5 months ago #

    Can't we just take one extra array b[i] and check if ' b[i] = i ' , to check if ith block is set or not?

  11. Bond
    guest
    Posted 5 months ago #

    Denote the huge array by T . We also have a
    stack implemented by an array S. The size of S equals the number of keys actually
    stored, so that S should be allocated at the dictionary’s maximum size. The stack
    has an attribute top[S], so that only entries S[1 . . top[S]] are valid.
    The idea of this scheme is that entries of T and S validate each other. If key k is
    actually stored in T , then T [k] contains the index, say j , of a valid entry in S, and
    S[ j ] contains the value k. Let us call this situation, in which 1 ≤ T [k] ≤ top[S],
    S[T [k]] = k, and T [S[ j ]] = j, a validating cycle.
    Assuming that we also need to store pointers to objects in our direct-address table,
    we can store them in an array that is parallel to either T or S. Since S is smaller
    than T , we’ll use an array S, allocated to be the same size as S, for these pointers.
    Thus, if the Array contains an object x with key k, then there is a validating
    cycle and S[T [k]] points to x.
    The operations work as follows:
    • Initialization: Simply set top[S] = 0, so that there are no valid entries in the
    stack.
    • SEARCH: Given key k, we check whether we have a validating cycle, i.e.,
    whether 1 ≤ T [k] ≤ top[S] and S[T [k]] = k. If so, we return S[T [k]],
    and otherwise we return NIL.
    • INSERT: To insert object x with key k, assuming that this object is not already
    in the dictionary, we increment top[S], set S[top[S]] ← k, set S[top[S]] ← x,
    and set T [k] ← top[S].
    • DELETE: To delete object x with key k, assuming that this object is in the
    dictionary, we need to break the validating cycle. The trick is to also ensure
    that we don’t leave a “hole” in the stack, and we solve this problem by moving
    the top entry of the stack into the position that we are vacating—and then Þxing
    up that entry’s validating cycle.

    S[T [k]] ← S[top[S]]
    S[T [k]] ← S[top[S]]
    T [S[T [k]]] ← T [k]
    T [k] ← 0
    top[S] ← top[S] − 1

    (This a master-piece by CLRS)


Reply

You must log in to post.

RSS feed for this topic