Find pair for given sum in a sorted singly linked without extra space in C++

C++Server Side ProgrammingProgramming

Concept

With respect of a given sorted singly linked list and a value x, our task is to determinepair whose sum is equal to x. Here we are not permitted to use any extra space and expected time complexity be O(n).

Input

head = 4-->7-->8-->9-->10-->11-->12 , x=19

Output

(7, 12), (8, 11), (9, 10)

Method

According to a simple solution for this problem, we take each element one by one and visit the rest list in forward direction to determine second element whose sum is equal to given value x. Here, time complexity for this method will be O(n^2).

We discuss an efficient solution for this problem in following topic.

Find pair in doubly linked list − The method is explained in below.

According to a simple approach for this problem, we pick each node one by one and determine second element whose sum is equal to x in the rest list by visiting in forward direction.Here, time complexity for this problem will be O(n^2) , where n is total number of nodes in doubly linked list.

An efficient solution for this problem is discussed. Here are the steps of the algorithm −

We initialize two pointer variables to determine the candidate elements in the sorted doubly linked list.

We initialize first1 with start of doubly linked list that means, first1=head and initialize second1 with last node of doubly linked list that means, second1=last_node.

Now we initialize first and second pointers as first and last nodes. In this case we don’t have random access, so to determine second pointer, we visit the list to initialize second1.

It has been seen that if current sum of first1 and second1 is smaller than x, then we move first1 in forward direction. Otherwise if current sum of first1 and second1 is greater than x, then we move second1 in backward direction.

Finally, loop termination conditions are also different from arrays. In this case, the loop ends when either of two pointers become NULL, or they cross each other (second1->next = first1), or they become same (first1 == second1).

XOR Linked list − With respect of singly linked list, we can visit list only in forward direction. We implement XOR concept to convert a singly linked list to doubly linked list.Following are steps −

  • At first we need to convert our singly linked list into doubly linked list. In this case, we are given singly linked list structure node which have only next pointernot prev pointer, as a result of this,to convert our singly linked list into doubly linked list we implementmemory efficient doubly linked list ( XOR linked list ).

  • With respect of XOR linked list, each next pointer of singly linked list containsXOR of next and prev pointer.

  • Here, after converting singly linked list into doubly linked list we initialize two pointers variables to determine the candidate elements in the sorted doubly linked list. We initialize first1 with start of doubly linked list i.e; first1 = head and initialize second1 with last node of doubly linked list i.e; second1 = last_node.

  • At present we don’t have random access, so for initializing pointer, we visitthe list until last node and assign last node to second1.

  • It has been seen that if current sum of first1 and second1 is smaller than x, then we move first1 in forward direction. Otherwise if current sum of first1 and second1 isgreater than x, then we move second1 in backward direction.

  • Finally, loop termination conditions are also different from arrays. In this case, the loop ends when either of two pointers become NULL, or they cross each other (second1->next = first1), or they become same (first1 == second1).

Example

 Live Demo

// C++ program to find pair with given sum in a singly
// linked list in O(n) time and no extra space.
#include<bits/stdc++.h>
using namespace std;
/* Shows Link list node */
struct Node1{
   int data1;
   /* also contains XOR of next and
   previous node after conversion*/
   struct Node1* next1;
};
/* With respect of a given reference (pointer to pointer) to the
head of a list and an int, push a new node on the front of the
list. */
void insert(struct Node1** head_ref1, int new_data1){
   /*Used to allocate node */
   struct Node1* new_node1 =
   (struct Node1*) malloc(sizeof(struct Node1));
   /* Used to put in the data */
   new_node1->data1 = new_data1;
   /* Shows link the old list off the new node */
   new_node1->next1 = (*head_ref1);
   /* Used to move the head to point to the new node */
   (*head_ref1) = new_node1;
}
/* Here returns XORed value of the node addresses */
struct Node1* XOR (struct Node1 *p, struct Node1 *q){
   return (struct Node1*) ((uintptr_t) (p) ^ (uintptr_t) (q));
}
// Shows utility function to convert singly linked list
// into XOR doubly linked list
void convert(struct Node1 *head1){
   // At first we store address of next node in it
   // then take XOR of next node and previous node
   // and store it in next pointer
   struct Node1 *next_node1;
   // Here prev1 node stores the address of previously
   // visited node
   struct Node1 *prev1 = NULL;
   // Used to traverse list and store xor of address of
   // next_node1 and prev1 node in next pointer of node
   while (head1 != NULL){
      // Shows address of next node
      next_node1 = head1->next1;
      // Shows xor of next_node1 and prev1 node
      head1->next1 = XOR(next_node1, prev1);
      // Used to update previous node
      prev1 = head1;
      // Used to move head1 forward
      head1 = next_node1;
   }
}
// Shows function to determine pair whose sum is equal to
// given value x1
void pairSum(struct Node1 *head1, int x1){
   // Used to initialize first1
   struct Node1 *first1 = head1;
   // next_node1 and prev1 node to compute xor again
   // and determine next and prev node while moving forward
   // and backward direction from both the corners
   struct Node1 *next_node1 = NULL, *prev1 = NULL;
   // Used to traverse list to initialize second pointer
   // here we need to move in forward direction so to
   // compute next address we have to take xor
   // with prev pointer because (p^q)^q = p
   struct Node1 *second1 = head1;
   while (second1->next1 != prev1){
      struct Node1 *temp1 = second1;
      second1 = XOR(second1->next1, prev1);
      prev1 = temp1;
   }
   // At present traverse from both the corners
   next_node1 = NULL;
   prev1 = NULL;
   // Now if we want to move forward then we must
   // know the prev1 address to compute next node
   // and if we want to move backward then we must
   // know the next_node1 address to calculate prev1 node
   bool flag1 = false;
   while (first1 != NULL && second1 != NULL && first1 != second1 && first1 != next_node1){
      if ((first1->data1 + second1->data1)==x1){
         cout << "(" << first1->data1 << ","<< second1->data1 << ")" << endl;
         flag1 = true;
         // Used to move first in forward
         struct Node1 *temp1 = first1;
         first1 = XOR(first1->next1,prev1);
         prev1 = temp1;
         // Used to move second in backward
         temp1 = second1;
         second1 = XOR(second1->next1, next_node1);
         next_node1 = temp1;
      } else {
         if ((first1->data1 + second1->data1) < x1){
            // Used to move first in forward
            struct Node1 *temp1 = first1;
            first1 = XOR(first1->next1,prev1);
            prev1 = temp1;
         } else {
            // Used to move second in backward
            struct Node1 *temp1 = second1;
            second1 = XOR(second1->next1, next_node1);
            next_node1 = temp1;
         }
      }
   }
   if (flag1 == false)
   cout << "No pair found" << endl;
}
// Driver program to run the case
int main(){
   /* Begin with the empty list */
   struct Node1* head1 = NULL;
   // int x1 = 17;
   int x1 = 19;
   /* Use insert() to construct below list 3-->6-->7-->8-->9-->10-->11 */
   /* insert(&head1, 11);
   insert(&head1, 10);
   insert(&head1, 9);
   insert(&head1, 8);
   insert(&head1, 7);
   insert(&head1, 6);
   insert(&head1, 3); */
   /* Use insert() to construct below list 4-->7-->8-->9-->10-->11-->12 */
   insert(&head1, 12);
   insert(&head1, 11);
   insert(&head1, 10);
   insert(&head1, 9);
   insert(&head1, 8);
   insert(&head1, 7);
   insert(&head1, 4);
   // Used to convert singly linked list into XOR doubly
   // linked list
   convert(head1);
   pairSum(head1,x1);
   return 0;
}

Output

(7,12)
(8,11)
(9,10)
raja
Published on 25-Jul-2020 14:29:14
Advertisements