How and where is the "head" list initialized? - java

How and where is the head list implemented in task 83 on leetcode? Where is it initialized? Can you please write the code for this in what it would look like in a regular editor?
Here is the solution:
public ListNode deleteDuplicates(ListNode head) {
if(head==null || head.next==null)return head;
ListNode node=head;
while(head!=null && head.next!=null){
if(head.val==head.next.val){
head.next=head.next.next;
}
else head=head.next;
}
return node;`
}

How and where is the head list implemented
In Computer science, the first Node of a Linked list is usually called the head (see: Linked list - Basic concepts and nomenclature).
And head an instance of Node class (a building block of the Linked list data structure), like any other node.
Method deleteDuplicates() expects an instance of Node which should be provided by the caller (i.e. a part of the code that uses deleteDuplicates()).
And by the way, it's a good practice to avoid mutating arguments, therefore it would be cleaner to use node reference to iterate through the list and preserve the head intact. This way it's more obvious that method returns precisely the same reference to the beginning of the list that has been passed to it.
public ListNode deleteDuplicates(ListNode head) {
if (head == null || head.next == null) return head;
ListNode node = head;
while (node != null && node.next != null) {
if (node.val == node.next.val) {
node.next = node.next.next;
} else node = node.next;
}
return head;
}

Looking at the first example, the calling code might look like this:
ListNode source = new ListNode(1, new ListNode(1, new ListNode(2)));
ListNode result = new Solution().deleteDuplicates(source);
// code that checks that result is a list of two elements and contains 1 and 2 in that order

Related

Head is getting reversed in a linked list for a palindrome validation algo

I am trying to write an algorithm that checks if an input LinkedList is a palindrome or not. My algorithm is as follows:
Set a dummy node to point to the head of the input linkedList
Use a handler to store the reversed linkedlist
Run a loop to compare the values from front and back
My error: I know that the algorithm is wrong, because the output that I get seems to say that my original head is pointing in the wrong direction. I cannot figure out why, since I have used handler nodes while reversing as well.
The code is as follows:
class Solution {
public boolean isPalindrome(ListNode head) {
if(head==null) return true;
ListNode dummy = head;
ListNode MatchList = null;
MatchList=reverseList(head);
while(dummy!=null)
{
if(dummy.val!=MatchList.val)
{return false;}
MatchList=MatchList.next;
dummy=dummy.next;
}
return true;
}
public ListNode reverseList(ListNode head) {
ListNode dummy, newHead;
newHead=head;
ListNode another=newHead;
ListNode prev=null;
while(another!=null)
{
dummy=another.next;
another.next=prev;
prev=another;
another=dummy;
}
return prev;
}
}
The problem in your attempt is that when you reverse the list, it happens to that list. Yet your code deals with it as if it is a second list, independent from the first list. But because it is not, the head node has become the tail, and so after reverseList has been called, head.next (i.e. dummy.next) is going to be null.
A simple idea would be to change reverseList so that it creates a new list, calling the ListNode constructor for each node it encounters, but then linking them in the opposite direction.
This is however not an ideal solution, as it needs O(n) auxiliary space.
There is the following "trick" you can apply:
Find the middle node of the list (or if the size is even, the first one of the second half).
Reverse the list that starts at that node, i.e. reverse the second half of the list
Now you can walk in both halves and compare the values in tandem.
To make that work, here is a function you could use:
public ListNode middleNode(ListNode head) {
ListNode fast = head;
while (fast != null && fast.next != null) {
head = head.next;
fast = fast.next.next;
}
return head;
}
And now you can do:
public boolean isPalindrome(ListNode head) {
if (head == null) return true;
ListNode mid = middleNode(head);
ListNode tail = reverseList(mid);
while (tail != null) {
if (head.val != tail.val) return false;
tail = tail.next;
head = head.next;
}
return true;
}

Delete an element from a linked list with constraints

This is a fairly easy question but I'm confused:
Given a Singly Linked List, write a function to delete a given node.
1) It must accept pointer to the start node as first parameter and node to be deleted as second parameter i.e., pointer to head node is not global.
2) It should not return pointer to the head node.
3) It should not accept pointer to pointer to head node.
The solution in Java is as following:
void deleteNode(Node node, Node n) {
if (node == n) {
if (node.next == null) {
System.out.println("There is only one node. The list "
+ "can't be made empty ");
return;
}
node.data = node.next.data;
n = node.next;
node.next = node.next.next;
System.gc();
return;
}
// When not first node, follow the normal deletion process
// find the previous node
Node prev = node;
while (prev.next != null && prev.next != n) {
prev = prev.next;
}
if (prev.next == null) {
System.out.println("Given node is not present in Linked List");
return;
}
prev.next = prev.next.next;
System.gc();
return;
}
I'm confused about why in deleting the head node, we're not modifying the head pointer but copying the fields instead (changing the content), but in deleting other nodes, it's simply prev.next = prev.next.next
Does it work if we just do head = head.next instead when deleting head node?
Thank you!
The reason the code copies the data rather than modifying the variable referencing the head is that other users of the list will have a reference to the head node. Changing the local variable will have no effect on their references so you won't have actually deleted the node. Copying the data to the head node effectively removes it.
So, for example, if you had code that did the following:
Node head = new Node("A");
Node tail = new Node("B");
head.next = tail;
deleteNode(head, head);
Then you would expect head.data to be "B" because the original node has been deleted. If you merely do node = node.next then head will still point to the original deleted node.
There are quite a few issues with the code you've posted so please add a comment if you want suggestions on improvements that should be made. It is not a typical algorithm for deleting nodes from a linked list.
One clear issue you've asked about is the use of System.gc. It is not necessary. There are rare cases when Java code needs to take explicit control of garbage collection. This isn't one of them. There's a good explanation of this in the accepted answer to this question.
You asked in the comments why deleting the head requires moving data while deleting other nodes only requires redirection around the node. The reason is because you don't have access to references to the head (as explained in the answer above). You do have access to references to other nodes (i.e. the previous node's next) so they can be changed directly rather than having to copy data.
For your reference, a much more standard implementation is to have the list itself store a reference to the head. Then the copying of node data can be completely avoided. Also note this compares to a value because the node class is private.
static class LinkedList<T> {
private class Node {
private final T value;
private Node next = null;
public Node(T value) {
this.value = value;
}
}
private Node head = null;
public void add(T value) {
Node node = new Node(value);
node.next = head;
head = node;
}
public void remove(T value) {
while (head != null && head.value.equals(value))
head = head.next;
Node prev = head;
while (prev != null && prev.next != null) {
if (prev.next.value.equals(value))
prev.next = prev.next.next;
else
prev = prev.next;
}
}
}
This avoids the arbitrary restrictions in the example you provided such as not being able to delete the head if it's the only node.

deleteNode have problems

my question is about a exercise in lintcode which requires delet node, but for some reason my simple program won't work.
For example, input (1->2->3->4->null, 3) should output (1->2->4->null), my idea is delete next node and "copy" its value to input THIS node.
/**
* Definition for ListNode.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int val) {
* this.val = val;
* this.next = null;
* }
* }
*/
public class Solution {
/**
* #param node: the node in the list should be deleted
* #return: nothing
*/
public void deleteNode(ListNode node) {
// write your code here
ListNode pnext;
if (node != null) {
if (node.next != null) {
ListNode tempnode = node.next;
if (node.next.next != null) {
pnext = node.next.next;
}
else {
pnext = null;
}
node.next = null; //delete next node
node = tempnode; // give next node to THIS node
node.next = pnext; // link next
}
}
else node = null;
}
}
I am very confused about giving value to node, does node1 = node2 even work? I know node.val can. Can anyone simply guide me please?
You did not include in your post what actually happens, and you did not include the part where you create your list, so I can only assume what happens is that you do not delete 3, but delete 4? Or does it not delete anything at all?
So you have a method that should delete a Node, and the Node you want to delete is given as a parameter. But as your list is only linked one way you have no way of determining the node before it (which holds the reference to the node you want to delete). Actually the delete method should be as easy as this:
public void deleteNextNode(ListNode node) {
if(node == null || node.next == null) return; //nothing to delete
if(node.next.next == null){
node.next = null;
return;
} else{
node.next = node.next.next;
}
}
Although I did not test it. As long as you don't store any other references to your nodes this is sufficient, otherwise you need to call next.null explicitely in the else part.
Edit: My function deletes the Node that follows the Node you pass, but you want a function that deletes the Node you pass it. The problem here is that the previous node stores the reference to the Node that you want to delete, but you have no way of determining that Node with only the reference to the Node you want to delete. So either you use this function and always pass the previous node, or you make a wrapper function and run through the list and always safe the previous Node and call the function with that node:
public ListNode deleteNode(ListNode start, ListNode deleteMe)
{
ListNode prev = start;
if(start == deleteMe) return start.next;
while(prev.next != null) {
if(prev.next == deleteMe)
deleteNextNode(prev);
prev = prev.next;
}
return start;
}
Note that I made the function return a ListNode, this is always the first Node of the List (in case you decide to delete the first node).
I hope this helps
You are complicating it unnecessarily and it is not that tough. As I see, you are just taking the ListNode as the parameter and not the data which you want to delete. Also, since you are using if and not while or for, you'll never end up iterating the whole list.
You should modify your function to take both the node as well as the data and start using a loop to iterate the complete list.
Here is the code snippet:
private void deleteNode(ListNode node, int data) {
while(node != null && node.data != data) {
node = node.next;
}
if(node != null) {
System.out.println("Deleted Node With Data: " + node.data);
node = node.next;
}
}
I think by:
node = tempNode; // give next node to THIS node.
You meant:
node.val = tempNode.val; // give next node value to THIS node.
That way, the next node's value is copied into the current node.
Next you would want to also do:
node.next = tempNode.next;
This way, the node effectively becomes the tempNode. I think this was your intention.. ?

Reversing a singly linked, sentinel based, list recursively (works, but not in the way I'd like it to)

I'm preparing for interviews and wrote up this simple function for recursively reversing a singly linked list. The first node is a sentinel node, head. The following code works fine for: list.reverse(list.head.next), but I can't seem to get it to work if I just pass it head.
public Node<T> reverse(Node<T> current)
{
if (current == null)
return head;
if (current.next == null)
{
head.next = current;
return current;
}
reverse(current.next).next = current;
current.next = null;
return current;
}
I assume it doesn't work when I pass it head instead of head.next because I say current.next = null, but even if I check if current == head or if current.data == null and only use current.next = null when those aren't true, it still doesn't work. I'm sure there's a really simple fix, but I'm just not seeing it right now.
The above if passed head returns an empty list, and if the suggested changes are made, simply doesn't finish running, but I don't get any sort of error.
(EDITED)
I kind of get your problem now:
Simply speaking, the sentinel head acts simply as a pointer to the first node, instead of being part of the linked list. Therefore it will not be involved in the reverse process, and need to handle separately.
which means, the original list looks like:
HEAD -> a -> b -> c -> null
after reverse, it should look like
HEAD -> c -> b -> a -> null
In brief, it should look like (assume your code already works when passing in head.next)
public Node<T> reverse(Node<T> current)
{
if (current == head) {
return reverse(current.next);
}
// rest of your original code.
}
Just a further suggestion:
Your reverse() method, as an public instance method of your list class, shouldn't accept the current node, as it is conceptually meaningless for caller.
I believe you should make this method protected, which means something like:
public void reverse() {
this.head = reverseInternal(head);
}
private Node<T> reverseInternal(Node<T> node) {
// your original reverse logic
}
With such encapsulation, you don't even need to struggle before how to make your reverse works when you pass in the sentinel head: you can simply call reverseInternal(head.next) in your public reverse() method.
First: if it returns an empty list it doesn't "work".
There is no need for head to be an empty node. You should normally just keep the first node (in your case list.head.next) as your list.head. head should be a reference to where the list starts, not a separate node.
The reason your code empties the list when you pass it list.head is it sets list.head.next to null. This is because you assume the node you pass to the list is a regular one, while your head node is special.
Here's a solution for your assumptions (I'll assume someone insisted on this bizarre detached head thing. Just don't do it if you're designing the list yourself. Please...)
public Node<T> reverse(Node<T> current)
{
if (current == null)
return head;
if (current.next == null)
{
head.next = current;
return current;
}
Node<T> temp = current.next;
current.next = null;
head.next = temp;
reverse(temp).next = current;
return current;
}
Explanation: This still sets the last node's next to null, but it pushes the list's head one spot down as it runs through the list, eventually pointing it to the last (now first) member.
This reeks of homework.
But still.
In general:
f(Node<T> current, ...) {
f(current.next, ...);
}
For a list a > b > c > d > e sitting in the midle at d, one
probably has built c > b > a already, so guess what is needed as additional parameter to f?
Good luck.
After comments:
public Node<T> reverse(Node<T> current)
{
return reverseRec(current, null);
}
/**
* #param current to-do (sub-)list.
* #param resultDone done reversed list sofar.
* #return reversed result.
*/
public Node<T> reverseRecursively(Node<T> current, Node<T> resultDone)
{
if (current == null) {
return resultDone;
}
Node<T> next = current.next;
current.next = resultDone;
return reverseRecursively(next, current);
}

LinkedList remove method

What is a doubly linked list's remove method?
The same algorithm that Bill the Lizard said, but in a graphical way :-)
(source: jaffasoft.co.uk)
The general algorithm is as follows:
Find the node to remove.
node.previous.next = node.next
node.next.previous = node.previous
node.previous = null
node.next = null
Dispose of node if you're in a non-GC environment
You have to check the previous and next nodes for null to see if you're removing the head or the tail, but those are the easy cases.
public void remove ()
{
if (getPreviousNode () != null)
getPreviousNode ().setNextNode (getNextNode ());
if (getNextNode () != null)
getNextNode ().setPreviousNode (getPreviousNode ());
}
Doubly Linked List Implementation Remove Methods (from my second programming assignment):
public void remove(int index) {
if(index<0 || index>size())
throw new IndexOutOfBoundsException("Index out of bounds. Can't remove a node. No node exists at the specified index");
if(size()==0) {
throw new NullPointerException("Empty list");
}
if(!isEmpty()) {
Node current;
//starting next one to our head
current = head.next;
for(int i=0;i<index;i++) {
current = current.next;
}
current.previous.next = current.next;
current.next.previous = current.previous;
numOfNodes--;
sizeChangeCount++;
}
}
public boolean remove(T o) {
Node current = head;
for(int i=0;i<size();i++) {
current=current.next;
if(current.data.equals(o)) {
current.previous.next = current.next;
current.next.previous = current.previous;
numOfNodes--;
sizeChangeCount++;
return true;
}
}
return false;
}
Are you asking for the name of a method in the api? That answer would simply be remove, assuming you are asking about java.util.LinkedList which is in fact a double linked list.
...or are you asking about what the name of the algorithm to remove an element from that type of data structure is called? Well.. the answer for that would also be to remove an element. Now for the actual algorithm to do it... it's really just a matter of changing the next pointer in the previous node and the last pointer in the next node. However, if you are using your data structure from multiple threads, you will need to either synchronize the remove method, or do the removal steps in an order that will make sense for your usage pattern for the data structure.
What about the current pointer pointer? You have to move crnt to the next node.
http://pastebin.ca/1249635

Categories