Google Interview Question for SDE1s


Country: United States
Interview Type: Phone Interview




Comment hidden because of low score. Click to expand.
7
of 9 vote

For the case where we don't know in advance that most elements will be T, a good approach would be to keep a growable bitset. This is a growable array of integers, used as a bitset for space efficiency. You could write a simple ArrayList implementation that initially allocates an array of integers of some small size, and every time the array runs out of space, doubles the storage and copies the existing data over to the new storage. The i-th Boolean in the collection would be stored in the (i%32)-th bit of the (i/32)-th integer, if we assume that integers are 32-bit. This data structure has O(1) amortized add, O(1) set, and O(1) get. The space usage is O(total number of values in the collection) + O(1).

If we know that very few values are F and we're interested in saving space, we can keep a number to tell us how many total T and F values we have, and then keep a hash set of all the F values. To determine the value at an index, just return !hashSet.contains(index). To set an index, remove it from the hashset if setting to true; add it to the hash set if setting to false. This data structure has O(1) expected time add, set, and get. The space usage is O(number of F values) + O(1).

In both of the above implementations, the length() operation would return, in O(1) time, a previously-stored count (that is updated in O(1) time as elements are appended).

- eugene.yarovoi September 14, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Good. +1.

- Anonymous September 14, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

I didn't go with bitset, but all in all I implemented the ArrayList using boolean arrays. I guess they didn't like my answer, got a reject!

- adi September 14, 2013 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

@adi: Lot of factors go into a reject. Your performance on any one particular question cannot be the determining factor (unless it raises a clear red flag/ is a phone interview etc).

- Anonymous September 14, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Here is an implementation of the first approach.

#include<stdio.h>
#include<stdlib.h>

typedef enum {false, true} bool;

typedef struct BVect_s {
    char *val;
    int len;
    int numBit;
} BVect;

int initialize(BVect *v){
    v->val = (char *)malloc(sizeof(char));
    v->len = 1;
    v->numBit = 0;
    return 0;
}

bool get(BVect *v, int pos){
    if(v->numBit <= pos)
        return false;
    int s = sizeof(char);
    return v->val[pos/s]&(1<<(pos%s))?true:false;
}

int set(BVect *v, int pos, bool a){
    if(pos >= v->numBit)
        return 1;
    int s = sizeof(char);
    if(a)
        v->val[pos/s] = v->val[pos/s]|(1<<(pos%s));
    else
        v->val[pos/s] = v->val[pos/s]&~(1<<(pos%s));
    return 0;
}

int doubleLen(BVect *v){
    v->len *= 2;
    return v->val = realloc(v->val, sizeof(char)*v->len);
}

int append(BVect *v, bool a){
    if(v->val == NULL)
        initialize(v);
    if(v->numBit == v->len*8)
        doubleLen(v);
    v->numBit++;
    return set(v, v->numBit-1, a);
}

/*driver function to test*/
int main(){
    char op;
    int val, pos;
    BVect *t;
    while(1){
        scanf("%c", &op);
        switch(op){
            case 'a':
                scanf("%d", &val);
                append(t, val);
                break;
            case 's':
                scanf("%d", &pos);
                scanf("%d", &val);
                set(t, pos, val);
                break;
            case 'g':
                scanf("%d", &pos);
                printf("%d\n", get(t, pos));
        }
    }
    return 0;
}

- karaamaati September 17, 2013 | Flag
Comment hidden because of low score. Click to expand.
-1
of 1 vote

@karaamaati: Thanks for adding code, but there's one critical mistake. It would be nice if you could edit your response to correct it. sizeof(char) is always 1, so you aren't really using bits here. You wanted the constant CHAR_BITS (use #include <limits.h>), which will (usually) be equal to 8. I also notice that in some places, you've directly used the constant 8, so you should convert those usages to CHAR_BITS as well for consistency.

There are some smaller stylistic issues too, for example "return condition ? true: false;" can be simplified to "return condition;". "complicatedThingThatTakesLotsOfTyping = complicatedThingThatTakesLotsOfTyping & expression" can be simplified to "complicatedThingThatTakesLotsOfTyping &= expression".

- eugene.yarovoi September 17, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

FWIW, std::vector<bool> is specialized to optimize space etc and can be used directly.

- Anonymous September 18, 2013 | Flag
Comment hidden because of low score. Click to expand.
2
of 2 vote

maybe we can just keep track of the index of the elements which are false.

- Ben September 13, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Here is an implementation.

#include <stdlib.h>
#include <iostream>
using namespace std;

class vectorBool{
  int* neg;
  int neg_size;
  int size;
public:
  vectorBool();
  ~vectorBool();
  void append(bool b);
  bool get(int index);
  void set(int index, bool b);
  int length();
  void display();
};

vectorBool::vectorBool(){
  neg = NULL;
  neg_size = 0;
  size = 0;
}

vectorBool::~vectorBool(){
}

void  vectorBool::append(bool b){
  if( b == false){
    int* newNeg = new int[neg_size+1];
    newNeg[neg_size] = size;
    if( neg ){
      for( int i = 0; i < neg_size; i++){
	newNeg[i] = neg[i]; 
      }     
      delete neg;
      neg = newNeg;
    }
    else{
      neg = newNeg;
    }
    neg_size++;
  }
  size++;
};

bool vectorBool::get(int index){
  if( index < 0 || index >= size ){
    cout << "Invalid Index!" << endl;
    exit (-1);
  }
  for( int i = 0; i < neg_size; i++){
    if ( index == neg[i] )
      return false;
  }
  return true;
}

void vectorBool::set(int index, bool b){
  if ( index < 0 ){
    exit (-1);
  }
  if ( index < size ){
    bool change_neg = false;
    for(int i = 0; i < neg_size; i++ ){
      if ( index == neg [i] ){
	  change_neg = true;
	  if( b == true){
	      int* newNeg = new int [ neg_size - 1];
	      for(int i = 0; i < index; i++){
	         newNeg[i] = neg[i];
	      }
	     for(int i = index+1; i < neg_size; i++){
	         newNeg[i-1] = neg[i];
	     }
	     neg_size--;
	     delete neg;
	     neg = newNeg;
	     break;
         }
      }
    }
    if(! change_neg){
      if( b == false){
	   int* newNeg = new int[neg_size+1];
	   neg[neg_size] = index;
	   neg_size++;
      }
    }	
  }
  else{
    append( b );
  }
}

int vectorBool::length(){
  return size;
}

void vectorBool::display(){
  cout << "neg: ";
  for(int i = 0; i< neg_size; i++)
    cout << neg[i] << ' ';
  cout << endl;
  cout << "neg_size: " << neg_size << endl;
  cout << "size: " << size << endl;
}

int main(){
  vectorBool v;
  v.append(false);
  v.append(true);
  v.append(false);
  v.set(2, true);
  v.append(false);
  v.display();
}

- liuguohua.friend September 15, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Use array of (int *) i.e array of array. int * array[1024];
Use array of 128 byte , i.e 1024 bits....

Whenever 128 byte array get full. create another 128 byte array and store its address in address array. Initially declare address array of size 1024. when it get full resize it to double and so on...... (here we are creating new address array and transferring only pointers from old array to new array. not 1024 bits )

For boolean get(int index) and set(int index, boolean b) query.

use array[ int(index/1024) ][ index%1024] for setting or getting index element.

- jigs September 14, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

typedef struct bitvec
{
bool bits[1024]; /// 1024 bits per bitvec.
int count;
struct bitvec *next;
} bitvec;

/// globals.
bitvec *head = NULL;
bitvec *last = NULL;
unsigned last_bit_index = 0;
unsigned append_count = 0;

bool* get_bit(unsigned index)
{
/// trying to get unappended bit.
if (index >= append_count) assert(0);

bitvec *curr = head;
unsigned vpos = index/1024;
unsigned bpos = index%1024;
/// iterate to the node of interest.
while(vpos--) { curr= curr->next; }

return &curr->bits[bpos];
}

void append(bool bit)
{
/// first time appending.
if (head == NULL && last == NULL)
{
head = last = (bitvec*) malloc(sizeof(struct bitvec));
}
/// need one more records.
if ( last_bit_index == 1023 )
{
last->next = (bitvec*) malloc(sizeof(struct bitvec));
last = last->next;
}
appendcount ++;
last->bits[last_bit_index++] = bit;
}
bool get(int index) { return *get_bit(index); }
void set(int index, boolean b) { *get_bit(index) =b; }
unsigned len() { return appendcount; }

- Anonymous September 14, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Can anyone provide a Java implementation please?

- Anonymous October 13, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Two things here. Notice that it said BooleanVector. Vector is synchronized data structure, so you must call sychronized (this) block in your append and set method. The other way to do it is to use a hashtable (thread safe). Since the api doesn't have a remove call, so you can assume that it's always growing. You can have the index as the key and increment it as the next key, and the T/F is obviously the value. The get would be O(1).

- Alex February 13, 2014 | Flag Reply


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More