I have an interview question that still kills my mind, please help.
You have to write a method in Java with a String parameter.
That String should be a tree of ternary operators (a?b:c). So basically it can be something like:a? g?h:j ? u?v:w : p : r?s:t
a
/ \
g?h:j r?s:t
/ \
u?v:w p
Something like that, I hope I even wrote it right, because I am really confused.
Then we have a class Node that has 2 fields: left and right:
class Node {
char variableName;
Node left, right;
}
So you have to return a Node with all the Nodes(left, right) from that String.
I hope this is understandable. If you need more information I will provide, but the basic idea here is to get all the nodes right. I was trying to do this using recursion and I still believe that this is right. But I cannot figure out how to do it right.
This question can be solved with a very simple recursive descent parser. The intention behind asking this question is to see if you can implement a recursive algorithm where recursion makes sense, as opposed to asking you to code up a boring recursive factorial to see if you have heard of recursion before.
Here is one possible implementation:
static class Parser {
private int pos = 0;
private String s;
public Parser(String s) {
this.s = s;
}
private void skipSpace() {
while (pos != s.length() && Character.isWhitespace(s.charAt(pos))) {
pos++;
}
}
public Node parse() {
skipSpace();
Node res = new Node();
res.variableName = s.charAt(pos++);
skipSpace();
if (pos == s.length()) return res;
if (s.charAt(pos) == '?') {
pos++;
res.left = parse();
skipSpace();
if (pos == s.length() || s.charAt(pos) != ':') {
System.err.println("Syntax error");
return null;
}
pos++;
res.right = parse();
}
return res;
}
}
public static Node parse(String s) {
Parser p = new Parser(s);
return p.parse();
}
Demo.
The idea is to use parse() method as if it's already written: first we parse the variable name, then we check if it is followed by a question mark. If it is, we consume the question mark, parse from the current position what becomes our left node, skip the colon (or error out if the colon is missing), and finally parse the right node. Skip whitespace as you go.
Related
I'm trying to understand the array-based implementation of Trie from http://www.programcreek.com/2014/05/leetcode-implement-trie-prefix-tree-java/ (see Java Solution 2 - Improve Performance by Using an Array).
public void insert(String word) {
TrieNode p = root;
for(int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
int index = c - 'a';
if(p.arr[index] == null) {
TrieNode temp = new TrieNode();
p.arr[index] = temp;
p = temp;
} else {
p = p.arr[index];
}
}
p.isEnd = true;
}
I'm not sure the else branch is ever executed. What am I missing?
Update 1
The given word only contains lower-case English letters
The first time you call this function, the else branch will indeed not execute. However, as the Trie gets populated, it is very possible that p.arr[index] is not null.
For example, calling insert("i") will cause add a new TrieNode at root.arr['i' - 'a']. Calling the function a second time, for example with insert("it"), will result in the check p.arr[index] == null returning false because the first insert already added the TrieNode for i at the root node.
You can test this out with the following main function (and putting a breakpoint or println statement in the else branch)
public static void main (String[] args)
{
Trie t = new Trie();
t.insert("i");
t.insert("it");
}
That looks to me pretty much like a bug. If c-'a'>26 then p.arr[index] won't be null but will raise an ArrayIndexOutOfBounds exception.
I have two functions here for size() but they both look like crap. The first one uses an overloaded function and the second, well, see for yourself. What I want to do is create a slick version of the second attempt but I'm low on ideas.
P.S: Telling me to use Java's util is kind of pointless. I want to make it pretty, not hide it.
So my function is called from a BST object and looks like this:
public int size() {
return size(root);
}
private int size(Node x) {
if (x == null) {
return 0;
} else {
return 1 + size(x.left) + size(x.right);
}
}
Now I don't want to overload the function so I rewrote it as such:
public int size() {
Node y = root;
if (y == null) {
return 0;
} else {
root = y.left;
int left = size();
root = y.right;
int right = size();
root = y;
return 1 + left + right;
}
}
All suggestions are welcome!
If it is something that is called regularly, perhaps you would be better caching the size in your Node class, and updating when you insert or delete, then it simply becomes
public int size() {
return root == null ? 0 : root.size();
}
IMHO Your first approach is good enough. Why? Because you have a perfect public interface(public size()) that governs how the size of the BST is calculated(using private size()) hiding the internal implementation. I don't see any harm in overloading as long as it lead to a better design decision.
Edit: This is my understanding of how 1st one is better than the 2nd approach. I welcome any feedbacks. Thanks!!
I am see an Exception in thread "main" java.lang.StackOverflowError. I hope to know what is wrong with the code below.
public void addWord(String word){
addWord(word,root,0);
}
private void addWord(String word,Node root,int pos)
{
for(Node c:root.children)
{
if(word.charAt(pos)==c.letter)
{
addWord(word,c,pos++);
}
}
Node temp = new Node();
temp.letter=word.charAt(pos);
temp.children=new ArrayList<Node>();
root.children.add(temp);
if(pos==word.length()-1)
{
temp.terminus=true;
return;
}
if(pos<word.length()-1)
{
addWord(word,temp,pos++);
}
}
In essence, stack overflow comes from the fact that your method keeps being called recursively and the recursion never ends.
One possible problem is this call:
addWord(word,temp,pos++);
It is equivalent to
addWord(word,temp,pos);
pos = pos + 1;
You probably mean:
addWord(word,temp,++pos);
which would be equivalent to
pos = pos + 1;
addWord(word,temp,pos);
I wrote a simpler version of addWord():
private void addWord(String word, Node aRoot, int pos) {
if (pos == word.length())
return;
for (Node c : aRoot.children) {
if (word.charAt(pos) == c.letter) {
addWord(word, c, pos+1);
return;
}
}
Node temp = new Node();
temp.letter = word.charAt(pos);
temp.children = new ArrayList<Node>();
temp.terminus = pos == word.length() - 1;
aRoot.children.add(temp);
addWord(word, temp, pos+1);
}
The original version in your code had a couple of problems with base cases, and with the recursive calls. As a general rule, you should avoid changing the values of a method's parameters (the pos++ part).
I'm guessing you're building a Trie data structure, and I anticipate that you're gonna have problems with that terminus attribute. Think about it, if you add several words with common prefixes, which would be the terminus node? do you intend to add several nodes with the same letter at the same level, or do you want to share nodes at the same level with the same letter? in the latter case, what would be the value of the terminus attribute?
To make my point clear, draw a diagram showing how would you like your Trie to look like after executing the following code (paying close attention to the value of terminus in each node), and see if the above implementation gives the result you expect.
Test t = new Test();
t.addWord("a");
t.addWord("abc");
t.addWord("ab");
im coming from c++ to java and i am confused on binary trees with java. is the only way to have a Node class is to make it an inner static class? all the examples i see do this. However, the way im doing it is i have a node class and a binarytree class uses this node class. but i keep getting an error when i try inserting into the tree after the second insert. i get an exception at this line if(dataIn <= nodeIn.getLeft().getData()){
I am confused as to what i did wrong.... here is my code for insert that i have. thanks in advance..
public void insert(int dataIn){
root = insert(root, dataIn);
}
private Node insert(Node nodeIn, int dataIn){
if(nodeIn==null){
nodeIn = new Node(null, null, dataIn);
}else{
if(dataIn <= nodeIn.getLeft().getData()){
nodeIn.setLeft(insert(nodeIn.getLeft(), dataIn));
}else{
nodeIn.setRight(insert(nodeIn.getRight(), dataIn));
}
}
return nodeIn;
}
Part of the reason it's confusing is that "Node" should not be a parameter to the insert method, you should be calling an insert method defined in node.
So let's say you hold the "Root" node in your "normal code"--let's call it "rootNode" just to be obscure.
Okay, so your code to insert into the tree would be:
rootNode.insert(newValue);
Easy enough.
Now to define that method.
public class Node {
private int value;
private Node lower;
private Node higher;
public void insert(int newValue) {
if (newValue < value)
if(lower == null)
lower=new Node(value);
else
lower.insert(newValue);
else
if(higher == null)
higher=new Node(value);
else
higher.insert(newValue);
}
// and you'll need a constructor
public Node(int value) {
this.value=value;
}
}
This should read much more clearly. I'm going to hit "Post" then I'm going to edit it and figure out how to easily refractor that evil evil copy & paste code.
On second thought, I'll leave it there because it's more readable. The best fix I can see is to make the nodes an array, then you get:
public class Node {
private int value;
private Node[] nodes=new Node[2];
private final int LOWER=0;
private final int HIGHER=1;
public void insert(int newValue) {
int index=LOWER;
if (newValue > value)
index=HIGHER;
if(nodes[index] == null)
nodes[index]=new Node(value);
else
nodes[index].insert(newValue);
}
}
But I won't replace the original because, as I said, it's clearer.
I recommend the refactoring book for more of this. It really does help simplify your code once you really get OO. Passing an object to an otherwise static method (one that doesn't use member variables) is a dead give-away.
With more considerations about #ted's comment and OO--getLeft and getRight shouldn't even be an issue. Neither is necessary outside the abstraction.
In general what you probably need is these methods in Node:
public boolean doesContain(int value) {
if(value == this.value)
return true
else
return nodes[ this.value < value ? LOWER : HIGHER].doesContain(value);
}
and maybe
public void getValuesSorted(LinkedList l) {
nodes[LOWER].getValuesSorted(l);
l.put(value);
nodes[HIGHER].getValuesSorted(l);
}
Then you don't even need to expose that it's a tree you are dealing with--beter OO abstraction.
You need to test whether nodeIn.getLeft() == null.
is the only way to have a Node class is to make it an inner static class? all the examples i see do this.
No.
The Node class doesn't need to be an inner or nested class. (Strictly speaking a "static inner" class is a nested class.)
However, only an inner or nested class can be private. If your Node class is a regular class you are exposing implementation details to (at least) other classes in the same package. This is a bad idea ... and that explains why you see the Node class declared the way it is.
you can use the below code to clear your understanding. Mostly we do not use any other class everything can be done inside a single Node class itself. here is a very basic example which i believe might be helpful... Also when i see you have two methods in which you have only provided data rather than root. Trust me it is better to have root in your main class. reasoning we have it handy where ever we need to cache.
public Node insert(Node root, Node newNode) {
if (root == null) {
root = newNode;
} else {
if(root.data > newNode.data) {
root.left = insert(root.left, newNode);
} else {
root.right = insert(root.right, newNode);
}
}
return root;
}
directly call this method from any class where you have initialized. here is a sample plz check..
Node root = new Node(10);
root.insert(root, new Node(5));
root.insert(root, new Node(3));
root.insert(root, new Node(6));
root.insert(root, new Node(1));
Instead of:
if (dataIn <= nodeIn.getLeft().getData()) {
... you want:
if (dataIn < nodeIn.getData()) {
You need to compare the value that is to be inserted with the value at the current node.
I changed the <= sign to a < sign so that duplicates are avoided.
So your code refactored is:
public void insert(int dataIn) {
root = insert(root, dataIn);
}
private Node insert(Node nodeIn, int dataIn){
if (nodeIn == null) {
nodeIn = new Node(null, null, dataIn);
} else {
if (dataIn < nodeIn.getData()) {
nodeIn.setLeft(insert(nodeIn.getLeft(), dataIn));
} else {
nodeIn.setRight(insert(nodeIn.getRight(), dataIn));
}
}
return nodeIn;
}
Actually, for a binary tree there is no need to check whether the inserting element is either greater than or left than the parent node. I think there is no need of checking those conditions. We have to take the input from user whether to insert right or left.
public class TreeNode
{
private int data;
private TreeNode left;
private TreeNode right;
public Tree( )
{
data = 0;
left = null;
right = null;
}
public Tree( int initialInfo, TreeNode initialLeft, TreeNode initialRight )
{
data = initialInfo;
left = initialLeft;
right = initialRight;
}
public void setLeft( TreeNode newLeft )
{
left = newLeft;
}
public void setRight( TreeNode newRight )
{
right = newRight;
}
public void insert( int element )
{
if( element <= data )
{
if( left == null )
setLeft( new TreeNode( element, null, null ) );
else
left.insert( element );
}
else
{
if( right == null )
setRight( new TreeNode( element, null, null ) );
else
right.insert( element );
}
}
}
All your solutions do not take into accoount what would happen if the node was to be inserted in the middle of the tree. You are assuming that it will also be smallest or greatest. When you insert something in the middle of the tree, then you will realize that the operation becomes more complex.
This is for homework but please know that I have looked online for help (such as http://www.sethi.org/classes/class_stuff/cis435/others/notes-java/data/collections/lists/simple-linked-list.html) and my textbook but I am still having some issues.
Any help would be appreciated...
Right now I'm trying to just insert values in but nothing is working. Whether it's the first item, whether it's being added as the last one, or somewhere in between.
Node header = null; // First element of list.
Node back = null; // Last element of list.
public void insert(int i, double value){ //insert value before i-th element
Node e = new Node();
e.num = value;
Node curr = header;
for(int x=0;x<i;x++) {
if (i == 1) { //we want to insert as first thing
if (size == 0) { //its the FIRST time we add something
header.next = e;
e.next = back;
break;
} else if (size == 1){
e.next = header.next; //i.e. the second thing in the list
header.next = e;
break;
} else {
e.next = header.next.next; //i.e. the second thing in the list
header.next = e;
break;
}
}
else if (x == (i-1)) {
e.next = curr.next;
curr.next = e;
break;
}
curr = curr.next;
}
size = size+1;
}
Not really sure why it isn't working.
Thanks!
For some reason, people who are still learning to program make things far more complicated then they need to be. I did it when I was learning java, I still do it when I am just getting into a new language, and students that I have marked find new and amazing ways to do it. You have more going on in your insert then there needs to be, for example, a method that inserts a value at a specific index should not check if it's the first item to be inserted (not saying it shouldn't check bounds). Here is the pseudo code of what I would do.
insert(index, value)
if index>size
throw null pointer
traverse to index -1 //lets call this nodeI
create newnode and set value
set newnode.next to nodeI.next
set nodeI.next to newnode
increase size.
Couple of handy hints for you, you should have a function to get an element from the link list, something that returns a node? public node elementAt(int index) for example? use that to traverse the linked list. If you want to append to the Linked list, try this
append(value)
insert(size-1,value)
and if you want to insert at the beginning? same idea
insert(value)
insert(0,value)
In the line e.next = header.next.next what would happen if header.next points to a 'null'? Is it possible to get there?
What are the corner cases you have to deal with and have you taken them all into account?
Can you start with the simplest case first, adding either an element to the front or an element to the back? Then use those functions to implement the insert?
A few suggestions:
implement java.util.List
Think about generics
Read this.
Start with "insert at the end" before you think about "insert at i".
I have tried a simple program, which will be useful for you guys, I am also learning Java, please bear with me for any mistakes, but this program works fine.
I am posting a very simple singly linked list program in Java, which I tried out today.
I hope it will help all.
LinkList.java
class LinkList
{
public static void main(String args[])
{
Node node = new Node(1);
node.addAtLast(2);
node.addAtLast(3);
node.addAtLast(4);
node.addAtLast(5);
node.printList();
}
}
Node.java
class Node
{
private int data;
private Node link;
public Node(int mydata)
{
data = mydata;
link = null;
}
public void printList()
{
System.out.print("|"+data+"|"+"->");
if(link != null)
{
//recursive call
link.printList();
}
else
{
//marking end of list as NULL
System.out.print("|NULL|");
}
}
public void addAtLast(int mydata)
{
if(link == null)
{
link = new Node(mydata);
}
else
{
link.addAtLast(mydata);
}
}
}
OUTPUT :
The below is our output
|1|->|2|->|3|->|4|->|5|->|NULL|