From c8a0ea09821de1122e2e56f4522fcee67db5c820 Mon Sep 17 00:00:00 2001 From: Aduri Pavan Kaushik Date: Mon, 27 Jul 2026 18:33:57 -0700 Subject: [PATCH 1/5] question1 done --- Exercise_1.py | 64 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/Exercise_1.py b/Exercise_1.py index 532833f5d..0582e170d 100644 --- a/Exercise_1.py +++ b/Exercise_1.py @@ -1,20 +1,64 @@ + +# Time Complexity : +# push: O(1) best and average case. I think python internally uses dynamic array for a list data structure. So every time we try to append, it calculates memeory slot for the next element and it does not travel across each emmeory block to find the next ememory location that needs to be used, hence its O(1). when the memory is filled up, then it allocates new larger block of memeory and does copy all the elements in the new block and then appends the element. so copy might cause O(N). but this happens only when memory is filled up. so worst case O(N). best and average case is O(1) +# pop: O(1) Since it is kind of getting and removing the element by calculating the memory location of the latest element using starting address and length of the array. so it clears the memory and sets it to None and then decreases the size/length counter. so next time we do pop it calculates the location of latest element by using starting address and length of the array - counter. +# peek: O(1) - we are using -1 index which internally tranforms into length - 1. so basically it needs to know the address by using a formula which is starting address + (index * size of size of one slot). so since its caluclating using formula its O(1), no traversing through each and every element. +# isEmpty and Size: both are O(1) - size counter as explained above is used to track the length internally. +# show : O(N) - since we are using self.stack[::-1] sowhat this does internally is it creates a new list and then copies each and every item into the list in reverse order. since its stack its Last In First Out(LIFO) so we will have to print last element first to show elements in stack. so if there are N elements it takes O(N) time complexity. + + + +# Space Complexity : O(N) - Number of elements stored in the stack. + + +# Did this code successfully run on Leetcode : Yes + + +# Any problem you faced while coding this : did not use isEmpty method initially so had #redundant code and hthen later refactored it. In python almost all of this has methods #defined so tried to not use them for popping atleast. + +# Your code here along with comments explaining your approach + class myStack: #Please read sample.java file before starting. #Kindly include Time and Space complexity at top of each file def __init__(self): - + #defining a instance variable which is a list. supposed to store all elements. + self.stack = [] + + + #checks if stack is empty. used self.stack since it resolves to finding length - pre calculated len counter. def isEmpty(self): - + if self.stack: + return False + return True + + #pushes elements into the stack using default append method. its a dynamic array so worst case it will need to copy all the elements into new list rarely. def push(self, item): - + self.stack.append(item) + + #removes and gives the top element in the stack. used del to remove the last element. def pop(self): - - + if not self.isEmpty(): + top = self.stack[-1] + del self.stack[-1] + return top + return None + + #this is like top method to return the latest element in the stack. it does not removes it just returns the top element. def peek(self): - + if not self.isEmpty(): + return self.stack[-1] + return None + + #size of the stack is returned. gives number of elements in stack. def size(self): - + return len(self.stack) + + #returns elements in the stack if any, or returns None elements in stack in formatted string. def show(self): + if not self.isEmpty(): + return f"elements in stack : {self.stack[::-1]}" + return f"No elements in stack" s = myStack() @@ -22,3 +66,9 @@ def show(self): s.push('2') print(s.pop()) print(s.show()) + +s.push('3') +s.push('4') +print(s.peek()) +print(s.size()) +print(s.show()) From 9caee845eb4b8627faeae99678e923f04085fd77 Mon Sep 17 00:00:00 2001 From: Aduri Pavan Kaushik Date: Mon, 27 Jul 2026 18:33:57 -0700 Subject: [PATCH 2/5] question1 done --- Exercise_1.py | 64 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/Exercise_1.py b/Exercise_1.py index 532833f5d..0582e170d 100644 --- a/Exercise_1.py +++ b/Exercise_1.py @@ -1,20 +1,64 @@ + +# Time Complexity : +# push: O(1) best and average case. I think python internally uses dynamic array for a list data structure. So every time we try to append, it calculates memeory slot for the next element and it does not travel across each emmeory block to find the next ememory location that needs to be used, hence its O(1). when the memory is filled up, then it allocates new larger block of memeory and does copy all the elements in the new block and then appends the element. so copy might cause O(N). but this happens only when memory is filled up. so worst case O(N). best and average case is O(1) +# pop: O(1) Since it is kind of getting and removing the element by calculating the memory location of the latest element using starting address and length of the array. so it clears the memory and sets it to None and then decreases the size/length counter. so next time we do pop it calculates the location of latest element by using starting address and length of the array - counter. +# peek: O(1) - we are using -1 index which internally tranforms into length - 1. so basically it needs to know the address by using a formula which is starting address + (index * size of size of one slot). so since its caluclating using formula its O(1), no traversing through each and every element. +# isEmpty and Size: both are O(1) - size counter as explained above is used to track the length internally. +# show : O(N) - since we are using self.stack[::-1] sowhat this does internally is it creates a new list and then copies each and every item into the list in reverse order. since its stack its Last In First Out(LIFO) so we will have to print last element first to show elements in stack. so if there are N elements it takes O(N) time complexity. + + + +# Space Complexity : O(N) - Number of elements stored in the stack. + + +# Did this code successfully run on Leetcode : Yes + + +# Any problem you faced while coding this : did not use isEmpty method initially so had #redundant code and hthen later refactored it. In python almost all of this has methods #defined so tried to not use them for popping atleast. + +# Your code here along with comments explaining your approach + class myStack: #Please read sample.java file before starting. #Kindly include Time and Space complexity at top of each file def __init__(self): - + #defining a instance variable which is a list. supposed to store all elements. + self.stack = [] + + + #checks if stack is empty. used self.stack since it resolves to finding length - pre calculated len counter. def isEmpty(self): - + if self.stack: + return False + return True + + #pushes elements into the stack using default append method. its a dynamic array so worst case it will need to copy all the elements into new list rarely. def push(self, item): - + self.stack.append(item) + + #removes and gives the top element in the stack. used del to remove the last element. def pop(self): - - + if not self.isEmpty(): + top = self.stack[-1] + del self.stack[-1] + return top + return None + + #this is like top method to return the latest element in the stack. it does not removes it just returns the top element. def peek(self): - + if not self.isEmpty(): + return self.stack[-1] + return None + + #size of the stack is returned. gives number of elements in stack. def size(self): - + return len(self.stack) + + #returns elements in the stack if any, or returns None elements in stack in formatted string. def show(self): + if not self.isEmpty(): + return f"elements in stack : {self.stack[::-1]}" + return f"No elements in stack" s = myStack() @@ -22,3 +66,9 @@ def show(self): s.push('2') print(s.pop()) print(s.show()) + +s.push('3') +s.push('4') +print(s.peek()) +print(s.size()) +print(s.show()) From 2c2eb2509c77db9d123132a5815d64f5ce2fe054 Mon Sep 17 00:00:00 2001 From: Aduri Pavan Kaushik Date: Mon, 27 Jul 2026 18:55:17 -0700 Subject: [PATCH 3/5] Fix Exercise_2 --- Exercise_2.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/Exercise_2.py b/Exercise_2.py index b11492215..bb6eb9f3f 100644 --- a/Exercise_2.py +++ b/Exercise_2.py @@ -1,3 +1,13 @@ +# Time Complexity : +# push: O(1) - adding a new node at the head of the linked list. +# pop: O(1) - removing the node at the head of the linked list. +# Space Complexity : O(N) - N is the number of elements in the stack, each element is stored as a node in the linked list. +# Did this code successfully run on Leetcode : Yes +# Any problem you faced while coding : Kind of confused when trying to implement push. so basically when we try to add a new node, I think thinking vertically helps. so new code added should point to previous node which head points to and the head should point to this new node next. so we create a new node and then we set new_node.next to self.head and then we set self.head to new_node. + + +# Your code here along with comments explaining your approach + class Node: def __init__(self, data): @@ -6,11 +16,24 @@ def __init__(self, data): class Stack: def __init__(self): - + self.head = None + + + #Thinking vertically helps. lets assume we got a first push operation, so we create a new node with the given data and then we point new_node.next to self.head which is intially None and then we updat this head to point to this new node. def push(self, data): - + new_node = Node(data) + new_node.next = self.head + self.head = new_node + + + # we already have self.head pointing to latest element, so we remove and return that element by getting value using self.head.data and then we move self.head to self.head.next so that head now points to the next element in the stack and we return data. def pop(self): - + if self.head is None: + return None + data = self.head.data + self.head = self.head.next + return data + a_stack = Stack() while True: #Give input as string if getting an EOF error. Give input like "push 10" or "pop" From 7eb03a300c75fc5dc09604d4c1d77ca5972922b7 Mon Sep 17 00:00:00 2001 From: Aduri Pavan Kaushik Date: Mon, 27 Jul 2026 19:02:29 -0700 Subject: [PATCH 4/5] Question3 Done --- Exercise_3.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Exercise_3.py b/Exercise_3.py index a5d466b59..3125ad63c 100644 --- a/Exercise_3.py +++ b/Exercise_3.py @@ -3,6 +3,8 @@ class ListNode: A node in a singly-linked list. """ def __init__(self, data=None, next=None): + self.data = data + self.next = next class SinglyLinkedList: def __init__(self): @@ -17,6 +19,15 @@ def append(self, data): Insert a new element at the end of the list. Takes O(n) time. """ + new_node = ListNode(data) + if self.head is None: + self.head = new_node + return + current = self.head + while current.next: + current = current.next + current.next = new_node + def find(self, key): """ @@ -24,9 +35,27 @@ def find(self, key): `key`. Return the element or `None` if not found. Takes O(n) time. """ - + current = self.head + while current: + if current.data == key: + return current + current = current.next + return None + + #Used two pointers approach. We have prev=None and current=self.head. we check if current.data is key if it is key then we already have prev so we just do prev.next to current.next so this way we are removing the current element. if its not matching with key we just move our prev and current pointers. def remove(self, key): """ Remove the first occurrence of `key` in the list. Takes O(n) time. """ + current = self.head + prev = None + while current: + if current.data == key: + if prev: + prev.next = current.next + else: + self.head = current.next + return + prev = current + current = current.next From 8a6ae7ee9e509c8ec32edb75735bd754f67632ad Mon Sep 17 00:00:00 2001 From: Aduri Pavan Kaushik Date: Mon, 27 Jul 2026 19:04:59 -0700 Subject: [PATCH 5/5] Question3 Done --- Exercise_3.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Exercise_3.py b/Exercise_3.py index 3125ad63c..0b97ee3dd 100644 --- a/Exercise_3.py +++ b/Exercise_3.py @@ -1,3 +1,17 @@ +# Time Complexity : +# append: O(n) - adding a new node at the end of the linked list. +# find: O(n) - searching for a node with a specific key in the linked list. +# remove: O(n) - removing a node with a specific key from the linked list. +# Space Complexity : O(N) - N is the number of elements in the linked list, each element is stored as a node in the linked list. + +# Did this code successfully run on Leetcode : Yes + +# Any problem you faced while coding : while removing the base case where prev is None is missed. i should check for prev is not None and if its None then self.head = current.next. + + +# Your code here along with comments explaining your approach + + class ListNode: """ A node in a singly-linked list.