Data structures linked list - algorithm

I was asked to solve this out:
There are two singly linked lists.
I need to write a method which get those two linked lists and returns a pointer to the starting point where the suffix is the same in those two lists.
Example:
given:
1->2->4->6->8->10->15
2->4->8->10->15
the returned value would be a pointer to the member - 8.
But,
I need to do it without changing the lists or using more memory,
and - we need to scan the lists only once, means T(n)=O(n).

measure the lengths of both lists
skip forward in the longer list until they're the same length
walk forward through both lists in step, and remember the nodes AFTER the last point where the lists have different elements. These are the pointers you can return.
Now... I know you said that you only want to scan the lists once, and I have done it twice, but you also said that this means T(n) = O(n), and that is not correct.
Scanning the lists twice is also in O(n) and is required to solve the problem without using unbounded extra memory.

This is a psuedocode.. not Python code for that matter
take the two lists and let p1 point to longer list and p2 point to shorter list,
while p1->next!=NULL:
if p1->value = p2->value:
p1 = p1->next
p2 = p2->next
else:
p1 = p1->next
returnpointer = p1->next// if it happens that some elements are same towards end but not the last element.. p1->next would be pointing to NULL anyways and else.. it'll always be the element next to the last element which wasn't same
return returnpointer

Related

Finding the kth last element of a singly linked list: answer explanation

When you need to find the kth last element of a singly linlked list, the usual naive approach is to perform two passes. The first to find the length of the list and the second to iterate until the (length-k)th element.
Whereas the optimized version takes advantage of two pointers:
p1 refering to the head of the list
p2 being kth elements ahead of p1
This allows us to return p1's element when p2 reaches the end of the list.
I don't understand why the second approach is faster than the first when in both cases we have one pointer iterating all over the list and another until the (length-k)th element.
Is it due to cache optimization?
Thanks.
If you keep p2 exactly k elements behind p1, then it doesn't really help much, since you have to do the same number of traversals all together.
You can optimize the procedure by using more pointers, though.
As you walk though the list, lets say you remember the pointer at every (k/m)th position, for some m. You only need to remember the last m+1 of those pointers. Then, when you get to the end of the list, instead of iterating again from the beginning, start at the oldest pointer you remembered. It will be between k and k + (k/m) elements behind the end, so you only have to move it forward by at most k/m positions.
Consider non-uniform memory access times and a singly linked list of length n:
- in the counted iteration approach, accesses to the same node will be n accesses apart
- in the lagging pointer approach, accesses to the same node will be k accesses apart
With an LRU cache (/with each LRU cache level), the former is more likely to induce capacity misses than the latter.

Reverse a sublist of a doubly linked list

I recently came up with a problem, and with some reading I understood that there's a way to reverse a doubly linked list in constant time, just by swapping head and tail pointers.
Now, thinking of a slightly different version of the problem, if we want to reverse just a sublist of the doubly linked list (from x to y), how could it be done?
0->1->2->3->4->5->6->7->8->9 with (x = 2, y = 7)
would become:
0->1->7->6->5->4->3->2->8->9
You can but you mess the linked list a lot.
Basically we add a bit to each node that says if you should reverse order at this point.
Next you modify the iterator to xor all these new bits it's seen so far.
The iterator will now pick next/prev or prev/next depending on the xor of the bits.
Now you can reverse arbitrary intervals in the linked list in O(1), BUT you loose iterator consistency: any swap operation might invalidate existing iterators. Also the code will be very confusing so I would avoid it if at all possible.
To do the actual flip you change (add null-checking to make sure you don't crash)
(first->prev,last->next) = (last->next, first->prev)
last->next->next = last
first->prev->prev = first
last.reverse_here = !last.reverse_here
first->prev.reverse_here = !first->prev.reverse_here
Invalidate_all_existing_iterators()
Draw it on paper because it's very confusing.
way to reverse a doubly linked list in constant time
It is not possible, however it is possible in linear time O(n)
Answer to question : You have to manage "start" and "end" differently than the rest. If you start from 7 and goes to 2, you remember this pointer 7-> and store it in variable X. It stores pointer to 8. Then you continue as usual.
When you reach the 2, you put 2.head = X.
The similar thing must be done for 1->7, but you should figure it out.
Edit about constant time : you can rewrite iterator in constant time, however the data structure itself remains unchanged. Therefore with only changing iterator, you cant take reversed data itself and do some stuff with it - because it is not really reversed.
PS : In arraylist you can change iterator in constant time even for sublist.

How to find a common node of two intersecting linked lists

We have a project in our Data Structures course and I am stuck with one of the problems.
I could not find any suitable solution for this problem in the web due to the special complexity limitations we where given.
The Problem:
let there be two Linked Lists, which intersect after m and n nodes (and continue). the first list has m nodes before the common node and the second one has n nodes up to the common node.
(m and n are not known).
There are two pointers L1, L2 to the first link in each list.
There is NO pointer to the end of any list.
The problem is to find the common node within limitations of O(m+n) [we cant run to the end of any of the links...], with a limit of O(1) additional memory [No option of changing/adding additional data in every link].
The two lists have only pointers pointing forwards (Singly Linked List).
The list pointers can be changed, but the order of the original list needs to be restored.
[although a solution that will ruin the list is also better than nothing].
I am after days of drawing lists and nodes.... losing my mind here :)
Thanks a lot,
Barak.
You already know the number of elements before the common node in each list.
... the first list has m nodes before the common node ...
Just skip that number of nodes in the corresponding list to reach to the common intersecting node.
I am not sure if you are asking the right question here. Kindly update if there is a change in your problem statement.
->Update:
Iterate each list to find its length.
length(List1) = x
length(List2) = y
Let x > y
skip (x-y) nodes on List1.
Traverse List1 and List2 simultaneously and compare the nodes of both the lists. When you find the nodes on both lists to be equal, that will be your point of intersection.

Getting the nth to last element in a linked list

We have a linked list of size L, and we want to retrieve the nth to the last element.
Solution 1: naive solution
make a first pass from the beginning to the end to compute L
make a second pass from the beginning to the expected position
Solution 2: use 2 pointers p1, p2
p1 starts iterating from the beginning, p2 does not move.
when there are n elements between p1 and p2, p2 starts iterating as well
when p1 arrives at the end of the list, p2 is at the expected position
Both solutions seem to have the same time complexity (i.e, 2L - n iterations over list elements)
Which one is better?
Both those algorithms are two-pass. The second may have better performance for reasonably small n because the second pass accesses memory that is already cached by the first pass. (The passes are interleaved.)
A one-pass solution would store the pointers in a circular buffer or queue, and return the "head" of the queue once the end of the list is reached.
How about using 3 pointers p, q, r and a counter.
Iterate through the list with p updating the counter.
Every n nodes assign r to q and q to p
When you hit the end of the list you can figure out how far
r is from the end of the list.
You can get the answer in no more than O(L + n)
If n << L, solution 2 is typically faster, because of caching, i.e. the memory blocks containing p1 and p2 are copied to the CPU cache once and the pointers moved for a bunch of iterations before RAM needs to be accessed again.
Would it not be much cheaper to simply store the length of the linked list in O(1) memory? The only reason you have to do a "first pass" at all is because you don't know the length of your linked list. If you store the length, you could iterate over (|L|-n) elements every time and get retrieve the element easily. For higher values of n in comparison to L, this way would save you substantial amounts of time. For example if n was equal to |L|, you could simply return the head of the list with no iteration at all.
This method uses slightly more memory than your first algorithm since it stores the length in memory, but your second algorithm uses two pointers, whereas this method only uses 1 pointer. If you have the memory for a second pointer, you probably have the memory to store the length of your linked list.
Granted O(|L|-n) is equivalent to O(n) in pure theory, but there are "fast" linear algorithms and then there are "slow" ones. Two-pass algorithms for this kind of problem are slow.
As #HotLicks pointed out in the comments, "One needs to understand that "big O" complexity is only loosely related to actual performance in many cases, since it ignores additive factors and constant multipliers." IMO just go for the laziest method in this case and don't overthink it.

Break the linked list into smaller linked lists

I need to break a singly linked list into smaller linked lists after every 2 nodes . The approach I thought was,
create an array containign head pointers of n/2 objects
Link hop the linked list and store the address in the array after
every 2 nodes are encountered.
Can there be a better approach for this?
Thanks.
That seems like a good approach.
You also need to remember to set the next member of the 2nd, 4th, etc... elements to null to break the long list into smaller pieces. Remember to store the old value before you overwrite it as you will need to use it while you iterate.

Resources