I've been practicing different interview problems and I came across a problem that I can't seem to resolve when stepping through the code by hand.
The problem is to write a function that partitions a linked list around a value x such that all nodes less than x come before all the nodes great than or equal to x.
[3, 5, 8, 5, 10, 2 ,1] where x=5
Should output something like: [1, 2, 3, 5, 8, 5, 10] (output can vary depending on implementation).
Here's the solution:
LinkedListNode* partition(LinkedListNode* node, int x)
{
LinkedListNode* head = node;
LinkedListNode* tail = node;
while (node)
{
LinkedListNode* next = node->next;
if (node->data < x)
{
node->next = head;
head = node;
} else {
tail->next = node;
tail = node;
}
node = next;
}
tail->next = nullptr;
return head;
}
I know the solution works and when run on the linked list above, I get the following output: [1, 2, 3, 5, 8, 5, 10]
When I run through this by hand, I get confused. When first iterating through the linked list, node, head, tail all point towards the node that has the value of 3. Now we're in the if statement.
We set node->next to head, which now points to itself (the one with node->data = 3)! After iterating through the entire list, this node's next field always points to itself.
Clearly, this function is working as intended but I must be stepping through it wrong. Any insight into what I'm overlooking??
Thanks!
edit: clarification
Related
I was working on Stack Overflow and came up across the #92.
Reverse a linked list 2 question. This is the question's description:
Given the head of a singly linked list and two integers left and right
where left <= right, reverse the nodes of the list from position left
to position right, and return the reversed list. For example, given
the linked list [1,2,3,4,5] 1, 4 the list should become [4,2,3,1,5]
It works for all runs but my code produces the wrong answer for one test case, which doesn't make sense. given. [1,2,3,4] 1,4 with 1 being left position an 4 being right position what makes sense for the list to become is [4,2,3,1] which is what my code produces. The correct answer they display is [4,3,2,1] which is screwing with my head and I can't understand why it's doing that. Any heads up are appreciated.
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right)
{
int x = 1;
ListNode * left_node = nullptr;
ListNode * right_node = nullptr;
ListNode * curr = head;
int temp = 0;
if (!head)
return nullptr;
while(curr)
{
if(x == left)
left_node = curr;
if(x == right)
right_node = curr;
curr = curr->next;
++x;
}
temp = left_node->val;
left_node->val = right_node->val;
right_node->val = temp;
return head;
}
Your solution implements swapping the values for the 2 indexes left and right, which matches the example given in the question.
But the question was to reverse the list between left and right, not just swap the two end points. So 1,2,3,4 becoming 4,3,2,1 is the correct solution and both the example and your solution are wrong, they only swap the entpoints.
PS: Most languages start counting at 0.
#Goswin Von Brederlow has already pointed out what is wrong, I will add a visual representation of what you are doing. Can you spot the problem?
EDIT: You can look in the comments for a better solution in terms of time and space (and also for a worse one).
After the while you should traverse the linked list. Since you don't have a "prev" (no double linked list) you need to traverse it multiple times to reverse it. I prepared a visualization of the algo, which uses a copy from left to right. And a support node for the prev node at each iteration. It uses idx and oidx to keep track of the position in the original and copied list.
And here are the steps of the iteration:
I'm working on some homework for a CS class, and struggling a bit with a function that's meant to reverse a doubly linked list between two given nodes. I'm pretty confused about what I'm doing wrong, and I've searched google and SO and I can't find anything that helps me out.
I have a doubly linked list, and I'm essentially using this function as a helper function to reverse it between two nodes that are given as the parameters of the function.
Below is the code for the template, commented so you know my thought process
template <class T>
void List<T>::reverse( ListNode * & startPoint, ListNode * & endPoint )
{
//make sure that none of the pointers are null and that the start and
//end points aren't the same
if(startPoint == NULL || endPoint == NULL || startPoint == endPoint)
return;
//Make two nodes denoting everything happening before the
//start and everything after the end
ListNode *before = NULL;
ListNode *after = NULL;
if(startPoint->prev != NULL)
before = startPoint->prev;
if(endPoint->next != NULL)
after = endPoint->next;
ListNode *temp = startPoint;
ListNode *temp2;
//run a loop actually reversing the list. I have identified
//that this is where the problem is happening (obviously)
//for some reason the prev pointer for every node is being set to null
//so if I had a linked list with 1 2 3 4 5
//after running this it's just 5
while(temp!=endPoint && temp!=NULL){
temp2 = temp->next;
if(temp->prev!=NULL);
temp->next = temp->prev;
if(temp2!=NULL)
temp->prev = temp2;
temp = temp2;
}
//switch around the end and start pointers
endPoint = startPoint;
startPoint = temp;
//make sure it's integrated into the rest of the linked list
if(before != NULL){
before->next = startPoint;
startPoint->prev = before;
}
if(after != NULL){
after->prev = endPoint;
endPoint->next = after;
}
}
So, any ideas?
I've understood where the problem is happening, and what it is, but I haven't understood why it's happening, and how to fix it.
Also, feel free to let me know if you think I'm doing something redundant or unnecessary, I have a tendency to do that sometimes.
EDIT: This is an inclusive function, so if you called it on a linked list {1, 2, 3, 4, 5, 6} with pointers pointing to nodes with value 2 and 5, then the linked list would be changed to {1, 5, 4, 3, 2, 6}
The problem is with the ends of the sublist.
You haven't given a complete example (which would have helped), but suppose we start with the list {1, 2, 3, 4, 5}, and we attempt reverse(s, e), where s and e are pointers that point to 2 and 4. (So our desired result is {1, 4, 3, 2, 5}.)
This is where my skill at ASCII art fails, but the 'next' and 'prev' pointers look like this:
1-->2-->3-->4-->5
1<--2<--3<--4<--5
When control leaves the while loop, they look like this:
1<->2<--3 4-->5
1 2-->3<->4<--5
which is almost what we intended, but the process stopped one node to soon (the 4 has not been reversed). After it is "integrated into the rest of the list", they look like this:
________ ___
/ / \ \
1 2<--3 >4-->5
1 2-->3-->4 5
\___\_____/___/
Not very clear, but if you start at the beginning of the list and move forward, it goes {1, 4, 5}, and if you move backward from the end it goes {5, 2, 3, 4, 1}. You have broken the doubly-linked condition that if a.next points to b, then b.prev points to a, and vise-versa.
My advice (apart from drawing more arrows with pencil and paper) is to remove the sublist from the list, reverse it, then splice it back in; trying to reverse it in place is confusing.
I have written a function to merge two singly linked lists. For example, if A = 1 2 3 and B = 3 4 5 and I merge them both, I get A = 1 2 3 3 4 5 and B = NULL. What I want to do now is to write a function which sorts a singly linked list using the mergesort algorithm (somehow using my merge function). For mergesort, if I'm not wrong, I would have to break the linked list in half in some way and then do the rest of the work. I have a small outline written down on how I want to do it. I'm not sure how I would go about doing the splitting at the moment. Any help is appreciated!
List mergeSort(List L) {
if(|L| > 1) {
split L into L1 and L2;
L1 = mergeSort(L1);
L2 = mergeSort(L1);
return(merge(L1,L2));
}
}
My merge function below:
void mylist::merge(mylist& b)
{
if (!this->isSorted() || !b.isSorted())
cout << "error" << endl;
Node* ptr1 = b.head;
Node* prev_a = NULL;
Node* curr_a = head;
Node* curr_b = ptr1;
while (curr_b) {
if (curr_a && head->key < ptr1->key) {
prev_a=curr_a;
curr_a = curr_a->next;
}
else {
Node* b_next = curr_b->next;
curr_b->next = curr_a;
if (prev_a) prev_a->next = curr_b;
else head = curr_b; // curr_b is first element in 'a'
prev_a = curr_b;
curr_b = b_next;
}
return;
}
To divide the list into two halves, two pointers can be used.
Both pointers start at the head of the list. One pointer move every two steps, while the other
move one step each time.
When the fast pointer reach null, the slower pointer will points to the middle of the list.
ListNode *fast(head->next), *slow(head);
while(fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
}
void insert(int number){
Node* temp0 = NULL;
Node* temp1 = head;
Node* temp = new Node();
int sum = 0;
while(temp1!= NULL && sum<=number){
// loop condition edited, before it was temp1!= NULL && sum>=number
sum+=temp1->content;
temp0=temp1;
temp1=temp1->next;
}
if(temp0 == NULL){
temp->content = number;
temp->next = head;
if(head!=NULL){
head->content -= temp->content;
}
head = temp;
}
else{
temp0->next = temp;
temp->content = number - sum;
temp1->content -= temp->content;
temp->next = temp1;
}// end of else
}// end of void insert
I ran into a problem, which i described in one of my previous questions, but still, i'm looking to implement the solution on my own.
In short, i want to make a "relative" list:
for example, for elements 1 5 7 2 4 6 the list would look like 1 1 2 1 1 1
I would make a priority queue list 1 2 4 5 7 6, and then i would change elements relative to the previous one:first element would stay 1,second would be 2-1 = 1, third would be 4-2 = 2, fourth 5-4 = 1 and so on.
When i form a priority queue, i would replace the current element with the difference of it's value and the value of the previous element.
I'm having problems implementing the insert feature. The code is given at the top of the question.
The idea is, i go through the list, adding the "difference" (which is the content field of my Node* structure) to a counter variable. When the sum counter becomes greater or equal to the element i need to insert, i found the position where to insert it.
If temp0 is null, i insert the element on the first position. If it's not the only element, i update the content of the next element - head, which was the previous first element.
If the number needs to be inserted somewhere in the middle of the list (or at the end), i update the content as sum - number, which would be a number >= 0, which is okay. Also, i update the content of the new's next element (temp1) as temp->content - temp->content.
For some reason, this does not work.
When i insert 4 2 8, instead of 2 2 4, i'm getting 4 -2 6 as the result list.
Your loop is "wrong", sum starts out being 0, so as long as number is not zero or negative, it never enters "find the place" loop. So every number is inserted at the beginning, rather than in its rightful place.
while(temp1!= NULL && sum>=number){
sum+=temp1->content;
temp0=temp1;
temp1=temp1->next;
}
Change it to sum <= number, and I believe it will work. Not sure what you want to have happen if you insert the same number multiple times... May you want sum < number instead?
Edit: You will also have some method to detect that your "new" value is less than the existing one, and if so insert a new head, rather than after the existing number. I'm not sure what the exact code for this would be, but you do need to do something along the lines of:
if (number < sum)
{
temp->next = head;
head->content -= temp->content;
head = temp;
}
else
{
... existing insert code ...
}
I have the solution code here:
// Pre-condition: The fronts of two linked lists are provided.
// Post-condition: A linked list is returned that is the result of
// interleaving the elements from each provided list.
// (e.g. {1, 2, 3} & { 4, 5, 6} would return {1, 4, 2, 5, 3, 6}
Node* interleave( Node*& front1, Node*& front2 ) {
if( !front1 ) return front2;
if( !front2 ) return front1;
Node* third = front1->next; //this will become the third element
Node* fourth = front2->next; // this will be come the fourth element
front1->next = front2;
front2->next = third;
third = interleave(third, fourth);
return front1;
}
I kind of understand it but i would never be able to come up with something like this since i'm very bad at recursion. Is there another way to do this problem non-recursively? if so could you give me a hint? I tried this:
Node* interleave( Node*& front1, Node*& front2 ) {
Node* newNode = new Node;
while(front1!=NULL && front2!=NULL){
newNode = front1->next;
newNode = front2->next;
front1 = front1->next;
front2 = front2->next;
}
return newNode;
}
I'm sure it's wrong but that's the only thing i can come up with right now. Please help. Thank you
Try drawing two linked lists in parallel on a sheet of paper. Put some numbers in the nodes, just to tell them apart. Consider how you would reconnect them to form a single list, starting at the head (or "front") and working down. Note that you have to keep track of a few special nodes, like the first node of the resultant list and a couple of others. The pattern should become clear.
(Note that there's no need to construct a new node with new.)
There are a few mistakes in your code:
Node* interleave( Node*& front1, Node*& front2 )
I don't see the need for a reference to a pointer, since the first item in front1 will keep on being the first, and you don't need to mess with front2 at all.
Node* newNode = new Node;
while(front1!=NULL && front2!=NULL){
newNode = front1->next;
This is causing a memory leak - you're allocating at least sizeof(Node) bytes, but then you're losing the reference to the pointer, and you won't be able to delete it anymore.
Also, you're not doing anything with newNode, so you might throw it away as well.
front1 = front1->next;
front2 = front2->next;
Basically you're telling that front1 will rather point to the next element, and since you passed a reference to front1, you're altering the real pointer. Eventually, front1 or front2 will be NULL and the loop will terminate, so at least one of the two given parameters will become useless. You're never changing next, so the order will be left unchanged - you're just walking through the lists.
One approach could be to set front2's value to front1->next, then swap pointers and iterate again:
Node *a = front1, *b = front2;
while (a && b) {
Node* tmp = a->next;
a->next = b;
b = tmp;
a = a->next;
}
return front1;
I didn't test this, but it should be close to working. You can replace the verbose swap code with std::swap() if you're using stl.
The idea is simple: suppose you have two lists:
A -> B -> C -> NULL
D -> E -> F -> NULL
you say that A's next item is going to be the first element in the second list, so D:
A -> D -> E -> F -> NULL
and then the second lists becomes the ancient A's successor, so just B -> C -> NULL. You then advance a to point to its new next, or D, so you now have:
D -> E -> F -> NULL
B -> C -> NULL
and you repeat:
D -> B -> C -> NULL
E -> F -> NULL
B -> C -> NULL
F -> NULL
and so on until a NULL is met. Then front1, that still points to A, should have the right sequence (that is, unless I'm terribly wrong :p )