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.
Related
I tried implementing the insert method for circular linked list. I think I had some success.
Problem:
When I display the list. The display method will loop because every next variable of the link is linked to a non-null node object. So head will never be a null object. From what I recall about singly linked list, head always point to the first node in the list or the first node with data inside of it.
My conceptual understanding of circular linked list:
From what I can understand circular linked is somewhat like a singly linked list but with a slight twist: the next variable of the tail object points to the head.
I'm coding it like the diagram has presented provided by the source link.
Source: http://sourcecodemania.com/circular-linked-lists/
public void insert(String data)
{
Link link = new Link(data);
if(head == null)
{
head = link;
tail= link;
}
else
{
tail.next = link;
tail = link;
tail.next = head;
}
}
public void display()
{
// good implementation for display #2
while(head != null)
{
// System.out.println (head.data);
head = head.next;
}
}
Once you insert at least one element, you would never come across null. It will keep on going till infinity.
Also, it might not be a good idea to modify head just for displaying the list. Operation like display should not have any side effects.
In stead, keep a member field size in your list class and update it in each insert and delete method.
Now you would know how many times you should iterate the loop.
ListClassName current = head; // Head is not modified.
for (int i = 0; i < this.size; i++) {
// System.out.println (current.data);
current = current.next;
}
Good luck.
You can keep a reference to the first Link object and check to make sure head is not equal to this object while looping:
public void display()
{
boolean first=true;
Link firstItem=null;
// good implementation for display #2
while(head != null && head!= firstItem)
{
if(first){
firstItem=head;
first=false;
}
// System.out.println (head.data);
head = head.next;
}
}
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 want to identify the loop or recursion in the list for the below structure of the node. How can I identify the same?
public class EntityNode {
private EntityNode nextNode; // Points to the next node
}
Example,
Node1 -> Node2 -> Node3 -> Node4 -> Node5 -> Node6 -> Node4
Here, you can see that Node6 is pointing to Node4, and here there comes the looping or recursion and my code will go into infinite. So what if I want to find out this type of scenario with the optimum performance level?
This is actually an interview question I have heard a few times. While I have never tried to implement any sort of loop detection, the answer that most of the interviewers seemed to like is iterating through the list and storing the visited nodes in a hashtable. If you get a collision while storing into the table, then you have a loop in your list.
Edit: In an attempt to offer some code for the example, here is what I would probably try to do (assuming you have some sort of LinkedList<EntityNode> object). I updated this to use a HashSet instead of a HashMap so it was more straightforward (as pointed out by PM 77-1).
public bool detectLoop(LinkedList<EntityNode> list)
{
Set<EntityNode> nodeSet = new HashSet<EntityNode>();
EntityNode curNode = list.getHead();
boolean loopDetected = false;
if(curNode != null)
{
while(curNode.getNextNode() != null && !loopDetected)
{
cureNode = curNode.getNextNode();
loopDetected = !nodeSet.add(curNode);
}
}
return loopDetected;
}
I haven't had the opportunity to test this, but this should work. The reason being that the add() method for a HashSet returns true if this set did not already contain the specified element. So if there is a EntityNode already exists in the set, it will return false, meaning that there was a loop detected.
Since my answer has sort of taken off, I want to say that there are other solutions to this as well. The other one that has been pointed out in this thread is the tortoise and the hare algorithm. You can find more information on that in this thread or at this wiki page.
You should have two EntityNode objects. Both start at Node1. Have the first object move two nodes down, and the second only move one node down. Repeat this until you either reach the end (there was no cycle) or the two objects meet at the same node (there is a cycle).
For your example:
n1: Node1, n2: Node1
n1: Node3, n2: Node2
n1: Node5, n2: Node3
n1: Node4, n2: Node4 -> cycle!!
For pseudocode:
while (n1.nextNode isn't null):
n1 = n1.nextNode.nextNode
n2 = n2.nextnode
if (n1 equals n2): return 'there is a loop!'
I searched on the net and found that this type of problem is called the tortoise and hare algorithm. The Wikipedia page is also here for the same.
As codaddict states in their answer here:
The idea is to have two references to the list and move them at
different speeds. Move one forward by 1 node and the other by 2 nodes.
If the linked list has a loop they will definitely meet.
Else either of the two references(or their next) will become null.
Java code implementing the algorithm:
boolean hasLoop(EntityNode first) {
if (first == null) // list does not exist..so no loop either.
return false;
EntityNode slow, fast; // create two references.
slow = fast = first; // make both refer to the start of the list.
while (true) {
slow = slow.nextNode; // 1 hop.
if (fast.nextNode != null)
fast = fast.nextNode; // 2 hops.
else
return false; // next node null => no loop.
if (slow == null || fast == null) // if either hits null..no loop.
return false;
if (slow == fast) // if the two ever meet...we must have a loop.
return true;
}
}
I think you can make a "visited" flag. Or you can use unintersecting sets, which helps to identify loops in O(N *log N).
P.S. I must admit that this method is more appropriate if you need to build a graph without cycles.
I like Bhavik's answer if you are constrained by memory limits. It doesn't create any possibly large objects to determine the answer.
If there is a loop then the single step and double step methods of walking through the EntityNodes will have to intersect.
Here is sample code to test with -
public class EntityNode {
private EntityNode nextNode = null; // Points to the next node
public static void main(String[] args) {
final EntityNode head = new EntityNode();
// Create small sample (test with even and odd number)
EntityNode tail = head;
for (int i = 0; i < 6; i++) {
EntityNode newNode = new EntityNode();
tail.nextNode = newNode;
tail = newNode;
}
// Add "loop" node
tail.nextNode = head;
System.out.println(detectLoop(head));
}
// Return true if a loop is found
private static boolean detectLoop(EntityNode head) {
boolean loopDetected = false;
if (head != null) {
EntityNode singleStep = head;
EntityNode doubleStep = head;
// If either EntityNode is null and end has been found
while ((singleStep.nextNode != null)
&& (doubleStep.nextNode != null)) {
singleStep = singleStep.nextNode;
// Assert doubleStepper.nextNode != null
doubleStep = doubleStep.nextNode.nextNode;
// If there is a "Collision" then there is a loop
loopDetected = (doubleStep == singleStep);
if (loopDetected) {
break;
}
}
}
return loopDetected;
}
Just traverse the list while keeping every visited node in a hash set. If the node you are adding is ever already present in the set, you have a cycle.
A.-Keep count of the amount of added nodes. Then start a loop through them, while counting the loops. If loopsAmount>nodesAmount, you have recursion.
B.-Keep track of the visited nodes. If a node is visited twice, you have recursion.
C.-Index the nodes while creating them. If node.nextNode.Index-1 != node.Index, you have recursion.
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.
This is part of an exercise we did in class, I just can't figure it out...
The required method is the insertBefore(object data) method wherein when a user choose this method it will prompt it to enter a data to be inserted before the reference data(input by user)
An example of how it should run:
// assuming linked list has data 1,2,3 inserted already
Choose Method:
1)Insert Before
choice: 1 // input by user
====Insert Before====
Enter Reference data: 2 // input by user
Enter Data to be inserted: 5 // input by user
supposed output: 1,5,2,3
Here's my code for this exercise: (This is inside a class called LinkList with variables
protected int end;
protected Node start;
and an inner class called Node)
private class Node
{
public char data;
public Node next;
public Node(char data)
{
this.data = data;
}
}
public void insertBef(char ref,char data)
{
Node temp = new Node(data);
Node current = start;
if(end!=0)
{
for(int i = 1; i<end; i++)
{
if(current == start)
{
Node newNode = start;
newNode.data = current.data;
newNode.next = temp;
current = current.next;
}
else if(current.data == ref)
{
Node newNode = current;
newNode.data = current.data;
newNode.next = temp;
current = current.next;
}
}
end++;
}
else
{
temp.next = start;
start = temp;
}
end++;
}
But when I run my code it ouputs 3,5, not 1,5,2,3! I can't see where I might have gone wrong...
Can someone please tell me where the mistake is, and explain how I might fix it?
I understand that to be able to insert before a reference value you should:
Make a new node for the new data
Make a temporary node for the reference value and link
Make the link of the data before the reference value point to the new node and make the link of the new node point to the temporary node
I just can't seem to figure out how to implement it in Java code...
When programming, if it seems hard, you're probably going about it the wrong way...
You only need one line of code to accomplish the task!
list.add(list.indexOf(reference), data);
Here's this line wrapped as an insertBefore method:
public static void insertBefore(List<Integer> list, int reference, int data) {
list.add(list.indexOf(reference), data);
}
Here's a test using your example:
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
insertBefore(list, 2, 5);
System.out.println(list);
}
Output:
[1, 5, 2, 3]
Note: This code will throw an exception if the reference element is not found.
I'll leave it to you to plug that hole.
First things first: for loops are generally a bad idea with linked lists. while loops are much better; you can do something like while(next != null).
Looking at your code, you seem to have a few problems.
Your for loop is overly complicated, and doesn't seem to make a lot of sense. Here's how your loop should look:
Get head node
Begin looping through the list, checking the next node's value as you go
Once you find that the next node's value is the one you're looking for, creating a new node.
Insert the new node by setting its Next value to be equal to the current node's Next value, then set the current node's next value to be the new node.
Return from the function.
Your middle bullet point is actually unnecessary, and I have no idea what you use end for. Regardless, you seem to have the basic principle down, so I won't feel like I'm spoiling you by posting code.
Now, I'm not sure what your start is. Does it hold a value, or is it a dedicated head node? I'd vote for a dedicated head node, I generally find it easier to work with because you don't need to add code for a special case where the number should come before the head. So your start node should be "empty"; the value it holds is ignored, the only thing it's used for is to keep a pointer to the first legit node in the list. If you do this, the insertBef method becomes incredibly simple. NOTE: untested code to follow.
public void insertBef(char ref, char data)
{
Node current = start;
while( current.next != null )
{
if( current.next.value == ref )
{
Node n = new Node(data);
n.next = current.next;
current.next = n;
return;
}
current = current.next;
}
}
Please don't just copy the code. If you have questions, post them and I'll do my best to answer.