Palindrome Linked List Question - Algorithm - algorithm

class PalindromicLinkedList {
public static boolean isPalindrome(ListNode head) {
if (head == null || head.next == null)
return true;
// find middle of the LinkedList
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode headSecondHalf = reverse(slow); // reverse the second half
ListNode copyHeadSecondHalf = headSecondHalf; // store the head of reversed part to revert back later
ListNode start = head;
// compare the first and the second half
while (start != null && headSecondHalf != null) {
if (start.value != headSecondHalf.value) {
return false; // not a palindrome
}
start = start.next;
headSecondHalf = headSecondHalf.next;
}
reverse(copyHeadSecondHalf); // revert the reverse of the second half
return true;
}
private static ListNode reverse(ListNode head) {
ListNode prev = null;
while (head != null) {
ListNode next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
}
}
This is palindrome linked-list question
Given the head of a Singly LinkedList, write a method to check if the
LinkedList is a palindrome or not.
Your algorithm should use constant space and the input LinkedList should be in the original form once the algorithm is finished. The algorithm should have O(N)O(N) time complexity where ‘N’ is the number of nodes in the LinkedList.
Above code is the solution for this problem,
and I understand most part of it but only have trouble to understand
reverse(copyHeadSecondHalf);
I just may guess this is for the algorithm condition which is that
input LinkedList should be in the original form once the algorithm is finished.
But Above code,
Have we ever changed or modified input LinkedList?
Everytime we just defined new ListNode pointing to the head reference
or some other ones.
Likewise, we just have new variable "headSecondHalf" to have new reversed version LinkedList.
and even we did nothing on copyHeadSecondHalf.
but why should we have
reverse(copyHeadSecondHalf);

But Above code, Have we ever changed or modified input LinkedList? Every time we just defined new ListNode pointing to the head reference or some other ones.
Yes, the original LinkedList is modified.
ListNode headSecondHalf = reverse(slow); // reverse the second half
The above line takes the middle of the LinkedList as input and reverses it. As a result, the structure of LinkedList is changed.
Ex: 5 → 2 → 3 → 2* → 5*
The slow pointer is at position 3.
Now, headSecondHalf points to 5* → 2* → 3
And original list becomes 5 → 2 → 3 (only half of the list) as 3 is pointing to NULL because of the reverse operation.
Likewise, we just have new variable "headSecondHalf" to have new reversed version LinkedList. and even we did nothing on copyHeadSecondHalf.
The headSecondHalf variable is used to check if the list is a palindrome. This means that the position is altered. For this reason, the value is copied to copyHeadSecondHalf, which is reversed again so that the original list is restored.

Consider following example linked list
1->2->3->4->2'->1'->NULL
in the first reverse, we get a new linked list as follows
1'->2'->4->NULL
The original linked list would be as follows
1->2->3->4->NULL
After comparison, we need to restore the linked list as per one of the condition. Hence the reverse step.
However, in the code, while returning false, this last step is not performed, breaking this rule. Hence either you add reverse before returning, or break the while loop, reverse and return at the end

Related

To find loop in a singly linked list without using slow and fast pointer

As we know that for detecting loop in a linked list, we use slow pointer and fast pointer in which firstly we initialize two node slow and fast with head nodethen we traverse fast pointer two step ahead and slow with one step ahead.If we find both addresses are equal, then, there is loop otherwise if fast==null || fast.next==null then there is no loop. Now my question is "Is there any possibility to detect loop in singly linked list without using fast and slow pointer ?"
Any idea will be appreciated.
Thanks in advance.
There are at least two other solutions.
An O(n^2) solution is to keep track of the node numbers. At each node, go back to the head and count how many next operations it takes to reach the current node. If you get to the nth node before you do n next operations, then there's a loop in your list. That is:
// assuming head is not null, and head doesn't point to itself
nodeNumber = 1
current = head.next
while (current != null)
{
p = head
counter = 0
while (p != current && counter < nodeNumber)
{
p = p.next
counter = counter + 1
}
if (p != current)
there's a loop
nodeNumber = nodeNumber + 1
}
A destructive method is to reverse the links as you go. If there's a loop in the linked list, then when your pointer is equal to null it will be at the root. That is:
if (head == null) || (head.next == null)
no loop
prev = head
current = head.next
while (current != null)
{
// save next position
next = current.next
// reverse the link
current.next = prev
// and move to the next node
prev = current
current = next
}
if (prev == head)
there is a loop
That does have the disadvantage of destroying the list if there's a loop in it. If there's not a loop, you can go back through the list and reverse the links.
Yes, of course. Most intuitive way is to traverse each node and check if you have visited this node. If you would have visited this node earlier, this means that there is a cycle and this particular node is the start of cycle.
To check if you have visited this node earlier you can maintain a hash-set which allows you to check for presence of an element in O(1) time complexity.
Check the below pseudo code.
Time Complexity - O(n)
Space Complexity - O(n)
boolean isCyclic(Node head){
HashSet<Node> set = new HashSet<Node>();
while(head != NULL){
if(set.contains(head))
return true;
set.add(head)
head = head.next
}
return false;
}

Flattening a multilevel linked list

Question
Given a linked list where in addition to the next pointer, each node
has a child pointer, which may or may not point to a separate list.
Given the head of the first list flatten the list so that all the
nodes appear in a single-level linked list.
Goal.
We need to flatten the list in such a way that all nodes at first level
should come first, then
nodes of second level, and so on.
The above list should be converted to
10->5->12->7->11->4->20->13->17->6->2->16->9->8->3->19->15
My approach:
1) Create an empty queue
2) while(Queue is not empty AND head.next!=null AND head.child!=null)
2a) while(head!=null)
if(head.child!=null)
Enqueue(head.child)
newList = head;
head = head.next;
newList = newList.next;
2b)head = deQ();
Is this approach correct?
Here's a simple two-finger breadth-first (level-order) traverse which does an in-place flattening. (Efficiency freaks might want to rearrange the loops because some tests are done twice, but it hardly makes a difference.) The basic idea is that there is an implicit queue consisting of the nodes between finger2 and finger1. finger1 walks forward across the level and every time it reaches a node with no right sibling, the "queue" is advanced by walking finger2 to the right until it finds a child, which is then appended at finger1 so that finger1 can keep moving to the right.
finger1 = finger2 = head;
while finger2 is not Null:
while finger1.next is not Null: finger1 = finger1.next
while finger2 is not Null and finger2.child is Null: finger2 = finger2.next
if finger2 is not Null:
finger1.next = finger2.child
finger2.child = Null
Simple stack based solution which traverses till next ends, then attaches the children from stack.
node *flatten(node *head) {
stack<node *> s;
node *curr = root;
while (1) {
if (curr->next) { // keep moving in current streak
if (curr->child)
s.push(curr);
curr = curr->next;
}
else { // attach child branch and continue from there
if (s.empty())
return head;
curr->next = s.top()->next;
s.top()->next = NULL;
s.pop();
curr = curr->next;
}
}
}

Implementing Consolidate in Fibonacci heap

The pseudocode from Introduction to Algorithms states:
for each node w in the root list of H
link trees of the same degree
But how to efficiently implement the for each root node part? Original roots are linked to other roots of the same degree throughout the process of consolidation, which makes it difficult to just pass through the circular list of root nodes. How can I decide whether I have checked every root node or not?
One simple way that you could do this would be to use a three-step process:
Break the circular link so that the list is now just a normal doubly-linked list.
Iterate over the doubly-linked list and process each tree. This is tricky because, as you've mentioned, the forward and next pointers on each node might change during the iteration.
Close the cycle.
Here's how you might do each step:
Break the circular link:
rootList->prev->next = NULL;
rootList->prev = NULL;
Iterate over the doubly-linked list.
Node* current = rootList;
while (current != NULL) {
/* Cache the next node to visit so that even if the list changes, we can still
* remember where to go next.
*/
Node* next = current->next;
/* ... main Fibonacci heap logic ... */
current = next;
}
Repair the doubly-linked list:
Node* curr = rootList;
if (curr != NULL) { // If list is empty, no processing necessary.
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = rootList;
rootList->prev = curr;
}
Hope this helps!

How to check if a circular single linked list is pallindrome or not?

Question: I have a single linked list (i.e. a list with only pointer to the next node). Additionally this is a circular linked list (in this example, the last node has a pointer to the first node). Every node in the list contains a char.
An example of such a list can be: a->b->c->b->a
Now how can I verify if this list is a pallindrome?
I have thought of the following solution:
Start from the head of list. Find the length of the list and then the mid node. Now start again from the head of the list and keep pushing elements in stack until the mid. Now traverse the list from the mid and pop element. If the value of the popped element is equal to the value of the current node. if not, return false. otherwise, continue until the stack is empty and we've verified all chars. CONS: uses extra stack space :(
Start from the head of list. Find the length of the list and then the mid node. now reverse the 2nd half of this list. and then using 2 pointers (one pointing to start and the other pointing to the mid+1'th element), check if the values are same. if not, return false. else continue until we reach the start node again. CONS: Changing original data structure.
Is there a more elegant way to approach this problem (which hopefully does not use O(n) extra space or changes original list)? I'm interested in the algorithm rather than any specific implementation.
Thanks
Since you're dealing with a single linked list, you must use a little extra space or a lot more extra time.
Your first approach sounds reasonable, but you can determine the length of the list and palindrome-ness in a single run.
We modify the so-called Floyd's Cycle-Finding Algorithm:
two pointers, "slow" and "fast", both start at the list head; the slow pointer advances one list element per iteration, the fast pointer two elements
in each step, the slow pointer pushes the current element on the stack
if the fast pointer reaches the end of the list, the slow pointer points to the middle of the list, so now:
the slow pointer advances to the end of the list, and in each step:
it pops one element from the stack and compares it to the current list element (if they are not equal, return false)
if the slow pointer reaches the end of the list, it is a palindrome
A little extra work is required for lists with an odd number of elements.
This is in pseudo-Haskell (I can't remember the exact syntax these days) and I've written for the non-circular case -- to fix that, just replace the clause matching against [] with whatever condition you use to identify you've come full circle.
p(xs) = q(xs, Just(xs)) != Nothing
q([], maybeYs) = maybeYs
q(x : xs, Nothing) = Nothing
q(x : xs, maybeYs) =
let maybeZs = q(xs, maybeYs) in
case maybeZs of
Nothing -> Nothing
Just (x :: zs) -> Just(zs)
otherwise -> Nothing
Since you know the Linked List does make a cycle, and you are only looking for palindromes starting at head, you can make this easier on yourself.
A -> B -> C -> B -> A
In this case, start with a pointer at head (call it H), and a pointer at head.Left() (call it T).
Now keep moving the head pointer H to the right, and the tail pointer T to the left.
As you walk the list, verify that the values of those elements are equal (i.e. a palindrome).
Your stopping condition however take a bit more. There are two cases:
Both pointers end point at the same element (i.e. odd number of elements)
The H pointer is pointing at the element just to the right of T.
So, you stop if H==T or if H==(T.Right()).
Using this approach (or similar) you visit each element just once.
Use the Tortoise and Hare approach as in the other solutions if you don't know if the linked list is cyclic.
Just paste my implementation so we could compare with each others, full test here:
/**
* Given a circular single linked list and the start pointer, check if it is a palindrome
* use a slow/fast pointer + stack is an elegant way
* tip: wheneve there is a circular linked list, think about using slow/fast pointer
*/
#include <iostream>
#include <stack>
using namespace std;
struct Node
{
char c;
Node* next;
Node(char c) {this->c = c;}
Node* chainNode(char c)
{
Node* p = new Node(c);
p->next = NULL;
this->next = p;
return p;
}
};
bool isPalindrome(Node* pStart)
{
Node* pSlow = pStart;
Node* pFast = pStart;
stack<Node*> s;
bool bEven = false;
while(true)
{
// BUG1: check fast pointer first
pFast = pFast->next;
if(pFast == pStart)
{
bEven = false;
break;
}
else
{
pFast = pFast->next;
if(pFast == pStart)
{
bEven = true;
break;
}
}
pSlow = pSlow->next;
s.push(pSlow);
}
if(s.empty()) return true; // BUG2: a, a->b->a
if(bEven) pSlow = pSlow->next; // BUG3: a->b->c->b->a, a->b->c->d->c->b->a: jump over the center pointer
while(!s.empty())
{
// pop stack and advance linked list
Node* topNode = s.top();
s.pop();
pSlow = pSlow->next;
// check
if(topNode->c != pSlow->c)
{
return false;
}
else
{
if(s.empty()) return true;
}
}
return false;
}
I think we dont need an extra space for this. And this can be done with O(n) complexity.
Modifying Philip's solution:
We modify the so-called Floyd's Cycle-Finding Algorithm:
Two pointers, "slow" and "fast", both start at the list head; the slow pointer advances one list element per iteration, the fast pointer two elements
in each step, the slow pointer pushes the current element on the stack
if the fast pointer reaches the end of the list, the slow pointer points to the middle of the list, so now:
Have another pointer at the start of the linked-list (start pointre) and now -
move the start pointer and the slow pointer one by one and compare them - if they are not equal, return false
- if the slow pointer reaches the end of the list, it is a palindrome
This is O(n) time complexity and no extra space is required.

How to determine if a linked list has a cycle using only two memory locations

Does anyone know of an algorithm to find if a linked list loops on itself using only two variables to traverse the list. Say you have a linked list of objects, it doesn't matter what type of object. I have a pointer to the head of the linked list in one variable and I am only given one other variable to traverse the list with.
So my plan is to compare pointer values to see if any pointers are the same. The list is of finite size but may be huge. I can set both variable to the head and then traverse the list with the other variable, always checking if it is equal to the other variable, but, if I do hit a loop I will never get out of it. I'm thinking it has to do with different rates of traversing the list and comparing pointer values. Any thoughts?
I would suggest using Floyd's Cycle-Finding Algorithm aka The Tortoise and the Hare Algorithm. It has O(n) complexity and I think it fits your requirements.
Example code:
function boolean hasLoop(Node startNode){
Node slowNode = Node fastNode1 = Node fastNode2 = startNode;
while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
if (slowNode == fastNode1 || slowNode == fastNode2) return true;
slowNode = slowNode.next();
}
return false;
}
More info on Wikipedia: Floyd's cycle-finding algorithm.
You can use the Turtle and Rabbit algorithm.
Wikipedia has an explanation too, and they call it "Floyd's cycle-finding algorithm" or "Tortoise and hare"
Absolutely. One solution indeed can be traversing the list with both pointers, one travelling at twice the rate of the other.
Start with the 'slow' and the 'fast' pointer pointing to any location in the list. Run the traversal loop. If the 'fast' pointer at any time comes to coincide with the slow pointer, you have a circular linked list.
int *head = list.GetHead();
if (head != null) {
int *fastPtr = head;
int *slowPtr = head;
bool isCircular = true;
do
{
if (fastPtr->Next == null || fastPtr->Next->Next == null) //List end found
{
isCircular = false;
break;
}
fastPtr = fastPtr->Next->Next;
slowPtr = slowPtr->Next;
} while (fastPtr != slowPtr);
//Do whatever you want with the 'isCircular' flag here
}
I tried to solve this myself and found a different (less efficient but still optimal) solution.
The idea is based on reversing a singly linked list in linear time. This can be done by doing two swaps at each step in iterating over the list. If q is the previous element (initially null) and p is the current, then swap(q,p->next) swap(p,q) will reverse the link and advance the two pointers at the same time. The swaps can be done using XOR to prevent having to use a third memory location.
If the list has a cycle then at one point during the iteration you will arrive at a node whose pointer has already been changed. You cannot know which node that is, but by continuing the iteration, swapping some elements twice, you arrive at the head of the list again.
By reversing the list twice, the list remains unchanged in result and you can tell if it had a cycle based on whether you arrived at the original head of the list or not.
int isListCircular(ListNode* head){
if(head==NULL)
return 0;
ListNode *fast=head, *slow=head;
while(fast && fast->next){
if(fast->next->next==slow)
return 1;
fast=fast->next->next;
slow=slow->next;
}
return 0;
}
boolean findCircular(Node *head)
{
Node *slower, * faster;
slower = head;
faster = head->next;
while(true) {
if ( !faster || !faster->next)
return false;
else if (faster == slower || faster->next == slower)
return true;
else
faster = faster->next->next;
}
}
Taking this problem to a next step will be identifying the cycle (that is, not just that the cycle exists, but where exactly it is in the list).
Tortoise and Hare algorithm can be used for the same, however, we will require to keep track of the head of the list at all times. An illustration of this algorithm can be found here.

Resources