From 67287d2fa924be67db8465cc17144abdcc21643a Mon Sep 17 00:00:00 2001 From: PiyushGoel0612 <121474233+PiyushGoel0612@users.noreply.github.com> Date: Fri, 10 Oct 2025 02:36:11 +0530 Subject: [PATCH 1/2] Added the validate bst function (#2696) * Added the validate bst function * Added the validate bst function --------- Co-authored-by: Piyush Goel --- algorithms/tree/bst/validate_bst.py | 90 +++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 algorithms/tree/bst/validate_bst.py diff --git a/algorithms/tree/bst/validate_bst.py b/algorithms/tree/bst/validate_bst.py new file mode 100644 index 000000000..81dfc1952 --- /dev/null +++ b/algorithms/tree/bst/validate_bst.py @@ -0,0 +1,90 @@ +# =============================================================================== +# Validate Binary Search Tree +''' +To check if the given binary tree is a valid binary search tree (BST), we need to ensure that: + 1. The left subtree of a node contains only nodes with keys less than the node's key. + 2. The right subtree of a node contains only nodes with keys greater than the node's key. + 3. Both the left and right subtrees must also be binary search trees. +''' +# =============================================================================== + +# Tree class definition +class TreeNode: + + def __init__(self, value): + + self.val = value + self.left = None + self.right = None + +# Function to validate if a binary tree is a BST +def validate_bst(node): + ''' + Validate if a binary tree is a binary search tree (BST). + Input params : Tree Node to be validated + Returns : Tuple ( + is_bst: bool, + min_value: int | None, + max_value: int | None + ) + ''' + + # Base case: An empty tree is a valid BST + if not node: + return (True, None, None) + + # Validate the left and right subtrees + valid_left, minn_left, maxx_left = validate_bst(node.left) + valid_right, minn_right, maxx_right = validate_bst(node.right) + + # If either subtree is not valid, the whole tree is not a valid BST + if not valid_left or not valid_right: + return ( + False, + minn_left if minn_left else node.val, + maxx_right if maxx_right else node.val + ) + + # Check the current node's value against the max of the left subtree + if maxx_left is not None and maxx_left > node.val: + return ( + False, + minn_left if minn_left else node.val, + maxx_right if maxx_right else node.val + ) + + # Check the current node's value against the min of the right subtree + if minn_right is not None and minn_right < node.val: + return ( + False, + minn_left if minn_left else node.val, + maxx_right if maxx_right else node.val + ) + + # If all checks pass, the tree/subtree is a valid BST + return ( + True, + minn_left if minn_left is not None else node.val, + maxx_right if maxx_right is not None else node.val + ) + +# Example usage +if __name__ == "__main__": + # Constructing a simple binary tree + root = TreeNode(10) + root.left = TreeNode(5) + root.right = TreeNode(15) + root.right.left = TreeNode(12) + root.right.right = TreeNode(20) + + ''' + 10 + / \ + 5 15 + / \ + 12 20 + ''' + + # Validate if the constructed tree is a BST + is_bst, _, _ = validate_bst(root) + print(f"The tree is a valid BST: {is_bst}") \ No newline at end of file From 5b63e90624bebb371949fbe49bbf20aa3c8e14d0 Mon Sep 17 00:00:00 2001 From: Carlo Fraley <148927755+Carlo-Fr@users.noreply.github.com> Date: Thu, 9 Oct 2025 17:07:28 -0400 Subject: [PATCH 2/2] Added Gale-Shapley algorithm with test cases (#2013) --- algorithms/greedy/__init__.py | 1 + algorithms/greedy/gale_shapley.py | 90 +++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 algorithms/greedy/gale_shapley.py diff --git a/algorithms/greedy/__init__.py b/algorithms/greedy/__init__.py index 66184782e..ee28ff0f3 100644 --- a/algorithms/greedy/__init__.py +++ b/algorithms/greedy/__init__.py @@ -1 +1,2 @@ from .max_contiguous_subsequence_sum import * +from .gale_shapley import * \ No newline at end of file diff --git a/algorithms/greedy/gale_shapley.py b/algorithms/greedy/gale_shapley.py new file mode 100644 index 000000000..c86556074 --- /dev/null +++ b/algorithms/greedy/gale_shapley.py @@ -0,0 +1,90 @@ +""" +The Gale-Shapley algorithm is a method to solve the +stable matching/marriage problem. Given N men and women +with ranked preferences of the opposite sex, the men and +women will be matched so that each pair of man and woman +would not prefer someone over their current match. With +no conflicting preferences, the matches are stable. The +algorithm can be extended to issues that involve ranked +matching. + +Example for function: + M denotes man, W denotes woman, and number corresponds to + respective man/woman. Preference lists go from highest to lowest. + + men_preferences = { + "M1": ["W1", "W2", "W3"], + "M2": ["W1", "W3", "W2"], + "M3": ["W3", "W1", "W2"], + } + women_preferences = { + "W1": ["M2", "M1", "M3"], + "W2": ["M1", "M2", "M3"], + "W3": ["M3", "M1", "M2"], + } + + input: print(gale_shapley(men_preferences, women_preferences)) + output: {'M2': 'W1', 'M3': 'W3', 'M1': 'W2'} + Explanation: + Both Man 1 and Man 2 have a top preference of Woman 1, + and since Woman 1 has a top preference of Man 2, Man 2 + and Woman 1 are matched, and Man 1 is added back to available + men. Man 3 and Woman 3 have their top preference as each other, + so the two are matched. Man 1 then proposes to Woman 2, and + Man 1 is the top preference of Woman 2, so the two are matched. + There is no match of Man AND Woman where both would want to + leave, so the current matches are stable. + +""" + +# size denotes the number of men/women +# Function takes in dictionary for men and women preferences in style outlined above +def gale_shapley(men, women): + size = len(men) + # Initialize all men to be available + men_available = list(men.keys()) + # Initialize married to empty + married = {} + # Intialize proposal count for each man to 0 + proposal_counts = {man: 0 for man in men} + while men_available: + # Pop first available man + man = men_available.pop(0) + # Of the popped man, set woman equal to corresponding proposal index + woman = men[man][proposal_counts[man]] + #increment proposal count + proposal_counts[man] += 1 + if woman not in married: + # Set marriage if woman not married + married[woman] = man + else: + # If woman married, currently_married corresponds to currently matched man + currently_married = married[woman] + if women[woman].index(man) < women[woman].index(currently_married): + """ + If the available man is of greater preference to the woman than her + currently married partner, change the marriage to the new available + man and append the previously married man back to men_available + """ + married[woman] = man + men_available.append(currently_married) + else: + # Add man back to men_available and try woman at next index + men_available.append(man) + # Returns pairs of matched men and women in form of Man:Woman + return {man: woman for woman, man in married.items()} + +# Example case +men_preferences = { + "M1": ["W1", "W2", "W3"], + "M2": ["W1", "W3", "W2"], + "M3": ["W3", "W1", "W2"], +} +women_preferences = { + "W1": ["M2", "M1", "M3"], + "W2": ["M1", "M2", "M3"], + "W3": ["M3", "M1", "M2"], +} + +res = gale_shapley(men_preferences, women_preferences) +print(res) \ No newline at end of file