I need some help understanding how a method works.
I have a basic Node class defined like this:
class Node {
Node next = null;
int data;
public Node(int d){
data = d;
}
}
Now I'm looking at how this deleteDuplicates method is working. I understand that we are passing through each node iteratively and storing its value in a set. If the value is already in the set, I believe we are setting the previous node's next pointer to skip the current node. Here's the method:
public static Node deleteDuplicates(Node head){
Node n = head;
HashSet<Integer> set = new HashSet<Integer>();
Node previous = null;
while(n != null) {
if (set.contains(n.data)){
// skip this node
previous.next = n.next;
}
else {
set.add(n.data);
previous = n;
}
n = n.next;
}
return head;
}
I'm confused about the variables previous and n. When we set previous = n;, isn't that making them reference the same object? If they reference the same object, one change you make to n will be the same in previous. So how does the line previous.next = n.next; work?
Thanks!
read these 2 lines together,
previous = n;
n = n.next;
So, once a node is processed, the pointers for previous and n are moved forward. n is next node after previous, thus previous is set to n, and n is moved to its next node, which is n.next
For the deletion part, hope the diagram below helps
Related
I'm trying to add a node in a circular list in Java. The problem is that my list has only a head (without a tail). Here is my code:
import java.io.PrintStream;
import java.util.EmptyStackException;
public class CircularList {
private Node head = null;
private class Node {
public Node(String payload, Node prev, Node next) {
super();
this.payload = payload;
this.prev = prev;
this.next = next;
}
private Node prev;
private Node next;
String payload = "";
}
public void push(String payload) {
Node n = new Node(payload, null, null);
if (isEmpty()) {
head = n;
n.next = n;
} else {
n.prev = head;
n.next = head;
}
}
Lets take some nodes.
< H - < A - < B -
This describes the connections of the nodes. A.next == H and A.prev == B.
H and B are special cases, where H is the head and B is the tail. Since the list is circular. Then H.next == B and B.prev == H.
When we push a node.
< N - < H - < A - < B -
Then we can see all of the assignments that need to change.
H = head;
B = H.next; // get the tail since you only have the head.
H.next = N;
N.prev = H;
N.next = B;
B.prev = N;
head = N;
You're almost there. When the list is empty, that part works fine. But when the list is not empty, think through what needs to happen, which is 4 things:
The 'head's previous node needs to become the new node.
The new node's 'next' needs to point at head.
The new node's 'previous' needs to point at what used to be head.prev.
What used to be head.prev's next pointer needs to point at the new node.
You'll need some temp variables to take care of all of that.
Given input (items = 6, position = 3)
creates a row of 6 items and a character positioned on item 3 {0,1,2,[3],4,5}
A call to left() moves the character two positions to the left and the item at position 3 is removed {0,[1],2,4,5}
The next call to right() moves the character two positions to the right and the item at position 1 is removed {0,2,[4],5}
Then calling position() method now should return 4.
The character will not move to the left or right if no items are present so no need to implement that.
public class MyClass {
int position;
int[] items;
public MyClass(int n, int position) {
this.position = position;
items = new int[n];
for(int i=0; i<n; i++) {
items[i] = i;
}
}
}
public void left() {
int p = this.position;
items[p] = -1;
for(int z=0; z<2;) {
p--;
int value = arr[p];
if(value != -1) {
z++;
}
}
this.position = p;
}
public void right() {
int p = this.position;
items[p] = -1;
for(int z=0; z<2;) {
p++;
int value = arr[p];
if(value != -1) {
z++;
}
}
this.position = p;
}
public int position() {
return arr[position];
}
This code works perfectly for small inputs, but I am getting performance errors when the input is large.
How to implement this efficiently? I don't have test case details for the error related to performance errors.
As it already has been pointed outed both in the comments and the answer by #AbhinavMathur, in order to improve performance you need to implement Doubly linked list data structure.
Note that it's mandatory to create your own implementation that will maintain a reference to the current node. Attempt to utilize an implementation built-in in the JDK in place of the items array will not buy you anything because the advantage of the fast deletion will be nullified by the cost of iteration (in order to reach the element at position n, LinkedList needs to crawl through the n elements starting from the head, and this operation has a liner time complexity).
Methods left(), right() and position() will have the following outcome:
left() - in case when the previous node (denoted as prev in the code) associated with current is not null, and in tern its previous node exists, the current node will be dereferenced (i.e. next and previous nodes associated with the current node will be linked with each other), and the variable current would be assigned to the prev of the previous node, i.e. current.prev.prev. Time complexity O(1).
right() - in case when the next node (denoted as next in the code) associated with current is not null, and in tern its next node exists, the current node will be dereferenced in a way that has been described above, and the variable current would be assigned to the next of the next node, i.e. current.next.next. Time complexity O(1).
position() - will return a value of the current node. Time complexity O(1).
That's how it might look like:
public class MyClass {
private Node current; // a replacement for both position and items fields
public MyClass(int n, int position) {
Node current = new Node(0, null, null); // initialing the head node
if (position == 0) {
this.current = current;
}
for (int i = 1; i < n; i++) { // initialing the rest past of the linked list
Node nextNode = new Node(i, current, null);
current.setNext(nextNode);
current = nextNode;
if (position == i) {
this.current = current;
}
}
}
public void left() { // removes the current node and sets the current to the node 2 position to the left (`prev` of the `prev` node)
if (current.prev == null || current.prev.prev == null) {
return;
}
Node prev = current.prev;
Node next = current.next;
prev.setNext(next);
next.setPrev(prev);
this.current = prev.prev;
}
public void right() { // removes the current node and sets the current to the node 2 position to the right (`next` of the `next` node)
if (current.next == null || current.next.next == null) {
return;
}
Node prev = current.prev;
Node next = current.next;
prev.setNext(next);
next.setPrev(prev);
this.current = next.next;
}
public int position() {
return current.getValue();
}
public static class Node {
private int value;
private Node prev;
private Node next;
public Node(int value, Node prev, Node next) {
this.value = value;
this.prev = prev;
this.next = next;
}
// getters and setters
}
}
A link to Online Demo
Using an array, you're setting the "removed" elements as -1; repeatedly skipping them in each traversal causes the performance penalty.
Instead of an array, use a doubly linked list. Each removal can be easily done in O(1) time, and each left/right operation would only require shifting the current pointer by 2 nodes.
I am trying to calculate a sum of each branch of a binary tree without using recursion. I'm trying to use a stack and can't figure out how to fix my code to get the right sums.
public static List<Integer> branchSums(BinaryTree root) {
LinkedList<BinaryTree> toVisit = new LinkedList<>();
BinaryTree current = root;
List<Integer> sums = new ArrayList<>();
int sum = 0;
while (current != null || !toVisit.isEmpty()) {
while (current != null) {
sum += current.value;
toVisit.push(current);
current = current.left;
}
current = toVisit.pop();
// if found leaf add sum to results and decrement sum by current node
if (current.left == null && current.right == null) {
sums.add(sum);
sum -= current.value;
}
current = current.right;
}
return sums;
}
Example input:
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ /
8 9 10
Example output [15, 16, 18, 10, 11]
Issue with your code is you are not keeping track of the node which
has been last popped from your stack.
Here is the updated code:
public static List<Integer> caculateSum(BinaryTree root) {
List<Integer> sums = new ArrayList<>();
int sum=0;
BinaryTree current = root, popped=null;
Stack<BinaryTree> s = new Stack<BinaryTree>();
while(current!=null ) {
//checking if last node popped from stack is not equal to left or right node of current node
if(popped==null||((current.left!=null && !current.left.equals(popped)) && (current.right!=null && !current.right.equals(popped)))) {
while(current != null) {
sum+=current.value;
s.push(current);
current = current.left;
}
}
current=s.peek();
if(current.right == null) {
//if current node is leaf node
if(current.left == null) {
sums.add(sum);
}
sum-=current.value;
popped = current;
s.pop();
} else if(current.right!=null && current.right.equals(popped)){
//if current node both left and right nodes have been processed
sum-=current.value;
popped = current;
s.pop();
}else {
//if current node right part is not processed
sum+=current.right.value;
s.push(current.right);
}
if(s.isEmpty()) {
break;
}
current=s.peek();
}
return sums;
}
Will explain this by taking an example. Suppose we have given binary tree
1,2,9,3,7,null,8,5
Here in above code apart from old variables a new variable popped is used which keeps track of last element which is popped out from stack.
So, following are the major steps :
Starting from current node first we are checking if current node left is not equal to popped (if it is equal it means that current node left part is already processed so we don't need to process it again). Same we are checking if current node right node is not equal to popped node (if it is equal it means we have already processed right node of current node which indirectly means left node is also processed).
Now for the top node of stack which is current node we check :
If its right node is null If it is true it means either current
node is leaf node or it is an already processed node whose right
node is null (like in our example node with value of 3). If it is
leaf we add it in our sums list. Also, for both cases we remove
this top node and subtract its value from current sum value
(This thing has been done in above code as well) .Along with this we
will keep track of popped element from stack in popped variable.
If its right is not null but its right node is equal to popped
node This happens when in last pass of while loop we had processed
this right node. This means for top node of stack both left and
right node have been processed and hence we pop this node and keep
track of it in popped variable.
Else we push the right node of top element of stack in stack.
At the end for above example , sums variable will store result as [11, 10, 18]
I attempted this for fun and was surprised I didn't see any actual solutions. The following is in Kotlin but can easily be transcribed into Java. The trick was to add state to the Node itself to mark it as consumed before you popped it, otherwise there was no value there to check when going down another branch.
This might be useful in super rare cases to prevent stack overflow? This will still run in O(N) but takes more space with the stacks, and will visit a node twice, once to traverse and once to pop.
open class BinaryTree(value: Int) {
var value = value
var left: BinaryTree? = null
var right: BinaryTree? = null
var consumed: Boolean = false
}
fun branchSums(root: BinaryTree): List<Int> {
var sumList = ArrayList<Int>()
var nodeStack = ArrayList<BinaryTree>()
var valueStack = ArrayList<Int>()
nodeStack.add(root)
while(!nodeStack.isEmpty()) {
val node = nodeStack.get(nodeStack.size-1)
if (node.consumed) {
valueStack.removeAt(valueStack.size - 1)
nodeStack.removeAt(nodeStack.size - 1)
continue
}
valueStack.add(node.value)
if (node.right == null && node.left == null) {
var sum = 0
for (value in valueStack) {
sum += value
}
sumList.add(sum)
}
if (node.right != null) {
nodeStack.add(node.right!!)
}
if (node.left != null) {
nodeStack.add(node.left!!)
}
node.consumed = true
}
return sumList
}
You can have this method:
public static int getBranchSum(Node root){
Queue<Node> q = new LinkedList<>();
q.add(root);
int sum=0;
while (!q.isEmpty()) {
Node curNode = q.poll();
sum+=curNode.data;
if(curNode.left==null || curNode.right==null)
curNode.visited=true;
if(curNode.left != null && curNode.left.visited)
curNode.visited=true;
if(curNode.left!=null && !curNode.left.visited)
q.add(curNode.left);
else if(curNode.right!=null && !curNode.right.visited)
q.add(curNode.right);
}
root.visited=false;
return sum;
}
Then call it below in a while loop as long as the output is not equal the root data.
boolean flag=true;
List<Integer> list = new ArrayList<>();
while(flag){
int result =getBranchSum(root);
if(result == root.data)
flag=false;
else
list.add(result);
}
System.out.println(list);
However the above the working only if we have a visited boolean in the node:
class Node{
Node left,right;
int data;
boolean visited = false;
Node(int data){
this.data=data;
left=right=null;
}
Branch sum without recursion
def branchSums(root):
cs=0
stack=[{"node":root,"cs":cs}]
sums=[]
while(len(stack)>0):
node_info=stack.pop()
node,cs=node_info["node"],node_info["cs"]
if node is None:
continue
cs=cs+node.value
if node.left is None and node.right is None:
sums.append(cs)
print(sums)
stack.append({"node":node.right,"cs":cs})
stack.append({"node":node.left,"cs":cs})
return sums
can someone please tell me if I am correct? I am studying for a midterm.
x is a variable pointing to a linked-list node and not the last node on the
list. t points to a new node that is not in the list.
x.next = t;
t.next = x.next;
I believe when it comes time to update t.next, x.next is no longer the original node following x, but is instead t itself. So it create a cycle in the list
t = x.next
x = t;
I believe this does nothing to the list.
Thank you in advance!!
You can also do it threadsafe like this:
t.next = x.next; // let t and x point to the SAME next.
x.next = t; // change the x.next to t(who has the old next)
In this case store node in temp variable. It won't create the cycle.
Object temp = x.next;
x.next = t;
t.next = temp;
First you have list like this..
X--->Y----->Z-->
You want to insert a node t after X
Right now t is
t---->null
Step 1- Now we have temp pointing to X's next
x---->y----->z----->
^
|
temp--
Step 2- Now x's next is pointing to t
x----->t---->
now main list is like this
temp---->y---->z---->
Step 3- Now t's next is pointing to temp which is only next pointer
temp---->y--->z---->
^
|
----------
|
x---->t---
So resulting list is
x--->t---->y---->z----->
You already have object x. This probably the current last element of the linked list. Now, you create a new object T and link it as the element after X
X // Lets assume X.next == NULL. So linked list looks like this X -> Null
X.next = T // Now X.next == T and T.Next == NULL, So linked list looks like this X -> T -> Null.
T.next = X.next // Now T.next == T. So linked list is X -> T <->T
This way, when you reach the end of the linked list, it will always return the last element instead of returning NULL.
If you are writing a simple algorithm for this, first you have to create an element and then point its next variable to it self.<First_element>.next = <First_element>. So the logic will work for all the instances.
Here is a simple experiment.
class Node{
Node next = null;
int id =-1;
}
public class LinkedList{
public static void main (String args[]){
Node x = new Node();
x.id = 0;
x.next = x;
// Now add a new element
Node t = new Node();
t.id =1;
x.next = t;
t.next = x.next; // Now we have a linked list of 2 elements
Node mynode = x;//First element of linked list
for(int i =0; i < 3; i++){
System.out.println(mynode.id);
mynode = mynode.next;
}
}
}
Output:
0
1
1
I am practicing linked list programming questions in java, i have a working solution for the following question but cannot understand how it works.
I have commented beside each line what I think should be happening but obviously I haven't grasped how these are working yet, could someone please explain where my comments are wrong and how this solution is correct.(in my comments i use h for head, s for slow etc.)
Given a linked list, swap every two adjacent nodes and return its head.
Example:
Given 1->2->3->4, you should return the list as 2->1->4->3.
public Node s(Node head) {
// 1(h)-2-3-4 passed in
// if only 1 node or null node return it
if (head == null || head.next == null) {
return head;
}
Node slow = head.next; // 1h-2s-3-4
head.next = head.next.next; // 1h-3-4
slow.next = head; // 2s-1h-3-4
head = slow; // 2s/h-1-3-4
Node parent = slow.next; // 1p-3-4
slow = slow.next.next; // 3s-4
while (slow != null && slow.next != null) {
Node temp = slow.next; // 4t-null
slow.next = slow.next.next; // 3s-null
temp.next = slow; // 4t-3s-null
parent.next = temp; // 1p-4-3
parent = parent.next.next; // 3p=null
slow = slow.next; // 4-null, loop ends cause next to slow is null
}
return head; // ( head = slow from earlier) 4-null
}
Let's assume a linked list of A -> B -> C -> D.
I've numbered the lines in your code to make it easier to talk about.
1 public Node s(Node head) {
2 // if only 1 node or null node return it
3 if (head == null || head.next == null) {
4 return head;
5 }
6
7 Node slow = head.next;
8 head.next = head.next.next;
9 slow.next = head;
10 head = slow;
11 Node parent = slow.next;
12 slow = slow.next.next;
13
14 while (slow != null && slow.next != null) {
15 Node temp = slow.next;
16 slow.next = slow.next.next;
17 temp.next = slow;
18 parent.next = temp;
19 parent = parent.next.next;
20 slow = slow.next;
21 }
22 return head;
23 }
At line 7, slow is made to point to node B. head.next is set to B's successor, C on line 8. On line 9, B points to A, and on line 10, head points to B. My comments show what happened.
7 Node slow = head.next; // slow = B
8 head.next = head.next.next; // head.next = C
9 slow.next = head; // B.next = A (because head points to A)
10 head = slow; // head = B
That code swapped the first two nodes. Your list now looks like this:
B -> A -> C -> D
Now the code gets kind of confusing, largely due to poor naming. slow currently points to B.
11 Node parent = slow.next; // parent = A
12 slow = slow.next.next; // slow = C
Remember that slow now points to C. Here's what happens next:
14 while (slow != null && slow.next != null) {
15 Node temp = slow.next; // temp = D
16 slow.next = slow.next.next; // C.next = D.next (which is null)
17 temp.next = slow; // D.next = C
18 parent.next = temp; // A.next = D
At this point, nodes C and D have been swapped, and A points to D, as required. The list now looks like B -> A -> D -> C.
The final two lines in the loop just set things up for next time. Remember, that right now, parent points to A.
19 parent = parent.next.next; // parent = C
20 slow = slow.next; // slow = null
Looping back to the top, we see that slow == null, so the loop exits.
Whereas the code you posted works, it's unnecessarily confusing. There's no need to do a special swap of the first two nodes before going into the loop, and variable names could be more descriptive.
To swap two nodes, you have to make the second point to the first, and the first point to the second's successor. To do that, you have to save the second's successor before you overwrite it. For example, if you have A -> B -> C and you want B -> A -> C, then you have to do this, assuming that head points to A:
firstNode = head // firstNode points to A
secondNode = firstNode.next // secondNode points to B
secondNodeSuccessor = secondNode.next // this points to C
secondNode.next = firstNode // B now points to A
firstNode.next = secondNodeSuccessor // A now points to C
head = secondNode // and head points to B
At this point, secondNodeSuccessor is pointing to C, which is the next firstNode.
With that understanding of how to swap nodes, you can simplify the code quite a bit:
public Node s(Node head) {
// if fewer than 2 nodes, return.
if (head == null || head == null) {
return head;
}
// we know that the new head will be the second node.
Node firstNode = head;
Node parentNode = null;
while (firstNode != null && firstNode.next != null) {
Node secondNode = firstNode.next;
Node secondNodeSuccessor = secondNode.next;
// swap the nodes
secondNode.next = firstNode;
firstNode.next = secondNodeSuccessor;
if (parentNode != null) {
// This links the previous node (the one right before
// the two that we just swapped) to the swapped nodes.
parentNode.next = secondNode;
}
// the new parent node is the last swapped node.
parentNode = firstNode;
firstNode = firstNode.next; // set up for next pair
}
return head.next;
}
Note the improvements here:
I eliminated the special-case swap of the first two nodes, which simplifies things by making every swap the same.
Meaningful variable names make it plain which node I'm referencing.
Eliminating the .next.next construction makes it easier to reason about the code, and also makes it easier to determine whether the code could potentially dereference a null.
Your debugger is a very useful tool for understanding how your code is working. If you were to single-step the code in your debugger, you could examine the variables and see how each line of code affects the state. If you don't know how to use your debugger, you should take the time right now to learn. It will save you hours of debugging, and also greatly increase your understanding of how code works.
In place of swapping nodes, we can swap data only that will be easy and will get the desired output.
public Node s(Node head) {
if (head == null || head.next == null) {
return head;
}
Node temp = head;
/* Traverse only till there are atleast 2 nodes left */
while (temp != null && temp.next != null) {
/* Swap the data */
int k = temp.data;
temp.data = temp.next.data;
temp.next.data = k;
temp = temp.next.next;
}
return head;
}
The other two solutions either don't match your requirements or provide wrong results for some inputs.
I propose an alternative approach that I have tested on LeetCode (if you want to test it yourself, please be sure to rename the Node type into ListNode).
I hope the comments I added to the code are clear enough. When in doubt, I suggest trying to execute this procedure in an interactive debugger.
public ListNode s(Node head) {
// if the list is empty or it's a singleton, no node needs to be swapped
if (head == null || head.next == null) {
return head;
}
// first and second are the first and second node of the current pair to swap
Node first = head;
Node second = head.next;
// parent is the node immediately before the current pair.
// Initially, there is no such pair
Node parent = null;
// the updated list starts from the second node of the first pair
head = second;
// iterate until there is a valid pair to swap
while (first != null && second != null) {
// swap the two nodes of the current pair
first.next = second.next;
second.next = first;
if (parent != null) {
// attach the second element to the updated node of the previous pair
parent.next = second;
}
// keep the invariant of parent valid: parent precedes the new pair to swap,
// if such a pair exists
parent = first;
// advance the pointers of the first and second elements of the new pair to swap
first = first.next;
second = (first == null) ? null : first.next;
}
return head;
}