leetcode

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit bca0cf9d05d7ff5f77d552eb6fb56bacff8190c3
parent d3f0506fd71be78dc95a09a173281783ec842c69
Author: Andrew Laack <andrew@laack.co>
Date:   Sat, 14 Jun 2025 14:09:00 -0500

Finished a bunch more neetcode

Diffstat:
Alinked-list-cycle/linked-list-cycle.py | 23+++++++++++++++++++++++
Alinked-list-cycle/linked-list-cycleV2.py | 31+++++++++++++++++++++++++++++++
Alongest-repeating-character-replacement/longest-repeating.py | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amaximum-difference-by-remapping-a-digit/max-diff.py | 46++++++++++++++++++++++++++++++++++++++++++++++
Amerge-two-sorted-lists/merge-two-sorted-lists.py | 44++++++++++++++++++++++++++++++++++++++++++++
Apermutation-in-string/perm-in-string.py | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Areorder-list/reorder-list.py | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Areverse-linked-list/reverse-list.py | 26++++++++++++++++++++++++++
8 files changed, 371 insertions(+), 0 deletions(-)

diff --git a/linked-list-cycle/linked-list-cycle.py b/linked-list-cycle/linked-list-cycle.py @@ -0,0 +1,23 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def hasCycle(self, head: Optional[ListNode]) -> bool: + + if head is None: + return False + + head.val = None + current = head.next + + while current is not None: + if current.val is None: + return True + else: + current.val = None + current = current.next + + return False diff --git a/linked-list-cycle/linked-list-cycleV2.py b/linked-list-cycle/linked-list-cycleV2.py @@ -0,0 +1,31 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def hasCycle(self, head: Optional[ListNode]) -> bool: + + # two pointers, one fast, one slow + # if fast catches slow, issue + # if fast reaches end, success + + if head is None: + return False + + fast_ptr = head.next + slow_ptr = head + + while fast_ptr is not None: + if fast_ptr == slow_ptr: + return True + + fast_ptr = fast_ptr.next + + if fast_ptr is not None: + fast_ptr = fast_ptr.next + + slow_ptr = slow_ptr.next + + return False diff --git a/longest-repeating-character-replacement/longest-repeating.py b/longest-repeating-character-replacement/longest-repeating.py @@ -0,0 +1,56 @@ +import numpy as np + +class Solution: + def characterReplacement(self, s: str, k: int) -> int: + + # keep track of the most popular as we go through + # when adverserial examples are found, we add them to our hash_map + # and increment our counter for them. + + # when adverserial > k, we move the left_ptr to the right, removing values each time. + # while we do this, we also need to check the most popular character in our + # substring. + + longest = 0 + + counts = [0] * 26 + + left_ptr = 0 + right_ptr = 0 + + converted = [char_to_int(i.lower()) for i in s] + + while right_ptr < len(s): + + counts[converted[right_ptr]] += 1 + adv = count_adversaries(counts) + + looped = False + while count_adversaries(counts) > k: + counts[converted[left_ptr]] -= 1 + left_ptr += 1 + looped = True + + else: + current = (right_ptr - left_ptr) + 1 + if current > longest: + longest = current + right_ptr += 1 + + + return longest + +def char_to_int(char_input): + return ord(char_input) % 97 + +def count_adversaries(counts): + + adversaries = 0 + max_index = np.argmax(counts) + for i in range(0, len(counts)): + + if i == max_index: + continue + adversaries += counts[i] + + return adversaries diff --git a/maximum-difference-by-remapping-a-digit/max-diff.py b/maximum-difference-by-remapping-a-digit/max-diff.py @@ -0,0 +1,46 @@ +class Solution: + def minMaxDifference(self, num: int) -> int: + + num_ls = [] + while num > 0: + lsb = num % 10 + num = num // 10 + num_ls.append(lsb) + + num_ls.reverse() + num_ls_min = num_ls.copy() + + # min = setting msb to 0 (since int, no leading 0's) + + val_to_map = num_ls[0] + + for i in range(0, len(num_ls)): + if num_ls[i] == val_to_map: + num_ls_min[i] = 0 + + # max = setting max non 9 value to be = 9 (or leaving as is when all 9's) + + num_ls_max = num_ls.copy() + digit_to_change = 9 + + for i in range(0, len(num_ls_max)): + if num_ls_max[i] != 9: + digit_to_change = num_ls_max[i] + break + + for i in range(0, len(num_ls_max)): + if num_ls_max[i] == digit_to_change: + num_ls_max[i] = 9 + + + max_val = to_int(num_ls_max) + min_val = to_int(num_ls_min) + + return max_val - min_val + + +def to_int(num_ls) -> int: + num = 0 + for i in range(len(num_ls) - 1, -1, -1): + num += num_ls[i] * 10**((len(num_ls) - 1) - i) + return num diff --git a/merge-two-sorted-lists/merge-two-sorted-lists.py b/merge-two-sorted-lists/merge-two-sorted-lists.py @@ -0,0 +1,44 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + # len(list1, list2) can be 0 + def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: + + if list1 is None: + return list2 + if list2 is None: + return list1 + + head = None + + if list1.val < list2.val: + head = list1 + list1 = list1.next + else: + head = list2 + list2 = list2.next + + assert(head is not None) + + current = head + + while list1 is not None and list2 is not None: + + if list1.val < list2.val: + current.next = list1 + list1 = list1.next + else: + current.next = list2 + list2 = list2.next + + current = current.next + + if list1 is None: + current.next = list2 + else: + current.next = list1 + + return head diff --git a/permutation-in-string/perm-in-string.py b/permutation-in-string/perm-in-string.py @@ -0,0 +1,68 @@ +class Solution: + + # SLIDING WINDOW: + + # CONSIDER: + + # if s2 contains a permutation of s1 then + # there exists a contiguous string s1_x + # such that the count of each character + # in s1_x is the same s2 + + # Given this, we slide a window over s2, + # keeping track of character counts as we go + # if the characters match s1's characters, we return + # true. + + # since we do at most 26 comparisons (one for each character) + # per window, we see this is O(n) + + def checkInclusion(self, s1: str, s2: str) -> bool: + + if len(s2) < len(s1): + return False + + s1_counts = [0] * 26 + s2_counts = [0] * 26 + + for char in s1: + s1_counts[to_int(char)] += 1 + + left_ptr = 0 + right_ptr = len(s1) - 1 + + # initialize first window + for i in range(0, right_ptr + 1): + s2_counts[to_int(s2[i])] += 1 + + while right_ptr < len(s2): + # check count + + if compare_lists(s2_counts, s1_counts): + return True + else: + s2_counts[to_int(s2[left_ptr])] -= 1 + left_ptr += 1 + + right_ptr += 1 + + if right_ptr >= len(s2): + return False + + s2_counts[to_int(s2[right_ptr])] += 1 + + return False + + +def to_int(char): + return ord(char) % 97 + +# assumes len(ls1) == len(ls2) which should +# be true when initialized to represent lower case +# characters. + +def compare_lists(ls1, ls2): + for i in range(0, len(ls1)): + if ls1[i] != ls2[i]: + return False + return True diff --git a/reorder-list/reorder-list.py b/reorder-list/reorder-list.py @@ -0,0 +1,77 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next + +# Do not return anything, modify head in-place instead. + +# IDEA: +# first -> last, second -> second to last, inner most is at the end + +# IDEA 2: + +# Cut list in half O(n) time O(1) +# interlace lists O(n) +# return nothing + +class Solution: + def reorderList(self, head: Optional[ListNode]) -> None: + + # count length + + current = head + n = 0 + + while current is not None: + n += 1 + current = current.next + + if n == 1: + return None + + # compute half + + midpoint_index = n // 2 + + # split half + + midpoint = head + + for i in range(0, midpoint_index - 1): + midpoint = midpoint.next + + midpoint_left = midpoint + midpoint = midpoint.next + midpoint_left.next = None + + + # reverse second half + + iterations = n - midpoint_index + left = midpoint + right = midpoint.next + left.next = None + + for i in range(0, iterations - 1): + temp_next = right.next + right.next = left + left = right + right = temp_next + + head_of_reverse = left + + # interlace + + # current_left = head + # current_right = head_of_reverse + + current = head + next_node = head_of_reverse + + while next_node is not None: + temp_next = current.next + current.next = next_node + + current = next_node + next_node = temp_next diff --git a/reverse-linked-list/reverse-list.py b/reverse-linked-list/reverse-list.py @@ -0,0 +1,26 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + + # number of nodes is min == 0 + def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: + + if head is None or head.next is None: + return head + + left = head + right = head.next + head.next = None + + while right is not None: + temp = right.next + right.next = left + left = right + right = temp + + head = left + + return head