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
42 changes: 42 additions & 0 deletions Problem1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Problem1 (https://leetcode.com/problems/reverse-linked-list/)
# Time Complexity: O(n), we visit every node exactly once
# Space Complexity: O(1), only a few pointers used, no extra data structures
# Approach: Walk through the list one node at a time. For each node, beforebreaking its forward link, save where the rest of the list continues.
#Then flip that node's pointer to point BACKWARD instead of forward.
#Move both pointers ahead by one and repeat until every node has been flipped.


# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:

previous = None # will track the node that comes before "current" in the REVERSED list.starts as None because the very first node
# we flip (the original head) should end up pointing to nothing
current = head # the node we are currently working on, starts at the original head

while current is not None: # keep looping until current falls off the end of the list (becomes None),that means every node has been flipped already

temperory = current.next # save where the list continues BEFORE we break the link.
# example: if current is node 1, and 1 -> 2 -> 3 -> 4 -> 5,
# then temperory = 2. without saving this first, we'd lose
# our way to the rest of the list the moment we rewire current.next

current.next = previous # flip current's arrow to point backward to "previous"
# instead of forward. example: 1.next was pointing to 2,
# now it's rewired to point to None (since previous = None
# on the first pass). this is the actual "reversal" step

previous = current # current has now been fully flipped, so it becomes the new
# "previous" for the next node we process.
# example: previous moves from None to node 1

current = temperory # move current forward to the node we saved earlier,
# so we can repeat this process on it.
# example: current moves from 1 to 2 (the value we stored
# in temperory before we touched any pointers)

return previous
45 changes: 45 additions & 0 deletions Problem2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Problem2 (https://leetcode.com/problems/remove-nth-node-from-end-of-list/)
# Time Complexity: O(n)
# Space Complexity: O(1), only a few pointers used, no extra data structures
# Approach: Use two pointers, fast and slow, kept exactly (n+1) nodes apart.
# Move fast ahead first to create that gap, then move both together until fast falls off the end.
#At that point, slow is sitting on the node just BEFORE the one we need to remove, so we can unlink it directly.
# A dummy node is placed before head so there's always a "previous" node to point from, even if the node being removed is the original head.


# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:

dummy = ListNode(-1) # create a fake node that sits before the real head
dummy.next = head # link dummy to the actual list

fast = dummy # fast pointer starts at dummy
slow = dummy # slow pointer also starts at dummy

count = 0 # tracks how many steps fast has taken so far
while count <= n: # this loop runs (n+1) times total, building the gap between fast and slow
fast = fast.next # move fast forward by 1 node
count += 1 # record that fast took one more step

while fast is not None: # keep moving both pointers together until fast runs off the end of the list
slow = slow.next # move slow forward by 1 node
fast = fast.next # move fast forward by 1 node (gap stays the same)

# at this point, slow is on the node right BEFORE the one we want to delete

temperory = slow.next # save a reference to the node we are about to remove
slow.next = slow.next.next # skip over that node: point slow directly to the node AFTER it
# the node being removed is now disconnected from the main list,
# but it still has its OWN .next pointer left over, pointing
# forward into the list (we haven't touched that yet)
temperory.next = None # now clean up that leftover pointer: set the removed
# node's .next to None, so it doesn't dangle into the
# rest of the list anymore. this doesn't change the
# main list at all, it only cleans up the node we cut out

return dummy.next
40 changes: 40 additions & 0 deletions Problem3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Problem3 (https://leetcode.com/problems/linked-list-cycle-ii/)
# Time Complexity: O(n), each pointer visits a bounded number of nodes
# Space Complexity: O(1), only a few pointers used, no extra data structures
# Approach: Use slow (1 step) and fast (2 steps) pointers to detect if a cycle exists.
#If they meet, reset slow to head and move both 1 step at a time and they will meet again exactly at the start of the cycle.

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None

class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:


if head is None: # empty list has no nodes, so no cycle is possible
return None

slow = head # slow pointer starts at the first node
fast = head # fast pointer also starts at the first node
flag = False # tracks whether we found a cycle or not

while fast.next is not None and fast.next.next is not None:
# stop if fast would hit the end of the list (no cycle case) for both even and odd lengths
slow = slow.next # move slow forward by 1 node
fast = fast.next.next # move fast forward by 2 nodes

if fast == slow: # if they land on the same node, a cycle exists
flag = True # mark that a cycle was found
break # no need to keep looping, exit now

if not flag: # loop ended naturally (fast hit the end) = no cycle
return None # so there's no cycle start to return

slow = head # reset slow back to the beginning of the list
while slow != fast: # fast stays at the meeting point from before
slow = slow.next # move slow forward by 1 node
fast = fast.next # move fast forward by 1 node (same speed now)
return slow # both pointers now point to the cycle's starting node