Greedy EXTREMELY HARD q

whitehousechef·2025년 6월 5일

q

There are 2 lists A and B containing (x, y) pairs of the same length,
A= [(x1, y1), (x2, y2),...,(xn, yn)]
B= [(x'1, y'1), (x'2, y'2),...,(x'n, y'n)]

x in A and B are nondecreasing order
x1<=x2<=x3 ...<=xn
x'1<=x'2<=x'3 ...<=x'n

for index 0<=i<n
we also want to make a[i][1]<b[i][1]

What do we do?

test case1
a= [(1, 0), (1, 1), (1, 7), (1, 5) ]
b= [(1, 7), (1, 9), (2, 3), (4, 1) ]
#in this case you can rearrange a
a= [(1, 5), (1, 7), (1, 1), (1, 0)]
b= [(1, 7), (1, 9), (2, 3), (4, 1) ]

test case2
a= [(1, 0), (2, 1), (3, 7), (3, 5) ]
b= [(2, 7), (2, 9), (2, 3), (2, 1) ]
#in this case you can rearrange b
a= [(1, 0), (2, 1), (3, 7), (3, 5) ]
b= [(2, 1), (2, 3), (2, 9), (2, 7) ]

#invalid test case
a = [(1, 0), (2, 1), (3, 7), (4, 5)]
b = [(2, 7), (3, 0), (4, 3), (5, 1)]

very brute force

compute all permutations and first check if x values are all increasing. If that check is true, if the y values of b >y values oa, then we can just return those 2 lists

def rearrange_lists_ultra_simple(a, b):
    """
    Ultra simple: Just try every possible rearrangement (very inefficient!)
    """
    # Try all permutations of both arrays
    for a_perm in permutations(a):
        for b_perm in permutations(b):
            # Check if x-values are still non-decreasing
            a_valid = all(a_perm[i][0] <= a_perm[i+1][0] for i in range(len(a_perm)-1))
            b_valid = all(b_perm[i][0] <= b_perm[i+1][0] for i in range(len(b_perm)-1))
            
            if a_valid and b_valid:
                # Check if y-constraint is satisfied
                if all(a_perm[i][1] < b_perm[i][1] for i in range(len(a_perm))):
                    return list(a_perm), list(b_perm)
    
    raise ValueError("No valid arrangement exists")

the perm time is n!
we are doing it twice and have n check
so time is n! ^2 * n time

n space

optimised

we are essentially filling avaialable values to be compared. If the x values of list a and b match,

1) we match the biggest avaialble value of y in a to the smallest value of y in b.

2) when we run out of elements in the available set, we populate that set with the current value but if we cant populate we raise exception

def rearrange_lists(a, b):
    n = len(a)
    if n != len(b):
        raise ValueError("Lists must have the same length")

    # Create sets to track available elements with their original indices
    available_a = set()
    available_b = set()

    result_a = [None] * n
    result_b = [None] * n

    def populate_group(available_set, arr, start_idx):
        """Populate available set with elements from the same x-group"""
        if start_idx >= len(arr):
            return start_idx

        current_x = arr[start_idx][0]
        idx = start_idx

        while idx < len(arr) and arr[idx][0] == current_x:
            available_set.add((arr[idx][1], idx))  # (y_value, original_index)
            idx += 1

        return idx

    a_idx = 0  # Current position in list a
    b_idx = 0  # Current position in list b
    result_idx = 0  # Current position in result

    while result_idx < n:
        # Populate available sets if empty
        if not available_a:
            a_idx = populate_group(available_a, a, a_idx)

        if not available_b:
            b_idx = populate_group(available_b, b, b_idx)

        # If both sets are empty, we're done
        if not available_a and not available_b:
            break

        # If one set is empty but the other isn't, no solution exists
        if not available_a or not available_b:
            raise ValueError("No valid arrangement exists")

        # Find the smallest available element in B
        min_b = min(available_b)
        smallest_b_y, b_original_idx = min_b
        available_b.remove(min_b)

        # Find the largest available element in A that's smaller than smallest_b_y
        valid_a_elements = [(y, idx) for y, idx in available_a if y < smallest_b_y]

        if not valid_a_elements:
            raise ValueError("No valid arrangement exists")

        # Choose the largest valid element from A
        largest_valid_a = max(valid_a_elements)
        largest_a_y, a_original_idx = largest_valid_a
        available_a.remove(largest_valid_a)

        # Store the results
        result_a[result_idx] = a[a_original_idx]
        result_b[result_idx] = b[b_original_idx]
        result_idx += 1

    return result_a, result_b

in the main while loop there is n^2 time so thats the main
n space

0개의 댓글