From 612435ba22fccdc8f5be472ffd26352e1859ee6e Mon Sep 17 00:00:00 2001 From: Manasvi Reddy Date: Fri, 26 Jun 2026 01:18:53 -0400 Subject: [PATCH] Done Linked-List-1 --- Problem1.py | 42 ++++++++++++++++++++++++++++++++++++++++++ Problem2.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ Problem3.py | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 Problem1.py create mode 100644 Problem2.py create mode 100644 Problem3.py diff --git a/Problem1.py b/Problem1.py new file mode 100644 index 00000000..a159fdba --- /dev/null +++ b/Problem1.py @@ -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 \ No newline at end of file diff --git a/Problem2.py b/Problem2.py new file mode 100644 index 00000000..3f3fff2c --- /dev/null +++ b/Problem2.py @@ -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 \ No newline at end of file diff --git a/Problem3.py b/Problem3.py new file mode 100644 index 00000000..e1e14cd5 --- /dev/null +++ b/Problem3.py @@ -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 \ No newline at end of file