Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 57 additions & 7 deletions Exercise_1.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,74 @@

# 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()
s.push('1')
s.push('2')
print(s.pop())
print(s.show())

s.push('3')
s.push('4')
print(s.peek())
print(s.size())
print(s.show())
29 changes: 26 additions & 3 deletions Exercise_2.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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"
Expand Down
45 changes: 44 additions & 1 deletion Exercise_3.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
# 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.
"""
def __init__(self, data=None, next=None):
self.data = data
self.next = next

class SinglyLinkedList:
def __init__(self):
Expand All @@ -17,16 +33,43 @@ 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):
"""
Search for the first element with `data` matching
`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