I am solving the problem in the interview question about LinkedList.
question is...
Write code to remove duplicates from an unsorted linked list
FOLLOW UP
How would you solve this problem if a temporary buffer is not allowed?
I was reading the solution and I dont understand three parts in the solution.
First,
public static void deletedup(LinkedListNode n)
{
Hashtable table = new Hashtable();
LinkedListNode prev = null;
while(n != null)
{
if(table.containsKey(n.data))
prev.next = n.next; //<--
else
table.put(n.data, true);
prev = n;//<--
}
n = n.next;
}
First-1 question.
In the solution, if table contains the duplicated keyword. they have move to next node.
I was thinking the we just need to to n = n.next. However, solution was doing prev.next= n.next;. However, we don't really sure prev in the code. Why do we have to use prev ?
Moreover,
after putting unique keyword in the table solution assign n to prev (prev = n;). Why do we have to do it ?
Second,
public static void deletedup(LinkedListNode head)
{
LinkedListNode pre = head;
LinkedListNode cur = pre.next;
while(cur != null){
LinkedListNode runner =head;
while(runner != current)
{
if(runner.data == cur.data)
{
LinkedListNode tmp = current.next;
pre.next = tmp;//<---
current = tmp;//<--
break;
}
[...]
}
[...]
}
}
Second question , from the second solution , it program find the duplicated keywords, we have to remove it. Therefore, they declare tmp node to remove to remove duplicated keyowrds.
However, I don't really understand the reason to do " pre.next = tmp and cur = tmp".
I am guessing thet "cur = tmp" will update the current to next node. However, I am not really sure about the reasons..
Third, for the Big o part . I am assuming that first solution will be O(n) and second solution will be O(n^2). Is it right ?
thanks
First Question:
n is a reference to a node. It is a local reference that is only valid in this function.
Say we are accessing the linked list in the future.
The way a node is discovered is by the reference 'r' located in the previous node. We need to change that reference. If we change n, it will not make any difference to 'r'.
If you're from the C/C++ world, think of n as being like a unique pointer to a node. Will changing the value of this pointer change the value of 'r'? I think not.
Second Question:
I think your doubt here might be related to assignments. WHen we say 'current.next', we are referring to the 'next' variable in object 'current'. We are not saying, 'advance current to the next node'. That is why 'current.next' will not really change any variables. When we say 'current = current.next', we are saying, okay, i want to change the node that 'current' is pointing to, and i want to change it to 'current.next', the next node.
Also, I believe you are right about the complexity.
first question:
n = n.next has no no affect on the list itself - it will only advance the value of the variable n to its following element, without touching the actual elements in the list.
Doing prev.next= n.next is updating the field next in the object which prev references to - and putting the value of n.next [which is a reference to an object] there.
second question:
Same issue, curr = temp will have no affect on the list, it will only modify the value of the variable.
Related
The question is very straight forward and I got the algorithm as well. The only thing I don't understand is the return statement. why do we need to return dummy.next, when we haven’t make any change to dummy at all.
I guess my question is when we initially set slow and fast equal to dummy, aren't we just making a deep copy of the list/dummy (meaning whatever change we made in either of them does not affect dummy), or am i missing something..?
Any help would be appreciated. if you can back up your explanation with an example, would be awesome.
And here is link to the question: https://leetcode.com/problems/remove-nth-node-from-end-of-list/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode slow = dummy, fast = dummy;
for(int i = 0; i <= n ; i++){
fast = fast.next;
}
while(fast != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}
}
The only difference that I can see between using the dummy and not would be in the case of having to remove the first element in the list. In that case, without using the dummy there would not be a way to remove the head node. However, this can easily be fixed by adding a simple check during the initial loop.
Here is my solution, omitting the use of the dummy head.
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode slow = head, fast = head;
for(int i = 0; i <= n ; i++){
if (fast == null) {
return head.next;
}
fast = fast.next;
}
while(fast != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return head;
}
To answer your other questions,
aren't we just making a deep of the list/dummy
there is no deep copying going on since the dummy keeps a reference of the head, not a copy.
why do we need return dummy.next, when we haven’t make any change to dummy at all.
the dummy is defined to be before the head. so when we want to return the changed head, we return the next node after dummy. If we just returned dummy, then the answer that we would get would have an extra 0 in the front of it, which we don't want.
To answer your questions,
when we initially set slow and fast equal to dummy, aren't we just
making a deep of the list/dummy
No it doesn't. The assignment is by reference as ListNode is a reference type. Thus changing any of dummy, slow, fast will show its affect on all three variables.
the only thing I don't understand is the return statement. why do we
need return dummy.next
As for the return statement, we still need to return the start of list that was provided to us as a parameter head in function, which is being pointed by dummy.next
As for why is the operations directly not performed on head and there is need of dummy variable and steps
ListNode dummy = new ListNode(0);
dummy.next = head;
the reason might be cover up all edge scenarios. eg : Linked List contains only one node and it is removed or the first node of linked list is removed.
I'm familiar with the 'this' keyword used in java, it is used to reference the current object. The following piece of code shows how a node of a LinkedList is created:
class Node {
Node next = null;
int data;
public Node(int d) {
data = d;
}
void appendToTail(int d) {
Node end = new Node(d);
Node n = this;
while (n.next != null) {
n = n.next;
}
n.next = end;
}
}
But here I'm not sure what the following line in the above code states:
Node n = this;
I'm pretty sure that 'this' here is referenced to the current object, but is this object head, tail or any other node in the LinkedList? Not sure if my question makes perfect sense, but any help is greatly appreciated.
I assume the appendToTail(int d) method appends the newly created node to the end of the list regardless of which Node its called from.
What happens is that one must find the end of the list in order to append the new Node to the end of it. Since we know that the node it is called from is in the list, it's an ideal starting point. Hence we choose the starting point as "this" node. But, this node is not necessarily the end of the list (in fact, it can be anywhere in the list), so we store it in a temporary variable Node n = this and continue changing our temporary variable until its the last node in the list, to which the new node can be added.
It's equivalent to starting from a random point (this) in a list and moving from that point to the end, wherever that is.
Hope this answered your question.
I'm pretty sure that 'this' here is referenced to the current object
Yup.
but is this object head, tail or any other node in the LinkedList?
That depends where the method was called from or if the list contains this Node at all.
All the method does is assign a temporary reference to the current Node so it can be iterated over. You can't say which Node it is without more information.
From comments - If you call appendToTail() on the head, this will be the head. If you call it on the tail, this will be the tail. If you call it on a middle node, this will be that middle node.
Example input: the node ‘c’ from the linked list a->b->c->d->e Result: nothing is returned, but the new linked list looks like a->b->d->e
I do understand that ppl have already asked this question before, but since my reputation is not high enough yet, I couldn't ask my question in that thread. so here goes my quesetion:
So in the solution, when deleting the middle node we do:
public static boolean deleteNode(LinkedListNode n) {
if (n == null || n.next == null) {
return false; // Failure
}
LinkedListNode next = n.next;
n.data = next.data;
n.next = next.next;
return true;
}
But what I don't understand is that why can't I just do n = next?
It is probably a trivial question, but I didn't seem to find a good explanation for this question
If you just do n = next then you have only changed what object your local reference variable n refers to; you haven't modified any part of the list.
The trick to "deleting" the current node is to overwrite it with the next one:
n.data = next.data;
n.next = next.next;
Now you are modifying fields of the object that is referred to by n, which is a part of the actual list.
In C++, the code you wrote would look like this:
bool deleteNode(LinkedListNode* n) {
if (n == null || (*n).next == null) {
return false; // Failure
}
LinkedListNode* next = (*n).next;
(*n).data = (*next).data;
(*n).next = (*next).next;
return true;
}
So what does that mean? When you call this method, in C++ it would look like this:
LinkedListNode* listNode = new LinkedListNode();
deleteNode(&listNode);
This is important, because that means you're just sending an address over, and not the entire object. This means that you don't actually have access to the node you gave as a parameter to the method, you only have a reference to its address.
Basically, in Java, you can't do the following C++ code:
*n = *next;
You can't modify the listNode object that's outside of the method. You only get its address. And you are only modifying the copy of its address, not the address itself.
Basically, it's because in Java, the pointer of the class is passed by value (as a copy), and primitives are also passed by value (as a copy).
somehow, it overwrites the current node which is supposed to be deleted with the
data of next node to it,and delete the next node.
LinkedListNode next = n.next;
n.data = next.data;
n.next = next.next;
That is how the code comes.
I' studying linked lists. I'm practicing problems from this book : Cracking the coding interview. I'm stuck, I can't understand how the author is trying to implement the following code, its supposed to delete a node....
class Node {
Node next = null;
int data;
public Node (int d) {
data = d;
}
Node deleteNode(Node head, int d) {
Node n = head;
if (n.data == d) {
return head.next;
}
while (n.next != null) {
if (n.next.data == d) {
n.next = n.next.next;
return head;
}
n = n.next;
}
return head;
}
I've 3 questions...
Question 1 -
What are we going to pass as the argument for the function deleteNode? What purpose does Node head serve? and what purpose does int d serve? Is the node head the node we want to delete? Or is it our head node? I mean, we are supposed to use the method as following right?
"Name of node".deleteNode("Node name", "integer value");
"Name of node" being the node we want to delete...Isn't that right?
Question 2 - Its clear in the code that the function deleteNode uses only data to confirm the identity of the node we want to delete. E.g. if(n.data ==d). Is that normal practice? I mean what if I have 2 different nodes containing the same integer as the data value? Shouldn't we use the name of the node to specify which node we want to delete?
Question 3 - function deleteNode returns a node. Why is that? In order to delete a node, we only gotta do 3 things...First, unlink the pointer of the node we want to delete. Second, put the pointer of the previous node, to the node where the pointer of the node we wanted to delete was originally pointing. Third, delete the node now that its not linked to the list. I don't see what purpose does return type node serves here...
Question 1 : All along your post, you keep talking about the "name" of the nodes, but the nodes have no name. They have an int value and a successor, that's all. In this deleteNode method, the first argument is the head of the linked list from which you want to remove the first occurrence of the value d.
Question 2 : As I said, the nodes have no name and are identified by their value. As soon as an occurrence of the wanted value is found, the corresponding node is deleted no matter how many occurrences of the same value are in the linked list.
Question 3 : the method returns the head of the list, so that you can chain multiple calls like this
myList.deleteNode(head,3).deleteNode(head,5).addNode(head,10)
If the method had a void return type, you should do
myList.deleteNode(head,3);
myList.deleteNode(head,5);
myList.addNode(head,10);
I am attempting to remove the last iterated element, with a custom iterator/linked list class. It for some reason only does this for the first item in the list (the head condition). Is there anything wrong with the conditions?
Should I, instead of the Else after If (prev=head), write If (next != null) to find middle nodes, and If (next = null) to find the last node?
Second question: to remove the items, should I also write prev.element = null (now I only have prev = null, and I suppose that erases the node but not its content.
Quite simply, what is wrong with my remove method, as I cannot figure it out myself. Thank you guys so much in advance. I have been working many hours with this but I still haven't got it working.
public E next() {
if (!hasNext())
throw new NoSuchElementException ();
prev = next;
E element = next.element;
next = next.next;
return element;
}
public void remove() {
if(prev == null) {
throw new IllegalStateException();
}
else {
if(prev == head){
head = head.next;
next = head;
}
else {
next = prev.next;
}
sizeOfList--;
prev = null;
}
}
You would need a while loop to be able to go through every node in the list until you hit the last one. As it is now, your code simply goes past the head, and then gets into the code that says sizeOfList-- and then prev = null;
You need something like this:
while (prev.next.next != null) {
prev = prev.next;
}
prev.next = null;
I do prev.next.next so that you can set the 2nd to last node in your linked list to point to a null value (which is done by prev.next = null;). Think of it this way: prev is the 2nd to last element in the list, prev.next is the last element, and obviously prev.next.next HAS to be null (because prev.next is LAST.) So once this is the case, delete the last element by setting the 2nd to last element to point to a null value.
And then decrement your list count.
This is my best guess with the given code
if(prev == head){ should change to if(prev.equals(head)){ Use equals method.
And I think you have to override equals method in the corresponding element class might definitely help.
== only checks for whether both variables refer to same object in memory, where as equals check Object state.
I hope it helps :).