Linked List - Keeping track of each node - algorithm

I found an algorithm to loop through a sorted linked list and remove the duplicate. I wrote it, it works.
Still, I don't understand how can this work. In the end of the loop, to move forward into the while loop, we do this :
currentNode = nextNode
How can this not erase the current node ? Why does the linked list is still here ? It feels every node is erased each time by the next, isn't it ?
class LinkedList {
constructor(value) {
this.value = value;
this.next = null;
}
}
function removeDuplicatesFromLinkedList(linkedList) {
let currentNode = linkedList;
while(currentNode !== null){
let nextNode = currentNode.next;
while(nextNode !== null && nextNode.value === currentNode.value){
nextNode = nextNode.next;
}
currentNode.next = nextNode
currentNode= nextNode
}
currentNode = linkedList;
return linkedList;
}
exports.LinkedList = LinkedList;
exports.removeDuplicatesFromLinkedList = removeDuplicatesFromLinkedList;

In fact, linkedList is never overwritten, so the initial list isn't damaged (because when removing duplicates, the first one is kept, only the following are removed).
Then, currNode is just the current pointer, to the current node. Assign a new value to it don't delete the previous node, since it's still referenced through the list head linkedList.
What is really missing is the free instruction on deleted node - this algo rely on a garbage collector to work without a memory leak.

Let's do this by an example:
2 -> 3 -> 3 -> 4
Initially currentNode == 2. In the first iteration of the loop nextNode == 3, which is the next node to current node. The inner while loop doesn't run since currentNode.value isn't equal to nextNode.value. So we hit:
currentNode.next = nextNode
currentNode= nextNode
This sets the next node of currentNode to NextNode. So, nothing changes. Then we move current node one forward: currentNode = nextNode
In the next iteration though, nextNode == 3, while currentNode == 3 too. Now the inner while loop runs one iteration and moves nextNode to 4 and breaks since they aren't equal anymore. Then, currentNode.next is set to nextNode, which was 4, and after nextNode is assigned to currentNode.
Since these are all pointers to nodes, nothing is being erased. Just the duplicate values are removed from the chain of linked nodes.

Related

Find the maximum sum of first and last element of a linked list

Given a singly linked list where each element contains a number and a pointer to the head of the list. Sum the first and last data and remove these nodes. Then sum the first and last data of the resulting linked list and remove these two nodes.
Keep doing this till the list becomes empty.
we have to find the maximum sum obtained from the resulting sum in O(1) space complexity.
The list is a singly linked list with even nodes.
My Thoughts:
One approach is to move the pointer to the last element at each iteration, remove the nodes, and keep a maxSum variable. This probably won't be an efficient solution.
If I understood correctly, a node in this linked list has two pointers: a pointer to the next node and one to the first node in the list.
There are several ways to solve this. Here is one:
Walk through the list and change the head pointer in each node to reference the previous node: this will give you a doubly linked list. Retain a pointer to the last node.
Now you can do a traversal in tandem starting at both ends of the list and walking towards each other.
Deleting nodes during that traversal is not really required. You could even restore the list to what it was originally in the second step.
It is even possible to do this without this extra head pointer in each node. In that case reverse the second half of the list.
Here is an implementation of the first idea, in JavaScript:
class Node {
constructor(data, head) {
this.data = data;
this.head = head || this; // default is node itself
this.next = null;
}
}
function createList(...values) {
if (!values) return null;
let head = new Node(values.shift()); // First value
let tail = head;
for (let value of values) { // Remaining values
tail.next = new Node(value, head);
tail = tail.next;
}
return tail.head;
}
function maxPairSum(head) {
if (!head) return -Infinity;
// Make doubly linked list, (ab)using node's head member
let tail;
for (tail = head; tail.next; tail = tail.next) {
tail.next.head = tail; // Next gets reference to previous
}
// Tandem walk, towards center
let maxSum = -Infinity;
for (let curr = head; curr != tail && curr != tail.next; curr = curr.next) {
maxSum = Math.max(maxSum, curr.data + tail.data);
tail = tail.head; // Is actually a reference to previous
}
// Restore head references (optional)
for (let curr = head; curr; curr = curr.next) {
curr.head = head;
}
return maxSum;
}
// Example run
let head = createList(2, 5, 1, 5, 4, 6);
let maxSum = maxPairSum(head);
console.log(maxSum); // 9
... And if you want to really remove the list, just clear the head reference. In JavaScript the garbage collector will free the unreachable memory; in some other languages (like C) you'll need to explicitly free the memory occupied by each node, before clearing the reference to the head node.
private static int max = 0, count = 0;
private static LinkedList top;
static int maximumPagesRec(LinkedList tail) {
if(tail.next==null)
max = max<top.data + tail.data ?top.data + tail.data: max;
else if(tail == top && count++ !=0){
max = max<top.data ?tail.data: max;
}
else if(top.next == tail && count++!=1)
max = max<top.data + tail.data ?top.data + tail.data: max;
else {
maximumPagesRec(tail.next);
}
top = top.next;
return max;
}
static int maximumPages(LinkedList head)
{ top = head;
return maximumPagesRec(head);
}
how about pushing all linked list value element to a stack, take 1->2->3->4 for example, and the stack will be 1234.
after that, we sum one by one and delete each linked list, store maximum value we got.

Linked list addition (of total size n) and reversion of last k nods at order of n

I am looking at this challenge:
Given are numbers m and p, which both may be as large as 250000. The next m lines have one of the following commands:
APPEND y, which adds y to the end of our list (queue)
ROTATE, which reverses the p last elements of the list. If the list has fewer than p elements, it reverses all of the elements of the list.
Our job is to print the list after all commands have been executed.
A brute force approach is to reverse the array manually, which would have a complexity of O(pm), but you are required to implement it with a complexity of O(m).
I have thought about using a doubly linked list, and I am quite sure it would work, but I could not complete my answer.
Example
Input
8 3
APPEND 1
APPEND 2
APPEND 3
APPEND 4
ROTATE
APPEND 5
APPEND 6
ROTATE
Output
1 4 3 6 5 2
The idea of a doubly linked list is correct. To make it work you need to step away from prev/next notions, but just keep track of the potential 2 neighbours a node may have, without any indication of direction (prev/next).
Your doubly linked list will have a head and a tail -- that must stay. And you are right to also maintain a reference to the node that is currently the start node of the "k last elements" (or fewer when there are not that many elements in the list). Keep that updated whenever you add a node. In order to know in which direction to move that reference, also maintain a reference to the node that precedes it.
Then, when a reversal needs to be performed, it is a matter of swapping the references (and back-references) to the head and tail of that "k last element" sublist. Don't go over the whole sublist to change links between each pair of consecutive nodes. By removing the idea of prev/next, you can just leave those "internal" links as they are. Whenever you need to iterate through the list, you will always know which side you are coming from (i.e. what the "previous" node was), and so you can derive which of the neighbours must be the "next" one.
Here is an implementation of that idea in JavaScript. At the end of the code the algorithm is executed for the example input you have given:
class Node {
constructor(x, neighbor1=null, neighbor2=null) {
this.x = x;
this.neighbors = [neighbor1, neighbor2]; // No specific order...
}
opposite(neighbor) {
// Return the neighbor that is on the other side of the argument-neighbor
return this.neighbors[1 - this.neighbors.indexOf(neighbor)];
}
replaceNeighbor(find, repl) {
let i = this.neighbors.indexOf(find);
this.neighbors[i] = repl;
}
}
class List {
constructor(k) {
this.nodeCount = 0;
this.k = k;
// All node references are null:
this.head = this.tail = this.tailBeforeLastK = this.headOfLastK = null;
}
add(x) {
this.nodeCount++;
let node = new Node(x, this.tail, null);
if (this.head === null) {
this.headOfLastK = this.head = this.tail = node;
return;
}
this.tail.replaceNeighbor(null, node);
this.tail = node;
if (this.nodeCount > this.k) { // Move the head of the "last K" sublist
[this.tailBeforeLastK, this.headOfLastK] =
[this.headOfLastK, this.headOfLastK.opposite(this.tailBeforeLastK)];
}
}
reverse() {
if (this.nodeCount < 2 || this.k < 2) return;
// Exchange the links to the start/end of the K-last sublist
this.tail.replaceNeighbor(null, this.tailBeforeLastK);
if (this.tailBeforeLastK) {
this.tailBeforeLastK.replaceNeighbor(this.headOfLastK, this.tail);
this.headOfLastK.replaceNeighbor(this.tailBeforeLastK, null);
}
else this.head = this.tail;
// Swap
[this.tail, this.headOfLastK] = [this.headOfLastK, this.tail];
}
toArray() {
let result = [];
for (let prev = null, node = this.head; node; [prev, node] =
[node, node.opposite(prev)]) {
result.push(node.x);
}
return result;
}
}
// Example
let k = 3;
// null means: REVERSE, a number means: ADD <number>:
let actions = [1, 2, 3, 4, null, 5, 6, null];
let list = new List(k);
for (let action of actions) {
if (action === null) list.reverse();
else list.add(action);
}
console.log(list.toArray());

Deleting nodes greater than specified value from linked list

Given an integer value and a pointer to the head of the linked list, how to delete all the nodes from the list that are greater than the specified value?
e.g.
List : 10->34->11->19->26->55->17
value: 19
output: 10->11->17 (All the nodes greater than 19 needs to be removed)
(Edge case)
List : 10->3->17->5->2->14->7
value: 9
output: 3->5->2->7 (All the nodes greater than 9 needs to be removed)
I am not looking for the exact code but just an algorithm to solve this!
private static Node removeNodes(Node start, int x) {
if(start == null) return start;
if(start.data > x && start.next == null) return null;
//find first head node
Node cur = start;
Node prev = null;
//4,5,3,2,1,6 --- where x = 2
while(cur != null && cur.data > x) {
prev = cur;
cur = cur.next;
}
if(prev != null) prev.next = null;
Node newHead = cur;
while(cur.next != null) {
if(cur.next.data > x) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return newHead;
}
first assign a temporary node to the start node
Then you have three cases in linked list..
if the desired node at the first position then make start to be equal start->next and delete temp node
if it is in the middle make another node to be stopped right before temp and make the next of that node to be equal the next of temp and then delete temp
if it is at last position make the next of the node before it to be equal to nullptr and that is it.
It can be solved using two pointers, previous and current,I guess this solution work.
public static ListNode removeNode(ListNode head,int value){
//removing every element whose Node value is greter than given value
if(head==null) { return head;}
ListNode current=head;
ListNode previous=new ListNode(0);
previous.next=current;
while(current!=null){
//System.out.println("current value; "+current.val);
if(current.val>=value){
if(current.next==null){
current=null;
}
else {
current=current.next;}
previous.next=current;
}
else {
previous=previous.next;
current=current.next;
}
}
return head;
}
Consider the picture here .Suppose we have to delete the node which is greater than 8 and we have Head Pointer pointing to head of the list.First we will take two pointers Prev and temp both points to head initially.Then through the pointer we will traverse the list and keep track the current and prev pointers in temp and Prev.If current number is greater than 8 Prev will point to the next node pointed by temp and temp node will be deleted.By traversing all the node and following this rule you can delete the specified node of the list....
I hope you got the point........

is wikipedia iterative postorder tree traversal pseudo code wrong?

Here is the pseudo code that wikipedia gives for iterative postorder tree traversal.
iterativePostorder(node)
parentStack = empty stack
lastnodevisited = null
while (not parentStack.isEmpty() or node ≠ null)
if (node ≠ null)
parentStack.push(node)
node = node.left
else
peeknode = parentStack.peek()
if (peeknode.right ≠ null and lastnodevisited ≠ peeknode.right)
/* if right child exists AND traversing node from left child, move right */
node = peeknode.right
else
visit(peeknode)
lastnodevisited = parentStack.pop()
It is pretty straight forward, and I have implemented it in Java. But it does not work, the problem is that every time it visits the most left leaf and return to its parent, it will add that left leaf again into the stack in next iteration. This causes an infinite loop. Is my method incorrect or the wikipedia version is wrong?
public static List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) return res;
Stack<TreeNode> s = new Stack<TreeNode>();
TreeNode lastVisitedNode = null;
TreeNode curr = root;
int i = 0;
while (curr != null || !s.isEmpty()) {
if (curr != null) {
System.out.println("push " + curr.val);
s.push(curr);
curr = curr.left;
} else {
curr = s.peek();
if (curr.right != null && lastVisitedNode != curr.right) {
curr = curr.right;
} else {
res.add(curr.val);
System.out.println("pop " + curr.val);
lastVisitedNode = s.pop();
}
}
System.out.println(s);
System.out.println(res);
if (i>8) break;
else i++;
}
return res;
}
The wikipedia version is wrong for the exact same reason as you've explained it.
Here is a probably better pseudo-code, from geeksforgeeks
1.1 Create an empty stack
2.1 Do following while root is not NULL
a) Push root's right child and then root to stack.
b) Set root as root's left child.
2.2 Pop an item from stack and set it as root.
a) If the popped item has a right child and the right child
is at top of stack, then remove the right child from stack,
push the root back and set root as root's right child.
b) Else print root's data and set root as NULL.
2.3 Repeat steps 2.1 and 2.2 while stack is not empty.
You will have to add extra code to check if the node right child is null in 2.1.a though.
The wikipedia pseudocode is not wrong. They use two different variables: node and peekNode, while you only use curr for both. Node == null refers to the case when there is no more of a left branch left to explore, so we can stop pushing and instead investigate the next element in the stack. You can either revert to using two different variables, or you make the following fix in your code:
Since you reassign curr to a non-null value everytime you investigate the stack, you need to reset curr to null after you visit your node. (Because the state that still no more left branch left to explore is still unchanged).
The wikipedia pseudocode doesn't have to do this because their node value remains null.
Here is my code which gives a perfect answer:
var currentNode = this.root()
var previousNode = null
while(!nodeStack.isEmpty() || currentNode) {
// If there is a node on which the recursive call is made, we have a subtree to explore. If this is null, we have to backtrack and do a callback.
if (currentNode) {
nodeStack.push(currentNode)
previousNode = currentNode
currentNode = currentNode.leftChild
} else {
currentNode = nodeStack.peek()
if (currentNode.rightChild && previousNode != currentNode.rightChild) {
currentNode = currentNode.rightChild
} else {
callback(currentNode)
currentNode = null
previousNode = nodeStack.pop()
}
}
}

Traversing two trees together?

I am looking a lot of interview problems where the question requires traversing two trees together, I am not sure exactly how to go about doing this.
e.g.
Given references to roots of two binary trees, how do you determine
whether the sequence of the leaf elements equal but you must
implement short circuiting return when the first node violates the
rule.
Is your question asking to find out whether:
"the sequence created by visiting all the leaf nodes of 2 trees is same"
with a constraint that when found a mismatch of leaf values, then we must quit immediately.
If so, I propose following solution:
insert (root of tree1) in stack1
insert (root of tree2) in stack2
temp1 = (root of tree1) -> left child
temp2 = (root of tree2) -> left child
while(stack1 and stack2 arent empty)
{
found = false
while(found == false) {
if (temp1 is leaf node)
child1 = value of temp1
found = true
pop element from stack1
set temp1 to its right child
if (temp1 has left child)
put temp1 in stack1
set temp1 to its left child
}
found = false
while(found == false) {
if (temp2 is leaf node)
child2 = value of temp2
found = true
pop element from stack2
set temp2 to its right child
if (temp2 has left child)
put temp2 in stack2
set temp2 to its left child
}
if(child1 != child2)
return
}
One possible solution:
I have created a tree class which has a method GetNextLeafNode(). This is responsible for returning the next immediate leaf node of a tree.
With the tree class I am keeping a stack to maintain the traversed elements
In the GetNextLeafNode() method, I am doing iterative tree traversal (Pre order).
Whenever I encounter a node(stack.Pop()) which is leaf I am just returning it. Otherwise I am pushing left and right pointers to the stack. Initially root node is pushed. At any time state of stack is proper.
Here is the code in C#:
public TreeNode GetNextLeafNode()
{
TreeNode leaf = null;
while (s.Count != 0)
{
TreeNode n = s.Pop();
if ((n.Left == null) && (n.Right == null))
{
leaf = n;
return leaf;
}
else
{
if (n.Right != null)
s.Push(n.Right);
if (n.Left != null)
s.Push(n.Left);
}
}
return leaf;
}
Now, we can create two different trees say, t1 and t2.
We can do the comparision as follows:
int data1 = t1.GetNextLeafNode().Data;
int data2 = t2.GetNextLeafNode().Data;
while (data1 == data2)
{
//both the leaf nodes are same.
data1 = t1.GetNextLeafNode().Data;
data2 = t2.GetNextLeafNode().Data;
}
In pseudo-code:
Go down to the first leaf (let's say left-most) in each tree.
Compare.
If not equal RETURN error.
Step to the next leaf in each tree (intuitively -- go up until you see a way to step to the right child, then take only left children on your way till you reach a leaf).
If one of the trees has a leaf but another returned to root RETURN error.
If both trees returned to root RETURN success.
Go to step 2.
A simple python solution.
Though this is not space optimal as we are storing leaves that can be O(N+M). This is not iterating both the trees together.
Time complexity - O(N+M).
You can also think of a solution where space is O(max(N,M)) in a similar fashion.
def binaryTreeLeafs(root1, root2):
# The order in which we see leaves will
# be maintained as it is inorder traversal.
def dfs(node, leaves):
if not node:
return
if not node.left and not node.right:
leaves.append(node.val)
return
dfs(node.left, leaves)
dfs(node.right, leaves)
leaves1 = []
leaves2 = []
dfs(root1, leaves1)
dfs(root2, leaves2)
return leaves1 == leaves2
# O(h1+h2) space
def binaryTreeLeaves2(root1, root2):
def isLeaf(node):
return not node or node.left == node.right == None
if not root1 and not root2:
return True
if (not root1) ^ (not root2):
return False
stack1 = [root1]
stack2 = [root2]
while stack1 or stack2:
if (not stack1) ^ (not stack2):
return False
tmp1 = stack1.pop()
while not isLeaf(tmp1):
if tmp1.right:
stack1.append(tmp1.right)
if tmp1.left:
stack1.append(tmp1.left)
tmp1 = stack1.pop()
tmp2 = stack2.pop()
while not isLeaf(tmp2):
if tmp2.right:
stack2.append(tmp2.right)
if tmp2.left:
stack2.append(tmp2.left)
tmp2 = stack2.pop()
if ((not tmp1) ^ (not tmp2)) or (tmp1 and tmp2 and tmp1.val != tmp2.val):
return False
return True

Resources