how to reduce doubly linked list complexity in the code - java

// Complete the sortedInsert function below.
/*
* For your reference:
*
* DoublyLinkedListNode {
* int data;
* DoublyLinkedListNode next;
* DoublyLinkedListNode prev;
* }
*
*/
static DoublyLinkedListNode sortedInsert(DoublyLinkedListNode head, int data) {
DoublyLinkedListNode Leader=head;
DoublyLinkedListNode newNode = new DoublyLinkedListNode(data);
while(Leader.next!=null){
if(data>Leader.data){
Leader = Leader.next;
}
else {
if(Leader.prev == null) {
newNode.next = Leader;
Leader.prev = newNode;
head = newNode;
return head;
}
}
}
if(Leader.next == null) {
if(data<Leader.data) {
newNode.prev = Leader.prev;
newNode.next = Leader;
Leader.prev.next = newNode;
return head;
} else {
newNode.prev = Leader;
Leader.next = newNode;
return head;
}
}
return head;
}
in the above-sorted insert method how to decrease this doubly linked list complexity, this is a hackerrank question I'm getting timed outs for the test cases I need help in decreasing the time complexity for this code.

You code will never come out of while loop.
Lets take the example. List = [(1), (4), (4)](only 1 element). New node is (4). Your result should be [(1), (4), (4), (4)]. But lets walk your code and check what will happen. Initially Leader = (1)
while(Leader.next!=null){ // 1
if(data>Leader.data){ // 3
Leader = Leader.next;
}
else { // 6
if(Leader.prev == null) { // 7
newNode.next = Leader;
Leader.prev = newNode;
head = newNode;
return head;
}
}
}
At line 1 check will pass (as (1).next is not null; in fact it is (4)).
At line 3 ((4) > (1)). Check pass. Leader = (1).next = (4). Jump to line 1
At line 1 check will pass (as (4).next is not null; in fact it is (4)).
At line 3 ((4) > (4)). Check Fail. Enter line 7
At line 7 check will fail ((4).prev is not null; in fact it is (4) - 1st 4). No update in Leader will take place. Leader will remain same & you will enter infinte loop from here.
You will have to take care of this. Maybe the Problem's discussion page will help. But do give it a through try.
My own try is included below:
static DoublyLinkedListNode sortedInsert(DoublyLinkedListNode head, int data) {
DoublyLinkedListNode n = new DoublyLinkedListNode();
n.data = data;
DoublyLinkedListNode curr = head;
if (head == null) {
return n;
}
// if given node is smaller than 1st node
if (data < curr.data) {
n.next = curr;
return n;
}
// find first node greater than given node
while (curr.next != null && curr.data < data) {
curr = curr.next;
}
// reached to the end.
if (curr.next == null && data >= curr.data) {
curr.next = n;
} else { // found the 1st node which is greater than given node
curr.prev.next = n;
n.next = curr;
}
return head;
}

Related

Reverse subparts of a contiguous linked list in Java

I am trying to reverse a subpart of a singly-linked list where the subpart is a contiguous set of even elements, bordered by either the end of the list or an odd element.
So far, I know how to reverse a linked list but I'm unable to figure out how to check if the element is odd or if it's at the end.
Node reverse(Node head) {
// Write your code here
if(head == null) return null;
Node prev = null;
Node curr = head;
Node next = null;
while(curr != null) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
Example
Input:
list = [1, 2, 8, 9, 12, 16]
Output:
[1, 8, 2, 9, 16, 12]
The subparts in this example are 2,8 and 12,16
Node reverse(Node head) {
if(head == null) return null;
Node curr = head;
Node next = null;
Node prev = null;
while(curr!=null && curr.data%2==0) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
if(curr!=head) {
head.next = curr;
curr = reverse(curr);
return prev;
} else {
head.next = reverse(head.next);
return head;
}
}
Q. Given a singly linked list of integers, reverse every contiguous set of nodes that have only even values.
I/P = 1 2 3 3 4 6 8 5, O/P = 1 2 3 3 8 6 4 5, explanation -
There are two sub lists of even elements, which [2] and [4->6->8]. The sub list [4->6->8] has been reversed and the single sub list [2] need not be reversed.
Test Cases passed
1 3 8 3 4 2 6 5 single/multi even element in list,
2 4 6 1 3 even occurs at head,
1 4 4 6 8 even occurs till tail,
2 4 6 8 2 all even in the list
import java.util.*;
//import ds.List.ListNode; import your ListNode class
/*
public class ListNode {
public int val;
public ListNode next;
public ListNode(int x) { val = x; next = null; }
}
*/
class Solution{
public ListNode reverseEvenElements(ListNode head)
{
ListNode p = null;//prev
ListNode c = head;//curr
while(c != null){
if(c.val % 2 == 0){
ListNode start = p;
while(c != null && c.val % 2 == 0){
p = c;
c = c.next;
}
//end of even elements = p
//making end of even node to null so that reverse should stop
//otherwise it will reverse whole list
p.next = null;
ListNode[] node;// [head,tail]
// if start is null i.e. even element found at head itself
if(start == null){
node = reverseList(head);
head = node[0];//node[0] = head of reversed list
}else{// start != null
node = reverseList(start.next);
start.next = node[0];
}
node[1].next = c;//node[1] = tail of reversed list
}
if(c != null){
p = c;
c = c.next;
}
}
return head;
}
// this method will be called when even elements occurs till last even element we get
//in the original list returns head & tail of reversed list
public static ListNode[] reverseList(ListNode head){
ListNode p = null;
ListNode c = head;
ListNode n = head.next;
while(true){
c.next = p;
p = c;
c = n;
if(n == null)
break;
else
n = n.next;
}
return new ListNode[] {p, head};// [head,tail]
}
}
from what you given me i understood like :
input : [1,2,4,8,5,7,7,6,6,2,8,1,1,1,2,4]
output: [1,8,4,2,5,7,7,8,2,6,6,1,1,1,4,2]
i have edited your code for reverse to reverse till which will reverse intervals & created reverse_whole which will find those intervals
public ListNode reverse_whole(ListNode head) {
ListNode temp=head;
ListNode pre_temp=new ListNode(0,temp);
ListNode ans_pre = pre_temp;
while(temp!=null){
if(temp.val%2==0){
ListNode temp_till=temp;
while(temp_till!=null&& temp_till.val%2==0){
temp_till=temp_till.next;
}
// temp_till will iterate over even number interval after one
//so: 1,2,4,6,7 : 7 is temp_till
// reverse 2,4,6 so it become : 1,6,4,2,7
pre_temp.next=reverse_subpart(temp,temp_till);
temp=temp_till;
}
pre_temp=temp;
if(temp!=null)temp=temp.next;
}
return ans_pre.next;
}
public ListNode reverse_subpart(ListNode head,ListNode end) {
// Write your code here
if(head == null) return null;
ListNode prev = null;
ListNode curr = head;
ListNode next = null;
while(curr != end) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
head.next=end;
return prev;
}
run reverse_whole
if you have any doubt can write me
class LinkedList {
Node head;
Node curr = head;
Node next = null;
Node prev = null;
class Node {
int data;
Node next;
Node(int d)
{
data = d;
next = null;
}
}
void pairWiseSwap()
{
Node temp = head;
while (temp != null && temp.next!=null) {
int k = temp.data;
int j = temp.next.data;
if(k%2==0 && j%2==0) {
temp.data=j;
temp.next.data=k;
temp=temp.next.next;
continue;
}
temp = temp.next;
}
}
public void push(int new_data)
{
Node new_node = new Node(new_data);
new_node.next = head;
head = new_node;
}
void printList()
{
Node temp = head;
while (temp != null) {
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
public static void main(String args[])
{
LinkedList llist = new LinkedList();
llist.push(16);
llist.push(12);
llist.push(9);
llist.push(8);
llist.push(2);
llist.push(1);
System.out.println("Linked List before calling pairWiseSwap() ");
llist.printList();
llist.pairWiseSwap();
System.out.println("Linked List after calling pairWiseSwap() ");
llist.printList();
}
}

Failing certain test cases for reversing a doubly-linked list

My implementation for a doubly linked list is listed down below, but for some reason I am not passing one test case. The reverse function only gives us the head of a doubly linked list, and does NOT give us the tail. Is there a certain edge case that I could be missing?
`
// Complete the reverse function below.
/*
* For your reference:
*
* DoublyLinkedListNode {
* int data;
* DoublyLinkedListNode next;
* DoublyLinkedListNode prev;
* }
*
*/
static DoublyLinkedListNode reverse(DoublyLinkedListNode head) {
// If the linked list is empty, return null
if (head == null) {
return null;
}
// If the linked list has only one element, return head becaue reverse of one ele is itself
else if (head.next == null) {
return null;
}
// Otherwise reverse
else {
DoublyLinkedListNode current = head.next;
head.next = null;
while (current != null) {
DoublyLinkedListNode nextCurr = current.next;
DoublyLinkedListNode prevCurr = current.prev;
current.next = prevCurr;
current.prev = nextCurr;
head = current;
current = nextCurr;
}
return head;
}
}
These logics are wrong:
// If the linked list has only one element, return head becaue reverse of one elem is itself
else if (head.next == null) {
return null; //return head instead (unchanged).
}
Start with head:
DoublyLinkedListNode current = head.next; // <<<< current = head
head.next = null; // <<<< comment out this line
In while loop :
No need to update head each time. Update it with the current at the end of the loop.
I've removed the unnecessary and incorrect logic and variables.
public static DoublyLinkedListNode reverse(DoublyLinkedListNode head) {
while (head != null) {
DoublyLinkedListNode nextCurr = head.next;
head.next = head.prev;
head.prev = nextCurr;
if (nextCurr == null) {
break;
}
head = nextCurr;
}
return head;
}

Singly Linked List - Put last node after first node

Let's say that I've a list that goes by 1->2->3->4->5. I want to put the last node after the first one so it goes like 1->5->2->3->4. This is my code but it doesn't work
public void Manipulate(){
Node curr = head;
Node next = null;
Node last = head;
while(last.next != null){
last = last.next;
}
next = curr.next;
last.next = next;
curr.next = next.next;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
SinglyLinkedList lista = new SinglyLinkedList();
int a = sc.nextInt();
int b = sc.nextInt();
lista.addFirst(a);
lista.insertAfter(a, b);
for(int i = 0; i < 2; i ++){
int c = b;
b = sc.nextInt();
lista.insertAfter(c, b);
}
lista.addLast(34);
lista.addLast(55);
lista.addLast("Ginger");
lista.Manipulate();
System.out.println(lista);
}
You already got some improvement suggestions, so here's a little explaination what you actually did wrong.
The result of your code (as is) would be:
1->3->4->5->2->3->4->5->2->3->4->5->2->3->4->5->2->3->4->5->2->3->4->5->2->3->4->5->2->3->->4->5->2->3->4->5->2->3->->4->5->2->3->4->5->2->3->4->5->2->3->4->5->2->3->->4->5->2->3->4->5->2->3->4->5->2->3->4->5->2->3->4->5->2->3->4->5->2->3->... (going on forever)
Which is why you run out of memory when trying to print that infinite beast.
First mistake: You need to actually make sure the element that will be the new last element does no longer have your former last element as next.
Second mistake: Your head element should have the former last element as next, not the next elements of its former next element.
// Edge case: list has zero or 1 node:
if(head == null || head.next == null) {
return;
}
Node prev = null;
Node last = head;
while(last.next != null){
prev = last;
last = last.next;
}
Node tmp = head.next;
head.next = last;
last.next = tmp;
// Prevent loop by setting the next of the new last to null
prev.next = null;
public void Manipulate() {
Node penultimate = null;
Node last = head;
while(last.next != null){
penultimate = last;
last = last.next;
}
if (penultimate != null){ // closes the list
penultimate.next = null;
}
if (last != head) { // move last element to second place
last.next = head.next;
head.next = last;
}
}

Implementing a linkedlist in java

I am learning data structures current and below is my implementation for linkedlist.I have kept it as simple as possible as my aim here is to understand the logic.
/*
* Singly linked list
*/
package linkedlisttest;
class Node {
int data;
Node next;
public Node(int data)
{
this.data = data;
}
}
class LinkedList {
Node head;
public void add(int data)
{
if (head == null)
{
head = new Node(data);
return;
}
Node current = head;
while (current.next != null) {
current = current.next;
}
current.next = new Node(data);
}
public int getSize() {
int i = 0;
Node current = head;
while (current != null) {
i += 1;
current = current.next;
}
return i;
}
public void add(int data, int index)
{
if (head == null && index == 0)
{
head = new Node(data);
return;
} else if (head == null && index != 0) {
return; // invalid position
} else if ( index > getSize() ) {
return;
}
Node current = head;
//iterate through whole list
int pos = -1;
Node previous = null;
Node next = null;
Node newNode = new Node(data);
//find next and previous nodes with relation to position
while (current != null) {
if (pos == index - 1) {
previous = current;
} else if (pos == index + 1) {
next = current;
}
pos++;
current = current.next;
}
previous.next = newNode;
newNode.next = next;
}
public void print()
{
Node current = head;
while (current.next != null) {
System.out.print(current.data + "->");
current = current.next;
}
System.out.print(current.data);
}
}
public class LinkedListTest {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
LinkedList lt = new LinkedList();
lt.add(3);
lt.add(5);
lt.add(6);
lt.add(4,1);
lt.print();
}
}
The bug happens for lt.add(4,1) and i suspect its an off by one error.
Expected output: 3->4->6
Actual output: 3->5->4
Thanks for the help guys...
Edit
Thanks to #StephenP and #rosemilk for their help.Indeed the code above has a logical bug as it replaces the value at index and not add it.
Here is the new optimized code
/*
* Singly linked list
*/
package linkedlisttest;
class Node {
int data;
Node next;
public Node(int data) {
this.data = data;
}
}
class LinkedList {
Node head;
int size;
/**
*
* #param data element to add to list
* Time Complexity : O(n)
*/
public void add(int data) {
if (head == null) {
head = new Node(data);
size += 1;
return;
}
Node current = head;
while (current.next != null) {
current = current.next;
}
current.next = new Node(data);
size += 1;
}
/**
*
* #return size of list
* Time Complexity: O(1)
* This is because we use a class
* variable size to keep track of size of linked list
*/
public int getSize() {
return size;
}
/**
*
* #param data element to insert
* #param index position at which to insert the element (zero based)
* Time Complexity : O(n)
*/
public void add(int data, int index) {
if (index > getSize()) {
return; // invalid position
}
Node current = head; //iterate through whole list
int pos = 0;
Node newNode = new Node(data);
if (index == 0) // special case, since its a single reference change!
{
newNode.next = head;
head = newNode; // this node is now the head
size += 1;
return;
}
while (current.next != null) {
if (pos == index - 1) {
break;
}
pos++;
current = current.next;
}
// These are 2 reference changes, as compared to adding at index 0
newNode.next = current.next; // here we are changing a refernce
current.next = newNode; // changing a reference here as well
size += 1;
}
/**
* Prints the whole linked list
* Time Complexity : O(n)
*/
public void print() {
if(getSize() == 0) { //list is empty
return;
}
Node current = head;
while (current.next != null) {
System.out.print(current.data + "->");
current = current.next;
}
System.out.print(current.data + "\n");
}
}
public class LinkedListTest {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
LinkedList lt = new LinkedList();
lt.print();
lt.add(3);
lt.add(5);
lt.add(6);
lt.print();
lt.add(4, 1);
lt.print();
lt.add(4, 7);// 7 is an invalid index
lt.add(8, 3);
lt.print();
}
}
Your add (int , int ) function has a logical bug and can be made better. You don't need previous current and next references, and can cleverly manipulate the list using just the reference to current node, handling inseration at index 0 separately. I would write the add function as follows
public void add(int data, int index)
{
if ( index > getSize() ) {
return; // invalid position
}
Node current = head; //iterate through whole list
int pos = 0;
Node newNode = new Node(data);
if (index == 0) // special case, since its a single reference change!
{
newNode.next = head;
head = newNode; // this node is now the head
return;
}
while (current.next != null) {
if (pos == index - 1) {
break;
}
pos++;
current = current.next;
}
// These are 2 reference changes, as compared to adding at index 0
newNode.next = current.next; // here we are changing a refernce
current.next = newNode; // changing a reference here as well
}
Also, your print function gives a NullPointerException when you try to print an empty list. I would write the print function like this,
public void print()
{
Node current = head;
while (current != null) {
System.out.print(current.data + "->");
current = current.next;
}
System.out.println("null"); // this is just to say last node next points to null!
}
Hope this helps :)
Currently, if you print out pos in your loop, the indices are -1, 0, 1 (instead of 0, 1, 2), so it'll never "find" the correct next. Replace int pos = -1; with int pos = 0; and it'll work.
I do agree with #StephenP that the output should (arguably) be 3->4->5->6, but that's a design decision.

Insertion in sorted doubly linked list

I am given the pointer to the head node of a sorted doubly linked list and an integer to insert into the list.I am told to create a node and insert it into the appropriate position in the list such that its sorted order is maintained. The head node might be NULL.
Sample Input
NULL , data = 2
NULL <-- 2 <--> 4 <--> 6 --> NULL , data = 5
Sample Output
NULL <-- 2 --> NULL
NULL <-- 2 <--> 4 <--> 5 <--> 6 --> NULL
I tried the above problem.But My program is terminating due to timeout.What am I doing wrong in the below code. Assume Node class and main function is already there. Many Thanks in advance!!
Node SortedInsert(Node head,int data) {
Node newn = new Node();
newn.data = data;
newn.prev=null;
newn.next = null;
Node ptr = head;
Node nex=head.next;
while(ptr!=null && nex!=null) {
if(ptr.data<=newn.data && nex.data>=newn.data) {
newn.next = nex;
newn.prev = ptr;
nex.prev = newn;
ptr.next = newn;
}
else {
nex=nex.next;
ptr=ptr.next;
}
}
if(ptr!=null && nex==null) {
if(ptr.data>=newn.data) {
newn.next=ptr;
ptr.prev=newn;
newn.prev=null;
head=newn;
}
else {
ptr.next=newn;
newn.prev = head;
}
}
if(head==null) {
head = newn;
}
return head;
}
Fairly simple:
You are not breaking out of the loop after succesfully inserting. Therefore it keeps looping over the position it inserts the node in. Make a tiny change:
if(ptr.data>=newn.data)
{
newn.next=ptr;
ptr.prev=newn;
newn.prev=null;
head=newn;
break;
}
However, you have some redundant code written. This is shorter and doesn't contain redundant code:
Node SortedInsert(Node head,int data) {
Node newn = new Node();
newn.data = data;
Node ptr = head;
if (ptr == null) {
head = newn;
} else if ( ptr.data > newn.data ) {
newn.next = ptr;
ptr.prev = newn;
head = newn;
} else {
Node nex = head.next;
while (nex != null && nex.data <= newn.data) {
ptr = nex;
nex = nex.next;
}
ptr.next = newn;
newn.prev = ptr;
if (nex != null) {
nex.prev = newn;
newn.next = nex;
}
}
return head;
}
If the head node is null you'll geta NullPointerException while trying to get the next/prev nodes. You should check that first:
Node sortedInsert(Node head, int data) {
Node newn = new Node();
newn.data = data;
//Basic case: the list is empty, so the head is null
if (head==null) {
return newn;
}
//If node is not null
Node aux= head;
Node auxPrev;
while (aux!=null && aux.data<data) {
auxPrev=aux;
aux=aux.next;
}
//auxPrev will be null if we are going to insert in the first position
if (auxPrev!=null)
auxPrev.next=newn;
newn.prev=auxPrev;
head=newn;
}
//aux will be null if we insert in the last position
if (aux!=null) {
aux.prev=newn;
newn.next=aux;
}
return head;
}

Categories