a program gives runtime error when submitted in leetcode but works in run code - c++11

encountered a question on leetcode
Question Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the list's nodes (i.e., only nodes themselves may be changed.)
Example
here is my solution
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head->next->next==NULL)
{ ListNode* temp=head;
head=head->next;
temp->next=NULL;
head->next=temp; //putting this line gives runtime error
return head;
}
else
{ ListNode* temp=head;
head=head->next;
temp->next=head->next;
head->next=temp;
temp->next=swapPairs(temp->next);
return head;
}
}
};
the code gives a runtime error when I put the marked line in the first condition but runs fine when using run code command.
the error isLine 15: Char 18: runtime error: member access within null pointer of type 'ListNode' (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:24:18

If this program is passed a null pointer or a single node, an error will be thrown as a nullptr has no attributes (i.e next). Therefore head->next or head->next->next cannot be determined.
The solution is to check for these edge cases beforehand.
if(!head){
return head;
}else if(!(head->next)){
return head;
}

Related

Why my Preoder, Inorder and Postorder functions are not working

#include <stdio.h>
#include <stdlib.h>
Node Creation
This structure creates the struct node data type
struct node
{
int data;
struct node *left, *right;
} * newnode;
Create Function
create() - It first allocates the memory required for the node. When user enters the data, it recursively calls itself to create its child node, and this process goes on. When the user enters -1, it terminates the recursion and goes back from where it is called.
struct node *create()
{
int x;
newnode = (struct node *)malloc(sizeof(struct node));
newnode->left = 0;
newnode->right = 0;
printf("Enter data(-1 for no node)\n");
scanf("%d", &x);
if (x == -1)
return 0;
newnode->data = x;
printf("Enter left child of %d\n", x);
newnode->left = create();
printf("Enter right child of %d\n", x);
newnode->right = create();
return newnode;
}
Preorder
preorder(struct node *root) - This function displays the data of the tree in preorder manner
void preorder(struct node *root)
{
if (root == 0)
return;
printf("%d\n", root->data);
preorder(root->left);
preorder(root->right);
}
Inorder
inorder(struct node *root) - This function displays the data of the tree in inorder manner
void inorder(struct node *root)
{
if (root == 0)
return;
inorder(root->left);
printf("%d\n", root->data);
inorder(root->right);
}
Postorder
Postorder(struct node *root) - This function displays the data of the tree in postorder manner
void postorder(struct node *root)
{
if (root == 0)
return;
postorder(root->left);
postorder(root->right);
printf("%d\n", root->data);
}
Main Function
Main function asks the user to create a tree and then traverse it according to the choice entered by the user. The problem is that preorder, inorder and postorder are not giving the required output, and result in an infinite loop after execution.
void main()
{
struct node *root;
root = 0;
int choice = 3, opt = 1;
while (opt)
{
printf("Select\n 1-for creation\n 2-for preorder\n 3-for inorder\n 4-for postorder\n");
scanf("%d", &choice);
switch (choice)
{
case 1:
root = create();
break;
case 2:
printf("Preorder is: ");
preorder(root);
break;
case 3:
printf("Inorder is: ");
inorder(root);
break;
case 4:
printf("Postorder is: ");
postorder(root);
break;
default:
printf("Invalid choice");
break;
}
printf("Wanna continue \n1-for yes\n0-for no\n");
scanf("%d", &opt);
}
}
There is no bug with any of the traversal functions you've provided.
No design or implementation problem with create () function either.
The trouble lies in the global struct node pointer newnode declared with the structure's definition.
Because each recursive call to create () is basically using the "same" newnode pointer, the tree is never really built in the way we want it to.
Let's try to dry run the create () function.
Let's say we want a tree like this:
1
/ \
2 3
create () is first called from main.
The memory is allocated using malloc () function and the address of the memory is stored in newnode.
Set it's attributes, left and right.
Ask for data and put it into data attribute, if data == -1 is true, return 0.
Up until this point, this is the state:
newnode -> 1
/ \
Null Null
create () is recursively called to build the left subtree.
The memory is allocated for newnode using malloc () and the address of the memory is stored in newnode. Note that this operation has basically "over-wrote" the address previously stored in newnode (because newnode is a global variable)
Then again, the user will be prompted for the data and its attributes will be set.
Therefore, the tree has now become:
newnode -> 2
/ \
Null Null
The struct node to which newnode was previously pointing is now lost (because of loss of its address)
Similarly, when the recursive call for the right subtree is made, then, the following will be observed:
newnode -> 3
/ \
Null Null
Considering the same scenario for the rest of the recursive calls made, it is clear that in the end, the tree we were expecting wasn't built and the reason is the global variable newnode, the constant allocation of memory and over-writing the address in newnode led to memory leakage only.
The reason infinite recursion was found is that, during multiple recursive calls, the left or right pointer of newnode was made to point to newnode itself, leading to a cycle. This node can be found by closely tracking the data of newnode during the recursive calls.
Hence, remove the declaration of newnode pointer from the structure declaration and modify the following statement in create () function:
newnode = (struct node *)malloc(sizeof(struct node));
to this:
struct node * newnode = (struct node *)malloc(sizeof(struct node));
And
struct node
{
int data;
struct node *left, *right;
};
is all what's needed.
In this way, each recursive call to create () function will have its own local pointer variable newnode and there will be no overwriting, no leakage, no cycle, no infinite recursion.

Linked List in Binary Tree

I'm trying to solve : https://leetcode.com/contest/weekly-contest-178/problems/linked-list-in-binary-tree/
I have the following solution :
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
boolean ans;
ListNode originalHead;
public boolean isSubPath(ListNode head, TreeNode root) {
this.ans = false;
originalHead = head;
traverse(head, root);
return ans;
}
public void traverse(ListNode head, TreeNode root) {
if(head == null) {
ans = true;
return;
}
if(root == null) return;
if(!ans && root.val == head.val) traverse(head.next, root.right);
if(!ans && root.val == head.val) traverse(head.next, root.left);
if(!ans) traverse(originalHead, root.right);
if(!ans) traverse(originalHead, root.left);
}
}
I'm wondering if this solution has a time complexity of O(n^2) or not. I ask this since I'm encountering a Time Limit Exceeded error for one of the test cases in the test suite.
I do see other O(n^2) solutions passing though.
Appreciate any help.
Thank you!
If n is the number of vertices in the tree, then your algorithm's worst-case time complexity is in Θ(2n) rather than O(n2).
This worst case occurs when every non-leaf node of the tree has just one child, the linked list is longer than the tree is deep, and all of the nodes in the tree and the linked list all have the same value. When that happens, you end up making all of your recursive calls — your if-conditions are always met — so each time you call traverse on a node, you call traverse twice on its child node. So you call traverse once on the root node, twice on its child, four times on its grandchild, eight times on its great-grandchild, etc., which is Θ(2n) if there are n nodes.

why is static keyword required for finding if a given binary tree is BST or not?

Here is the code for finding if the given binary tree was a binary search tree(BST) or not:
bool isBST(struct node* root)
{
// traverse the tree in inorder fashion and keep track of prev node
if (root)
{
struct node *prev = NULL;
if (!isBST(root->left))
return false;
// Allows only distinct valued nodes
if (prev != NULL && root->data <= prev->data)
return false;
prev = root;
return isBST(root->right);
}
return true;
}
However this does not give the correct output.
when I changed my code to the below version it worked fine:
bool isbst(node * root)
{
static struct node * prev = NULL;
if( root)
{
if(!isbst(root->left))
return false;
if(prev != NULL && root->data < prev->data)
return false;
prev = root;
return isbst(root-> right);
}
return true;
}
My question is why does it work when the line static struct node * prev = NULL; was added to the code?
In my previous code even though the variable 'prev' was declared again and again it was update to the root each time..my code should have worked fine. But it didn't. what is wrong with it?
static struct node * prev = NULL;
In the above line, the use of the static keyword gives rise to two things:
1) prev is only initialised to null exactly once, i.e. the first time it is reached
2) More importantly, because prev is static, any update to its value is retained in subsequent calls to the function isBST.
In your initial/bad/non-working case without the static keyword
struct node *prev = NULL;
1) You are not retaining the value of the previous node (this is precisely why your algo didn't work)
2) Not only that you are setting it to null
In short, with the use of static, you are retaining the previous node's value (your intention). In the other case, you aren't retaining the previous node's value
static initialisation of a variable within a function scope in C++ is a neat way to retain values between recursive calls.

Odd Even Linked List Run Time Error for one particular input. Runs fine for everything else

I am trying to solve a problem from LeetCode.
Problem
Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes.
You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity.
Example:
Given 1->2->3->4->5->NULL,
return 1->3->5->2->4->NULL.
My Solution:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
ListNode *even, *firsteven, *odd, *curr;
if(head == NULL)
return NULL;
odd = head;
even = head;
curr = head;
if(head->next) {
even = even->next;
firsteven = head->next;
}
else return head;
if(head->next->next)
curr = head->next->next;
else return head;
while(curr) {
even->next = curr->next;
curr->next = NULL;
odd->next = curr;
curr->next = firsteven;
odd = odd->next;
even = even->next;
even->next ? curr = even->next : curr = NULL;
}
return head;
}
};
My solution works perfectly well for all inputs except for inputs of size 3.
For an input 1->2->3 I am getting a run time error. I have done a dry run several times. I am not sure why I am getting a run time error.
Can you please tell me what am I doing wrong?
The problem is with this line:
even->next = curr->next;
When current is set to the last element (3), you're trying curr->next, which will result in an error.

Linked List Merge Sort Exaplanation

Can someone explain to me please, how this code works :
http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.c
I don't understand the algorithm used in this post. Thanks
Merge sort is often preferred for sorting a linked list. The slow random-access performance of a linked list makes some other algorithms (such as quicksort) perform poorly, and others (such as heapsort) completely impossible.
Let head be the first node of the linked list to be sorted and headRef be the pointer to head. Note that we need a reference to head in MergeSort() as the below implementation changes next links to sort the linked lists (not data at the nodes), so head node has to be changed if the data at original head is not the smallest value in linked list.
MergeSort(headRef)
1) If head is NULL or there is only one element in the Linked List
then return.
2) Else divide the linked list into two halves.
FrontBackSplit(head, &a, &b); /* a and b are two halves */
3) Sort the two halves a and b.
MergeSort(a);
MergeSort(b);
4) Merge the sorted a and b (using SortedMerge() discussed here)
and update the head pointer using headRef.
*headRef = SortedMerge(a, b);
/* Link list node */
struct node
{
int data;
struct node* next;
};
/* function prototypes */
struct node* SortedMerge(struct node* a, struct node* b);
void FrontBackSplit(struct node* source,
struct node** frontRef, struct node** backRef);
/* sorts the linked list by changing next pointers (not data) */
void MergeSort(struct node** headRef)
{
struct node* head = *headRef;
struct node* a;
struct node* b;
/* Base case -- length 0 or 1 */
if ((head == NULL) || (head->next == NULL))
{
return;
}
/* Split head into 'a' and 'b' sublists */
FrontBackSplit(head, &a, &b);
/* Recursively sort the sublists */
MergeSort(&a);
MergeSort(&b);
/* answer = merge the two sorted lists together */
*headRef = SortedMerge(a, b);
}
/* See http://geeksforgeeks.org/?p=3622 for details of this
function */
struct node* SortedMerge(struct node* a, struct node* b)
{
struct node* result = NULL;
/* Base cases */
if (a == NULL)
return(b);
else if (b==NULL)
return(a);
/* Pick either a or b, and recur */
if (a->data data)
{
result = a;
result->next = SortedMerge(a->next, b);
}
else
{
result = b;
result->next = SortedMerge(a, b->next);
}
return(result);
}
/* UTILITY FUNCTIONS */
/* Split the nodes of the given list into front and back halves,
and return the two lists using the reference parameters.
If the length is odd, the extra node should go in the front list.
Uses the fast/slow pointer strategy. */
void FrontBackSplit(struct node* source,
struct node** frontRef, struct node** backRef)
{
struct node* fast;
struct node* slow;
if (source==NULL || source->next==NULL)
{
/* length next;
/* Advance 'fast' two nodes, and advance 'slow' one node */
while (fast != NULL)
{
fast = fast->next;
if (fast != NULL)
{
slow = slow->next;
fast = fast->next;
}
}
/* 'slow' is before the midpoint in the list, so split it in two
at that point. */
*frontRef = source;
*backRef = slow->next;
slow->next = NULL;
}
}
/* Function to print nodes in a given linked list */
void printList(struct node *node)
{
while(node!=NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
/* Function to insert a node at the beginging of the linked list */
void push(struct node** head_ref, int new_data)
{
/* allocate node */
struct node* new_node =
(struct node*) malloc(sizeof(struct node));
/* put in the data */
new_node->data = new_data;
/* link the old list off the new node */
new_node->next = (*head_ref);
/* move the head to point to the new node */
(*head_ref) = new_node;
}
/* Drier program to test above functions*/
int main()
{
/* Start with the empty list */
struct node* res = NULL;
struct node* a = NULL;
struct node* b = NULL;
/* Let us create a unsorted linked lists to test the functions
Created lists shall be a: 2->3->20->5->10->15 */
push(&a, 15);
push(&a, 10);
push(&a, 5);
push(&a, 20);
push(&a, 3);
push(&a, 2);
/* Remove duplicates from linked list */
MergeSort(&a);
printf("\n Sorted Linked List is: \n");
printList(a);
getchar();
return 0;
}
Try imaging all the merges that are performed in a normal merge sort on an array: first, elements are paired up and merged into sorted subarray of length two, then these subarray of length two are paired up and merged into sorted subarray of length four and so on. Notice the length of the subarray: 1, 2, 4, and so on, let's call this instep, which doubles in each iteration.
At any point, p points to a list of length instep, q points to a list of length instep or smaller (we may hit the end of the list), and q immediately follows p. They form a pair of subarray as mentioned above. We do a merge on p and q to get a sorted list of length psize + qsize starting from p. We than move p and q to the next pair, and so on. Once we are done with the whole list, we double instep and start merging longer sorted list.

Resources