I came across below interview question and I am working on it:
Build a queue class with the enqueue and dequeue methods. The queue
can store an UNLIMITED number of elements but you are limited to
using arrays that can store up to 5 elements max..
Here is what I was able to come up with. Is this the right way to do it in the interview or is there any better way we should implement in the interview?
class Solution {
private final List<List<Integer>> array;
public Solution() {
this.array = new ArrayList<>();
}
public void enqueue(int value) {
if(array.isEmpty()) {
List<Integer> arr = new ArrayList<>();
arr.add(value);
array.add(arr);
return;
}
if(array.get(array.size() - 1).size() != 5) {
array.get(array.size() - 1).add(value);
return;
}
List<Integer> arr = new ArrayList<>();
arr.add(value);
array.add(arr);
return;
}
public int dequeue() {
if(array.isEmpty()) {
return -1;
}
for(List<Integer> l : array) {
for(int i=0; i<l.size(); i++) {
return l.remove(i);
}
}
return -1;
}
}
As I mentioned in comments, your solution doesn't really solve the problem because the outer array of 5-element arrays can have more than 5 elements.
Instead, you can implement the queue as a linked list of 4-integer nodes, using the 5th element for a reference to the next array. But there's no reason to assume the elements are integers. This turns out to be pretty simple.
public class SillyQueue<T> {
private static final int MAX = 5;
private Object [] head = new Object[MAX], tail = head;
private int headPtr = 0, tailPtr = 0;
void enqueue(T x) {
if (tailPtr == MAX - 1) {
Object [] a = new Object[MAX];
tail[MAX - 1] = a;
tail = a;
tailPtr = 0;
}
tail[tailPtr++] = x;
}
T dequeue() {
if (headPtr == MAX - 1) {
head = (Object[]) head[MAX - 1];
headPtr = 0;
}
return (T) head[headPtr++];
}
}
Your answer uses ArrayList instead of true arrays, and worse, uses an unlimited arraylist to put those arrays in. I think that the interviewers expected you to implement a singly-linked list of 5-element arrays:
/**
* A singly-linked list node with an array; supports popping its 1st elements,
* and adding elements at the end, possibly by creating a new node
*/
public class ListNode {
final int MAX = 5;
private int contents[] = new int[MAX];
private int size = 0; // valid elements
private ListNode next = null;
private ListNode(ListNode next) {
this.next = next;
}
public boolean isEmpty() { return size == 0; }
public ListNode addLast(int value) {
ListNode next = this;
if (size == MAX) {
next = new ListNode(this);
}
next.contents[next.size ++] = value;
return next;
}
public int removeFirst() {
if (size == 0) {
throw new NoSuchElementException("empty queue");
}
int value = contents[0];
size --;
for (int i=1; i<size; i++) contents[i-1] = contents[i];
return value;
}
}
/**
* A simple queue on top of nodes that keep arrays of elements
*/
public class ListArrayQueue {
ListNode first = new ListNode();
ListNode last = first;
public void enqueue(int value) {
last = last.addLast(value);
}
public int dequeue() {
if (first.isEmpty() && first != last) {
first = first.next;
}
return first.removeFirst();
}
}
Performance-wise, this can be improved: you can avoid keeping the size in each ListNode, since only the 1st and last nodes can be non-full. You can also avoid the loop in removeFirst, but that would entail replacing size by firstIndex and lastIndex; which could again be moved into the ListArrayQueue to save space in each node.
If they has asked you to build an unlimited array out of 5-element array pieces, you would have had to implement something similar to a b-tree. Which, without handy references, would be quite hard to pull off during an interview.
You can use a 1-D array and use Wrap-around indexing to implement the queue with the limitation that queue can contain maximum 5 elements.
For checking the condition of empty queue, maintain a variable that counts the number of elements present in the queue.
Is this the right way to do it in the interview…?
Presenting uncommented code is never right, let alone in an interview.
In an interactive interview, it would be your task to find out whether you can/should use an unlimited number of arrays.
If not, you have to negotiate a way to handle an enqueue() to a queue filled to capacity in addition to a dequeue() to an empty one.
Fix the type of items the queue can hold.
Agree upon the parameters of the enqueue and dequeue methods.
The task is to Build a queue class, Solution is a bad choice for a name - array for something to access the items is no better.
In a language providing arrays, I'd take limited to using arrays literally - if using something more, why not an implementation of java.util.Queue?
The empty queue handling is entirely redundant: in enqueue(), you could have used
if (!array.isEmpty() && array.get(array.size() - 1).size() < 5); in dequeue() you can just drop it.
Instantiating List<Integer>s, you know there won't be more than five items at a time: tell the constructor.
dequeue() leaves empty List<Integer>s in arrays, giving rise to the current nested loop that desperately needs a comment.
(For the second part of the question, I second Rajkamal Tomar.)
Trade Off - Organize Fixed Size Arrays
Manage arrays based on ArrayList
enqueue - append new fixed size array - O(1)
dequeue - remove first fixed size array - O(n)
Manage arrays based on LinkedList
enqueue - append new fixed size array to linked list - O(1)
dequeue - remove first fixed size array - O(1)
cons - extra next pointer to setup linked list
public class FixedArrayQueue<T> {
private Node<T> head, tail;
private int front, rear, size;
private final int SIZE;
public FixedArrayQueue(int n) {
SIZE = n;
head = tail = new Node<T>(SIZE);
front = rear = size = 0;
}
public void enqueue(T t) {
tail.array[rear++] = t;
if (rear == SIZE) {
rear = 0;
append();
}
size++;
}
public T dequeue() {
if (size == 0) {
throw new EmptyQueueException();
}
T ret = head.array[front++];
if (front == SIZE) {
front = 0;
remove();
}
size--;
return ret;
}
private void append() {
tail.next = new Node<T>(SIZE);
tail = tail.next;
}
private void remove() {
head = head.next;
}
private boolean isEmpty() {
return size == 0;
}
private int size() {
return size;
}
}
class Node<T> {
T[] array;
Node<T> next;
public Node(int n) {
array = (T[]) new Object[n];
}
}
Related
So, I am creating a generic data structure named "Sack". In this I add items to a sack, grab a random item, see if it's empty, or dump out its contents etc. Also I'm creating it to expand to hold as many items as needed.
Currently, I'm working on the add method and I'm having troubles on my add method, and I am trying to think of a way adding what's in my parameter into the sack.
import java.util.Arrays;
public class Sack<E>
{
public static final int DEFAULT_CAPACITY = 10;
private E [] elementData;
private int size;
#SuppressWarnings("unchecked")
public Sack()
{
elementData = (E[]) new Object[DEFAULT_CAPACITY];
}
#SuppressWarnings("unchecked")
public Sack(int capacity)
{
if(capacity < 0)
{
throw new IllegalArgumentException("capacity " + capacity);
}
this.elementData = (E[]) new Object[capacity];
}
public boolean isEmpty()
{
if(size == 0)
{
return true;
}
else
{
return false;
}
}
public E [] dump()
{
E [] E2 = Arrays.copyOf(elementData, size);
for(int i = 0; i < size; i++)
{
elementData[i] = null;
}
size = 0;
return E2;
}
In this method, I am trying to add item, into my sack. When I run my tests, I am told it's incorrect. If there's a way to improve this.
public void add(E item)
{
elementData[size] = item;
size++;
}
elementData is what I am adding the items into.
Update
I updated my add method to look like this.
public void add(E item)
{
if(size >= elementData.length-1)
{
elementData[size] = item;
size++;
}
}
The message I am now receiving is that add is not working correctly and to check size usage.
You cannot ensure capacity of Java arrays, Javascript can! You can create a new one and copy:
public void add(E element) {
int index = size++;
if(size >= elementData.length-1) {
// it ensures elementData
elementData = java.util.Arrays.copyOf(elementData, size);
}
elementData[index] = element;
}
or skip ensure of array capacity and change the check direction:
public void add(E element) {
if(size < elementData.length-1) {
elementData[size++] = element;
}
// TODO else notice of the unsuccessfull add
}
It sounds like there's a spec for what your Sack is supposed to do that you did not paste.
It also sounds like your add method is supposed to just work, even if the sack is already at capacity.
That means you need to make a new array, copy over all elements, and then replace the array you have in your Sack instance with the new one (because java arrays cannot grow or shrink).
Look at the source of of java's own ArrayList for a hint on how that's done.
So after numerous tries, I give credit to #rockfarkas for solving this. I put in the following code and it solved my add method code.
public void add(E item)
{
int index = size++;
if(size >= elementData.length-1)
{
elementData = Arrays.copyOf(elementData, size);
}
elementData[index] = item;
}
Here's another way of doing this,
public void add(E item)
{
ensureCapacity(size+1);
elementData[size] = item;
size++;
}
This also works, but I would have to modify the ensureCapacity method accurately, which I have.
I'm attempting to create an array of linked list which will deal with hash value collisions. I have an array of an objects which I have tried to store the linkedList but it doesn't seem to work. Is there something I'm doing wrong, or is there a more efficient route I should take.
This is the error I get when running my code.
Exception in thread "main" java.lang.ArrayStoreException: linkedList
at p7b.Insert(p7b.java:57)
at p7b.main(p7b.java:31)
Here is my method
public static void Insert(int hashVal, String key,int[] arrayNums, Object[] arrayString){
Node newNode = new Node(key,null);
linkedList list = new linkedList();
if (arrayString[hashVal] == null){
arrayString[hashVal] = list;
}
Here is the linkedList code:
public class linkedList{
private Node head;
private int size;
public linkedList(){
size = 0;
head = null;
}//end default constructor
public boolean isEmpty(){
return size == 0;
}//end isEmpty
public int size(){
return size;
}//end size
protected Node find(int index){
Node curr = head;
for(int skip = 0; skip < index; skip++){
curr = curr.getNext();
}//end for
return curr;
}//end find
public Object get(int index){
if (index >=0 && index < size) {
// get reference to node, then data in node
Node curr = find(index);
Object dataItem = curr.item();
System.out.println(dataItem);
return dataItem;
}
else
return "error";
}//end get
public void add(int index, String item){
if(index>= 0 && index < size+1){
if(index == 0) {
//insert the new node containing item at
//beginning of list
Node newNode = new Node(item,head);
head = newNode;
head.setNext(head);//--------------------
}
else {
Node prev = find(index-1);
//insert the new node containing item after
//the node that prev references
Node newNode = new Node(item,head.getNext()); //changed prev to head
head.setNext(newNode); //prev.next = newNode --//changed prev to ead
head = newNode;
}//end if
}
sizeplus();
/*if(index == 16){//fffff
for(int i = 0; i < 50; i++){
System.out.println(head.item());-------------EXR
head = head.getNext();
System.out.println("----------");
}//ifffffff
}
*/
}//end add
public int sizeplus(){
size+=1;
return size;
}
public void remove(int index){
int num = index;
while(size>0){
//System.out.println("strt");
if(index>= 0 /*&& index < size*/){
if(index == 0) {
//delete the first node from the list
System.out.println("REMOVED :"+head.item());//----------------EXR
head = head.getNext();
}
else {
Node prev = find(index-1);
// delete the node after the node that prev
//references, save regerence to node
Node curr = prev.getNext();
System.out.println(curr.item());
if(size > 1){
}
else{
System.out.print("is the last one left");
}
prev.setNext(curr.getNext());
curr = prev.getNext();
index+=num-1;
}//end if
size--;
//System.out.println(size+" <-size || index-> " +index);
}//end if
}
}//end remove
public Node getH(){
return head;
}
}//end class
ALSO: how would i change from linked list to the next
here is what i tried.
linkedList list = new linkedList();
list = arrayString[i];
p7b.java:44: error: incompatible types
list = arrayString[i];
^
required: linkedList
found: Object
1 error
From your main method :
Object[] arrayString = new String[40];
...
Insert(hashVal,key,arrayNums,arrayString);
You are passing a String array to your method.
Therefore you can't put linkedList instances in this array.
If you want this array to contain linkedList instances, change the code to :
Object[] arrayString = new linkedList[40];
...
Insert(hashVal,key,arrayNums,arrayString);
or even better :
linkedList[] arrayString = new linkedList[40];
...
Insert(hashVal,key,arrayNums,arrayString);
and change the signature of Insert to accept a linkedList[] instead of Object[].
Here's the culprit:
Object[] arrayString = new String[40];
You're claiming that it's an Object[], but it's actually backed by a String[] instead. Java can't make the determination at compile time that you're not going to be able to store any old Object into that array, so it blows up at run time.
What you should do is type the array correctly - if it's going to hold linkedList entities, it should be linkedList entities.
linkedList[] linkedLists = new linkedList[40];
More specifically, you are using the array in a lot of different places. Be consistent with its usage.
Having a few thoughts about your code: it's not...correct. You're creating a linked list, right? There's no reason to use arrays unless the list itself is backed by them.
I can't vouch for the correctness of your linkedList.add method right now, but you don't want to use arrays for this at all. Create a single instance of a linked list outside of that method and store all of the data you care about in it.
public static void insert(String key, int index, linkedList list) {
list.add(index, key);
}
(As a general thought, linked lists don't have index positions that you simply insert into, so the index portion is completely superfluous.)
So I have this code I need to analyze and learn from it, about how bounded queue works, here it is:
class Queue<T> { // bounded
private T[] seq; // the sequence
private int size = 0; // size of sequence
private int head = 0; private int tail = 0; // front and rear
Queue(int n) { // n>0
seq = (T[])(new Object[n]);
}
Queue(){ this(10000);} // = seq=(T[])(new Object[10000]);
boolean isEmpty() { return size==0;}
boolean enq(T t) {
if (size<seq.length) {
seq[tail] = t; tail = (tail+1)%seq.length; size++;
return true;
}
else return false;
}
T deq() {
if (isEmpty()) return null;
else {
T temp = seq[head];
head = (head+1)%seq.length; size--;
return temp;
}
}
}
So everything is okay, but I don't understand why in the name of god is there a modulus (%) operation in the enq(T t) method and deq() method...
There is a modulus operation so that the queue can be represented by an array, where the contents of the queue "wrap around" the end of the array to the beginning.
Example with a size of 10:
[6th] [tail] [empty] [empty] [empty] [head] [2nd] [3rd] [4th] [5th]
Here, head = 5, and tail = 1, because a total of 12 items have been added and 5 removed. Even if there isn't enough room at the end of the array, there is room at the beginning of the array to store more data up until the capacity of the array.
The modulus operations allow the head and tail to wrap around on a deq and enq operation, respectively, so that 9 becomes 0 instead of 10, which would have caused an ArrayIndexOutOfBoundsException.
I am following the below approach to calculate the middle element from the linked list , but I want is there any built in method or any other approach which can also find the same easily , the approach that I am following is shown bellow..
import test.LinkedList.Node;
public class LinkedListTest {
public static void main(String args[]) {
//creating LinkedList with 5 elements including head
LinkedList linkedList = new LinkedList();
LinkedList.Node head = linkedList.head();
linkedList.add( new LinkedList.Node("1"));
linkedList.add( new LinkedList.Node("2"));
linkedList.add( new LinkedList.Node("3"));
linkedList.add( new LinkedList.Node("4"));
//finding middle element of LinkedList in single pass
LinkedList.Node current = head;
int length = 0;
LinkedList.Node middle = head;
while(current.next() != null){
length++;
if(length%2 ==0){
middle = middle.next();
}
current = current.next();
}
if(length%2 == 1){
middle = middle.next();
}
System.out.println("length of LinkedList: " + length);
System.out.println("middle element of LinkedList : " + middle);
}
}
class LinkedList{
private Node head;
private Node tail;
public LinkedList(){
this.head = new Node("head");
tail = head;
}
public Node head(){
return head;
}
public void add(Node node){
tail.next = node;
tail = node;
}
public static class Node{
private Node next;
private String data;
public Node(String data){
this.data = data;
}
public String data() {
return data;
}
public void setData(String data) {
this.data = data;
}
public Node next() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public String toString(){
return this.data;
}
}
}
Output:-
length of LinkedList: 4
middle element of LinkedList : 2
The basic algorithm would be
Take two pointers
Make both pointing to first node
Increment first with two nodes and second with one, at a time.
Loop until the 1st loop reaches the end. At this point, the 2nd will be at the middle.
Example:-
while ( p2.next != null ) {
p2 = p2.next;
if (p2.next != null) {
p2 = p2.next;
p1 = p1.next;
}
}
It will definitely work in odd case, for even case you need to check one more condition if first point is allowed to move next but not next to next then both pointers will be at middle you need to decide which to take as middle.
I would recommend using the Java built in
LinkedList<Object e>
It gives you all the functionality you need like getting the length: list.size(), and the middle object:
list.get((list.size())/2);
Options:
Have a double linked-list and go from the back and front at the same time until you get to a common point.
Store the size of the list and simply stop when you've reached this half this size (similar to what the standard API's LinkedList does).
Other than that I don't think you can do better than your algorithm.
public Node getMiddleElement(Node head) {
Node slow_pointer=head;
Node fast_pointer=head;
while(fast_pointer.next!=null && fast_pointer.next.next!=null)
{
slow_pointer=slow_pointer.next;
fast_pointer=fast_pointer.next.next;
}
return slow_pointer;
}
Node mid_elem=PrintMiddleElement(head);
System.out.println(mid_elem.data);
I/P:5 10 15 25 35 25 40 O/P:25
Solution for this question:
Use two indexes, first and second, both initialized to 0
Increment first by 1 and second by 2 * first
Set value of first to middle
Loop will execute until value of second is less than list size
Here is code snippet for getting middle element of list or linked list:
private int getMiddle(LinkedList<String> list) {
int middle = 0;
int size = list.size();
for (int i = 0, j = 0; j < size; j = i * 2) {
middle = i++;
}
return middle;
}
LinkedList<String> list = new LinkedList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
list.add("6");
list.add("7");
int middle = getMiddle(list);
System.out.println(list.get(middle));
I'm having trouble with my custom iterator...it seems that the next() method is not working.
I think my constructor is not working...and I got this error message: java.lang.ArithmeticException: / by zero
import java.util.Iterator;
public class RandomBag <Item> implements Iterable<Item>
{
private Node first;
private int N;
private int k=0;
private class Node
{
Item item;
Node next;
}
public void add(Item item)
{
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
N++;
}
public boolean isEmpty()
{
return first == null;
}
public int size()
{
return N;
}
public Iterator<Item> iterator()
{
return new RandomIterator();
}
private class RandomIterator implements Iterator<Item>
{
Item[] a = (Item[]) new Object [N];
public RandomIterator()
{
int counter = 0;
//put items in the array
for (Node x=first; x!=null; x=x.next)
{
a[counter] = x.item;
counter++;
}
//randomize the items in the array
for (int i=0; i<size(); i++)
{
int randomIndex = StdRandom.uniform(i, size());
Item item = a[randomIndex];
a[randomIndex] = a[i];
a[i] = item;
}
}
public void remove() {}
public boolean hasNext()
{
return k!=N;
}
public Item next()
{
Item item = a[k % a.length];
k++;
return item;
}
}
public static void main(String[] args)
{
RandomBag<Double> numbers = new RandomBag<Double>();
Iterator iter = numbers.iterator();
numbers.add(1.0);
numbers.add(4.0);
numbers.add(3.0);
numbers.add(5.0);
StdOut.println(iter.next());
StdOut.println(iter.next());
StdOut.println(iter.next());
StdOut.println(iter.next());
}
}
The problem is in this method:
public Item next()
{
Item item = a[k % a.length]; // If a.length is zero... BOOM
k++;
return item;
}
It doesn't protect you against this error in the future with a zero-length bag (or some of the other code issues pointed out), but moving this line:
Iterator iter = numbers.iterator();
Below the final .add() statement should fix the issue you're seeing, which is occurring because the iterator is initializing before anything is in numbers.
First of all: The k variable should be part of the iterator and NOT of the class itself - otherwise you get obviously pretty useless results as soon as you have more than 1 iterator.
But the problem is that you use a argument less constructor for your RandomBag class which means that N is initialized to 0. Then you construct your inner class iterator with an array of size N (=0) and try to use it - that won't work. The add() methods after initializing your Iterator have absolutely no effect - which makes this iterator pretty useless (usually you should throw a concurrent modification exception here and use the data of the datastructure not make a copy=)
PS: If you want to use this strange iterator, change your hasNext() method to use your arrays length and NOT N - that'll fix this issue because next() will not be called (or if it is, throwing an exception is fine)