I'm working on a hackerrank problem and it seems like no matter the variation of the solution I try, I can't get the cycle detection to work.
Here's the code I'm using
static boolean hasCycle(SinglyLinkedListNode head) {
if (head == null) return false;
SinglyLinkedListNode slow, fast;
slow = head;
fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
I can tweak the solution to get the other test to pass, but not both. In this case true is never returned, even when it should be. How can I fix this, what am I doing wrong?
It has to do with Hackerrank itself. I tried my own solution that passed all the tests some time ago but it also failed for cases where there were cycles. So, I took a look at Hackerrank's insertNode method used for creating lists in test cases:
public void insertNode(int nodeData) {
// here a new node object is created each time a method is called
SinglyLinkedListNode node = new SinglyLinkedListNode(nodeData);
if (this.head == null) {
this.head = node;
} else {
this.tail.next = node;
}
this.tail = node;
}
And then how it's used in their main:
public static void main(String[] args) throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
int tests = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int testsItr = 0; testsItr < tests; testsItr++) {
int index = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
SinglyLinkedList llist = new SinglyLinkedList();
int llistCount = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int i = 0; i < llistCount; i++) {
int llistItem = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
// a new node is inserted each time so no cycle can be created whatsoever.
llist.insertNode(llistItem);
}
boolean result = hasCycle(llist.head);
bufferedWriter.write(String.valueOf(result ? 1 : 0));
bufferedWriter.newLine();
}
bufferedWriter.close();
scanner.close();
}
As you can see for each llistItem value llist.insertNode(llistItem) is invoked to add an item to the list. This method, however, can't create cycles as it creates a new SinglyLinkedListNode each time. So, even though some llistItem values are the same the nodes containing them are always different.
UPDATE
As of January 5, 2020, Hackerrank tests are fixed and the solution provided by the OP passes all of them.
Tests of this challenge are incorrect, and there are no loops. Check it by printing out head.next....next. You can get NPE where tests waiting for return TRUE. See linked lists generations in other languages.
Related
I created some Nodes with lastNode pointing head.
In removeCycle method Firstly detected the lastNode and then got error, when I try to make lastNode(i,e prev).next = null
public class loopsRemove {
public static class Node{
int data;
Node next;
public Node(int data){
this.data = data;
this.next = null;
}
}
public static Node Head;
public static Node Tail;
public static int count =0;
public static int removeCycle(){
Node slow = Head;
Node fast = Head;
boolean Cycle = false;
while(fast !=null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
count++;
if(slow == fast){
Cycle =true;
break;
}
}
if(Cycle == false){
return 0; //No Cycle and come out of function (int type is just to observe where function is returning
}
slow = Head;
Node prev=null; //to track previous of fast
while(slow != fast){
prev = fast;
slow = slow.next;
fast = fast.next; //speed is same as slow now
}
prev.next =null; //Making endNode.next to null
return 1; //int return is just to check weather my code is returning here or above
}
public static void main(String[] args) {
Head = new Node(3);
Head.next = new Node(4);
Head.next.next = new Node(5);
Head.next.next.next = new Node(6);
Head.next.next.next.next = Head; //cycle formed
System.out.println(removeCycle());
System.out.println(Head.next.next.next.next.data); // null is expected at the last node if removeCycle works correctly
}
}
Expected output:
1
null
current output :
Exception in thread "main" java.lang.NullPointerException: Cannot assign field "next" because "prev" is null
at loopsRemove.removeCycle(loopsRemove.java:44)
at loopsRemove.main(loopsRemove.java:55)
Your algorithm works for breaking cycles anywhere, except when the cycle includes the head node.
To solve this you could temporarily prefix a dummy node before the head, use the algorithm on this longer list, and then omit that dummy node again.
The below code is your code except for the lines that reference dummy:
public static int removeCycle() {
Node dummy = new Node(0);
dummy.next = Head; // Prefix a dummy node before the head node
Node slow = dummy; // Apply the algorithm on this longer list
Node fast = dummy;
boolean Cycle = false;
while(fast !=null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
count++;
if(slow == fast){
Cycle =true;
break;
}
}
if(Cycle == false){
return 0;
}
slow = dummy; // Start at the temporary head
Node prev=null;
while(slow != fast){
prev = fast;
slow = slow.next;
fast = fast.next;
}
prev.next =null;
return 1;
}
Note that in your main program you should not try to print the data of a null reference. Just print the next property that is expected to be null:
System.out.println(Head.next.next.next.next);
Because the dummy node is not referenced by anything else than a local variable, it can be garbage collected after removeCycle returns.
The first while ends when
if(slow == fast){
Cycle =true;
break;
}
Then
slow = Head;
doesnt change anything, in this case (3->4->5->6) slow is already head, slow==fast is still true and the following while is never entered
Node prev=null; //to track previous of fast
while(slow != fast){
prev = fast;
slow = slow.next;
fast = fast.next; //speed is same as slow now
}
prev.next =null;
meaning that prev is null when you try to assign prev.next.
Edit:
The reason that your code won't work without the dummy in trincots answer is that when there are no elements that are not part of the circle, then the first while stops when slow==fast==Head, meaning that the next-reference to head is lost. Using the dummy, slow==fast at the element before head (in case there are no non-circular elements, otherwise earlier), so that prev.next can be reassigned to null. And, there's no risk that the second while is skipped. (This can also be avoided by using a do-while.)
I have written a circular doubly-linked list with a dummy node at the front. During the initialization of my DLL class, I create the dummy node. When I use the debugger in jGrasp and use the visualization tool, after inserting several numbers, my dummy node gets shuffled around and does not stay at the front. I don't understand how I am modifying my linked list. As a preface, my node class has has an integer val and two pointers named prev and next.
One thing I notice is that after the assignment statement curr = dummy, dummy node is shuffled to the curr from the previous insertion.
public class DLL {
Node curr;
Node help;
Node dummy = new Node(null, null, -1);
public DLL() {
this.curr = curr;
this.help = help;
dummy.next = dummy;
dummy.prev = dummy;
}
public boolean isEmpty() {
if (dummy.next == dummy && dummy.prev == dummy) {
return true;
}
return false;
}
public void push(int elem) {
if (isEmpty()) {
Node sec = new Node(dummy, dummy, elem);
dummy.next = sec;
dummy.prev = sec;
} else {
curr = dummy;
while (curr.next != dummy) {
curr = curr.next;
}
Node n = new Node(curr, dummy, elem);
curr.next = n;
dummy.prev = n;
}
}
public void reverse() {
curr = dummy;
help = dummy;
while (curr.next != help || curr != help) {
curr = curr.next; // increment curr
help = help.prev; // decrement help
swap(curr, help); // swap
}
}
public void swap(Node curr, Node help) {
int temp = curr.val;
curr.val = help.val;
help.val = temp;
}
public boolean contains(int elem) {
curr = dummy.next;
while (curr != dummy && elem != curr.val) {
curr = curr.next;
if (curr == dummy) {
return false;
}
}
return true;
}
}
Here is the small test class I used:
public class testDLL {
public static void main(String[] args) {
DLL dlink = new DLL();
dlink.push(4);
dlink.push(6);
dlink.push(3);
dlink.push(2);
assert dlink.contains(4) == true;
assert dlink.contains(6) == true;
assert dlink.contains(3) == true;
assert dlink.contains(2) == true;
dlink.reverse();
}
}
Welcome to SO. Rather than finding the problem for you, I'll suggest how you might tackle it yourself.
Your test is trying to test too much in one go. For your test to work all of the methods need to work. Better is to test each method in isolation (as far as possible) and then build to testing more complicated scenarios.
So try to get this test working first:
DLL list = new DLL();
assertTrue(list.isEmpty());
Then
DLL list = new DLL();
list.push(5);
assertTrue(list.contains(5));
Pretty soon you'll find you need a method to get the list in a different format for test purposes. This is pretty typical.
DLL list = new DLL();
list.push(5);
list.push(7);
list.push(5);
assertEquals(list.asList(), List.of(5, 7, 5));
DLL list = new DLL();
list.push(5);
list.push(7);
list.reverse();
assertEquals(list.asList(), List.of(7, 5));
And so on.
That way you can check each method works with basic values before moving on.
Now a couple of design pointers: your use of a dummy node to store the head and tail is unusual. It would be easy to mess values up (as you've done). Better is to store the head and tail as separate variables that are null (or, better, Optional.empty) if the list is empty and point to the same node for a single item.
I have resolved this issue I believe. Instead of setting curr = dummy, I set curr = head. Immediately after initializing dummy at the top of DLL, I set head = dummy. This way I do not alter head as I go along.
Given, a linked-list, I'm trying to partition it into so that the even nodes come before the odd nodes. My approach is to create two different linked-list (even and odd) to store even numbers and odd numbers. However, I'm running into a problem when I want to add to the even or odd linked list (I commented the part that I think is giving me problem in my code below). Thanks!
public class SeperateOddEven {
static Node head;
static int count;
public static class Node {
int data;
Node next;
private Node(int data) {
this.data = data;
next = null;
count++;
}
}
public void seperate() {
Node even = null;
Node odd = null;
Node temp;
// go through each linked-list and place node in new list depending on whether they are even or odd
while(head != null) {
// if even, place in even linked-list
if(head.data % 2 == 0) {
temp = new Node(head.data);
even = temp; // Problem here
even = even.next; // and here
} else { // if head.data % 2 != 0
temp = new Node(head.data);
odd = temp;
odd = odd.next;
}
head = head.next;
}
toString(even);
//toString(odd);
}
public void toString(Node node) {
while (node != null) {
System.out.print(node.data + " ");
node = node.next;
}
}
public static void main(String[] args) {
SeperateOddEven s = new SeperateOddEven();
head = new Node(8);
head.next = new Node(12);
head.next.next = new Node(10);
head.next.next.next = new Node(5);
head.next.next.next.next = new Node(4);
head.next.next.next.next.next = new Node(1);
head.next.next.next.next.next.next = new Node(6);
System.out.println("original list: ");
s.toString(head);
s.seperate();
}
}
I believe you identified exactly where the problem is. Let's go line by line:
temp = new Node(head.data);
The extra temp variable is unnecessary but fine.
even = temp;
A problem arises on the next line however. You assign even to temp (making temp unnecessary). If something was previously stored in even, it is now lost to the garbage collector because you now have no reference to it. even and temp are now both references to the same Node object.
What I think you might have wanted to do was to say even.next = temp. This would start to create a list, but with only a single reference you would have to use that reference to point to the head of the list. Each time you wanted to append to the list, you would need to loop through it until you found the end. If you instead tried to make this single reference point to the tail of the list, you would no longer have any way to get back to the head because your Nodes only have next references, and not prev references (a list with bidirectional references is called a doubly linked list).
even = even.next;
Because even (and temp) both point to the newly created Node object, the even.next property is null. So when this line executes, even now points to null. The work inside the loop has accomplished nothing because you immediately lose references to every Node you create.
Try something like this:
// Must keep track of head reference, because your Nodes can only go forward
Node evenHead = null;
Node evenTail = null;
Node oddHead = null;
Node oddTail = null;
while (head != null) {
if(head.data % 2 == 0) {
if (evenHead == null) {
// The even list is empty, set the head and tail
evenHead = new Node(head.data);
evenTail = evenHead;
} else {
// Append to the end of the even list
evenTail.next = new Node(head.data);
evenTail = evenTail.next;
}
} else {
// similar code for odd, consider creating a method to avoid repetition
}
}
You can also try this :
while (head != null) {
// if even, place in even linked-list
temp = new Node(head.data);
if (head.data % 2 == 0) {
if(even == null) {
even = temp;
} else{
Node insertionNode = even;
while(insertionNode.next != null)
insertionNode = insertionNode.next;
insertionNode.next = temp;
}
} else { // if head.data % 2 != 0
if(odd == null) {
odd = temp;
} else{
Node insertionNode = odd;
while(insertionNode.next != null)
insertionNode = insertionNode.next;
insertionNode.next = temp;
}
}
head = head.next;
}
My code needs to find a cycle in a linked list. If there is a cycle then the output is 1; the result is 0 otherwise. I've done research and learnt about Floyd's cycle algorithm and came across several other posts that contain the code for the algorithm. But I'm failing some test cases here on HackerRank. Could smb please tell me what is wrong with the code? Thanks!
int HasCycle(Node head) {
if(head == null){
return 0;
}
Node slow = head;
Node fast = head;
while(true)
{
slow = slow.next;
if(fast.next != null){
fast = fast.next.next;
}
else{
return 0;
}
if(slow == null || fast == null){
return 0;
}
if(slow.data == fast.data){
return 1;
}
}
}
Your issue is when a linked list has .data fields with all 10 for example. Then it always is a cycle according to your algo. You need if slow==fast return 1 as opposed to if slow.data==fast.data.
I’ve been doing this problem:
I created one file which takes random numbers and I stored those numbers in a SinglyLinkedList data structure and I'd like to perform a mergeSort to sort these random numbers.
Everything works fine for smaller no of input.
But when I insert 10000 numbers, it starts giving ‘stack_overflow’ error at around 9800 no(at displaying numbers only) and when I insert 0.1 million numbers- it works well till 99700 numbers but then it starts showing errors for the rest of the numbers.
So what exactly the reason would be behind this error (I know it’s because it gets lost in recursive function)
Please help me out here, I'm not able to track the problem which causes this error.
Here's my main method code:
FileReader fr = new FileReader("C://my_folder//file_List.txt");
BufferedReader br = new BufferedReader(fr);
LinkedListNode lln = new LinkedListNode();
String str;
while((str=br.readLine())!=null){
/* This insertAtEnd appends the number to the SinglyLinkedList*/
lln.insertAtEnd(Integer.parseInt(str));
System.out.println(" "+str);
}
/*This method displays the elements of a LinkedList*/
Node res = lln.traverse();
System.out.println("\n");
mergeSortLinkedList ms = new mergeSortLinkedList();
ms.sort(res);
here's my sort method code:
public void sort(Node n){
Node tmp = n;
MergeSort(tmp);
}
Node a;
Node b;
public void MergeSort(Node headRef){
Node head1 = headRef;
if(head1 == null || head1.next == null){
return;
}
System.out.print("hi..");
Node Euler = splitList(head1);
printList(Euler);
}
/* perform merge sort on the linked list */
public Node splitList(Node head1){
Node slow;
Node fast;
Node left, right;
if(head1 == null || head1.next == null){
left = head1;
right = null;
return head1;
}
else{
slow = head1;
fast = head1.next;
while(fast!=null){
fast = fast.next;
if(fast!=null){
slow = slow.next;
fast = fast.next;
}
}
left = head1;
right = slow.next;
slow.next = null;
}
return SortedMerge(splitList(left),splitList(right));
}
/* merge the lists.. */
public Node SortedMerge(Node a, Node b){
Node result = null;
if(a == null){
return b;
}
else if( b == null){
return a;
}
if(a.data < b.data){
result = a;
result.next = SortedMerge(a.next, b);//getting error at this line
}
else{
result = b;
result.next = SortedMerge(a,b.next);//getting error at this line
}
return result;
}
public void printList(Node Euler){
System.out.println("\nPrinting sorted elements");
Node Ref = Euler;
int count = 0;
while(Ref!=null){
count++;
System.out.println(count+"-"+Ref.data);
Ref = Ref.next;
}
}
have you considered using Collections.sort() from the JDK, which will do a merge-sort? Java 8 has also a parallelSort which does a parallel merge-sort.
I’d like to give you a update.
By changing the stack size, I did able to run my program properly.
The reason it was causing
Exception in thread "main" java.lang.StackOverflowError is because it was getting out of stack size.
So I searched around and got this solution.
Go to the project properties- Inside run, go to the VM option and put this in argument -Xss100m to make it run!
Now it is able to sort more than 1 million numbers :D
Other suggestions / solutions are welcome.