Exemple #1
0
def q1_calc_max_profit(prices: list) -> float:
    r"""Compute maximum profit from stock prices.
    
    Args:
        prices (list): List of prices as `float`. Index is number of minutes
            since beginning of trading day.
    
    Returns:
        max_profit (float): Maximum profit possible from buying then selling.
    
    Notes:
        * interviewcake.com question #1, "Apple Stocks".
        * Complexity:
            * n = len(prices)
            * Ideal: Time=O(n), Space=O(1)
            * Realized: Time=O(n), Space=O(1)
    
    References:
        .. [1] https://www.interviewcake.com/question/stock-price
    
    """
    # Check arguments.
    utils.check_arguments(antns=q1_calc_max_profit.__annotations__,
                          lcls=locals())
    # Calculate max_profit sequentially with min_price since the fund must be
    # bought before being sold.
    (min_price, max_profit) = (prices[0], 0.0)
    for price in prices:
        min_price = min(min_price, price)
        max_profit = max(max_profit, price - min_price)
    return max_profit
Exemple #2
0
 def calc_segi(seg1: tuple, seg2: tuple) -> tuple:
     r"""Calculate the intersection of a line segment.
     
     Args:
         seg1 (tuple):
         seg2 (tuple):
             Segments are `tuple`s with ('x', 'width') for x-axis or
             ('y', 'height') for y-axis.
     
     Returns:
         segi (tuple):
             Segment intersection as `tuple`. Same format as `seg1`, `seg2`.
             All values are `None` if segments are disjoint.
     
     """
     # Check arguments.
     utils.check_arguments(antns=calc_segi.__annotations__, lcls=locals())
     # Order segments by coordinates of leading edge.
     # Disjoint if first trailing edge < second leading edge.
     if seg1[0] < seg2[0]:
         (seg1st, seg2nd) = (seg1, seg2)
     else:
         (seg1st, seg2nd) = (seg2, seg1)
     if seg1st[0] + seg1st[1] < seg2nd[0]:
         segi = (None, None)
     else:
         segi = (seg2nd[0],
                 min(seg1st[0] + seg1st[1], seg2nd[0] + seg2nd[1]) -
                 seg2nd[0])
     return segi
def q1(pr_a: float = 0.28,
       pr_b: float = 0.29,
       pr_c: float = 0.19,
       pr_aib: float = 0.14,
       pr_aic: float = 0.12,
       pr_bic: float = 0.10,
       pr_aibic: float = 0.08) -> float:
    r"""Calculate P(not(A union B union C)).
    
    Args:
        pr_[a,b,c] (float): [P(A), P(B), P(C)]
        pr_[aib,aic,bic] (float): [P(A intr B), P(A intr C), P(B intr C)]
        pr_aibic (float): P(A intr B intr C)
    
    Returns:
        pr_naubuc (float): P(not(A union B union C))
    
    Notes:
        * P(not(A union B union C)) = (1 - (
            P(A) + P(B) + P(C) - P(A intr B) - P(A intr C)
            - P(B intr C) + P(A intr B intr C)))

    """
    # Check arguments.
    utils.check_arguments(antns=q1.__annotations__, lcls=locals())
    # Calculate probability of union complement.
    pr_naubuc = 1.0 - (pr_a + pr_b + pr_c - pr_aib - pr_aic - pr_bic +
                       pr_aibic)
    return pr_naubuc
def sum_ints(path: str) -> int:
    r"""Sum the integers from a text file, one integer per line.

    Args:
        path(str): Path to file. File contains one `int` per line.

    Returns:
        total(int): Total sum of all `int`s in the file.

    Notes:
        * Example 4 from [1]_.
        * Complexity:
            * n = number of lines in `path` file.
            * Time: O(n)
            * Space: O(1)

    References:
        .. [1] https://sites.google.com/site/steveyegge2/
               five-essential-phone-screen-questions
    
    """
    # Check input.
    utils.check_arguments(antns=sum_ints.__annotations__, lcls=locals())
    if not os.path.exists(path):
        raise ValueError(
            ("`path` does not exist:\n" + "path =\n{path}").format(path=path))
    # Sum the lines in the file.
    total = 0
    with open(path, 'rt') as fobj:
        for line in fobj:
            total += int(line.strip())
    return total
Exemple #5
0
def q16_max_duffel_bag_value(cake_tuples: list, bag_capacity: int) -> int:
    r"""Compute max value that the duffel bag can hold.
    
    Args:
        cake_tuples (list): `list` of `tuple`s (cake_weight, cake_value)
            cake_weight, cake_value > 0
        bag_capacity (int): Max weight that the duffel bag can hold.
    
    Returns:
        bag_value (int): Max value that the duffel bag can hold.
            Returns `numpy.inf` if there is a cake with weight = 0.
        
    Notes:
        * interviewcake.com question #16, "The Cake Thief"
        * Complexity:
            * (n, k) = (len(cake_tuples), bag_capacity)
            * Ideal:
                * Time: O(n*k)
                * Space: O(k)
            * Realized:
                * Time: O(n*k)
                * Space: O(k)
                
    References:
        .. [1] https://www.interviewcake.com/question/python/cake-thief
    
    """
    # Check arguments.
    utils.check_arguments(antns=q16_max_duffel_bag_value.__annotations__,
                          lcls=locals())
    for tup in cake_tuples:
        for item in tup:
            if item < 0:
                raise ValueError(
                    ("All items in `cake_tuples` must be >= 0:\n" +
                     "cake_tuples =\n" + "{ct}").format(ct=cake_tuples))
            elif not isinstance(item, int):
                raise ValueError(
                    ("All items in `cake_tuples` must be type `int`:\n" +
                     "cake_tuples =\n" + "{ct}").format(ct=cake_tuples))
    if bag_capacity < 0:
        raise ValueError(("`bag_capacity` must be >= 0\n" +
                          "bag_capacity = {bc}").format(bc=bag_capacity))
    # With dynamic programming:
    bag_value = 0
    for (cake_weight, cake_value) in cake_tuples:
        if cake_weight == 0 and cake_value > 0:
            bag_value = sys.maxsize
    if bag_value != sys.maxsize:
        bag_values_max = [0] * (bag_capacity + 1)
        for bag_capacity_current in range(len(bag_values_max)):
            for (cake_weight, cake_value) in cake_tuples:
                if cake_weight <= bag_capacity_current:
                    bag_values_max[bag_capacity_current] = max(
                        bag_values_max[bag_capacity_current], cake_value +
                        bag_values_max[bag_capacity_current - cake_weight])
        bag_value = bag_values_max[bag_capacity]
    return bag_value
Exemple #6
0
def q5_count_combinations(amount: int, denoms: list) -> int:
    r"""Count the number of combinations of `denomiations` that sum to `amount`.
    
    Args:
        amount (int): Amount of money to partition.
        denoms (list): `list` of demoninations to partition `amount`
    
    Returns:
        ncombos (int): Number of combinations.
    
    Raises:
        ValueError:
            * Raised if not amount >= 1.
            * Raised if not len(denoms) >= 1.
            * Raised if any denoms are not `int`.
            * Raised if any denoms are not >= 1.
        
    Notes:
        * interviewcake.com question #5, "Making Change".
        * Complexity:
            * n = amount; k = len(denoms)
            * Complexity:
                * Ideal: Time: O(n*k); Space: O(n)
                * Realized: Time: O(n*k); Space: O(n)
    
    References:
        .. [1] https://www.interviewcake.com/question/python/coin
    
    """
    # Check arguments.
    utils.check_arguments(antns=q5_count_combinations.__annotations__,
                          lcls=locals())
    if not amount >= 1:
        raise ValueError(
            ("`amount` must be >= 1\n" + "amount = {amt}").format(amt=amount))
    if not len(denoms) >= 1:
        raise ValueError(("`len(denoms)` must be >= 1\n" +
                          "len(denoms) = {nden}").format(nden=len(denoms)))
    for denom in denoms:
        if not isinstance(denom, int):
            raise ValueError(
                ("All `denoms` must be type `int`\n" + "denom = {den}\n" +
                 "type(denom) = {tden}").format(den=denom, tden=type(denom)))
        if not denom >= 1:
            raise ValueError(("All `denoms` must be >= 1\n" +
                              "denom = {den}").format(den=denom))
    # For each denomination, iterate through the amounts to find the number of
    # combinations per amount.
    # Note: For each amount, iterating through denominations will instead find
    # the number of permutations per amount.
    amt_ncombos = [0] * (amount + 1)
    amt_ncombos[0] = 1
    for den in denoms:
        for amt in range(den, amount + 1):
            amt_ncombos[amt] += amt_ncombos[amt - den]
    ncombos = amt_ncombos[amount]
    return ncombos
Exemple #7
0
def q14_movies_match_flight(flight_length: int, movie_lengths: list) -> bool:
    r"""Check if the sum of two movie lengths exactly equals the flight length.
    
    Args:
        flight_length (int): Length (duration) of the flight. Units: minutes.
        movie_lengths (list): List of `int` as the lengths (durations) of
            movies. Units: minutes.
        
    Returns:
        found_match (bool):
            True: There are two movies whose sum lengths exactly matches the
                length of the flight.
            False: There are not two movies...
        
    Notes:
        * interviewcake.com question #14, "Inflight Entertainment" [1]_.
        * Complexity:
            * Ideal:
                * Time: O(n)
                * Space: O(n)
            * Realized:
                * Time: O(n)
                * Space: O(n)
    
    References:
        .. [1] https://www.interviewcake.com/question/python/
            inflight-entertainment
    
    """
    # Check arguments.
    utils.check_arguments(antns=q14_movies_match_flight.__annotations__,
                          lcls=locals())
    # Memoize movie lengths seen.
    # Without `collections.defaultdict`:
    # `in` calls `dict.__contains__`, which is O(1) lookup for Python 3x.
    #found_match = False
    #movie_lengths_seen = dict()
    #for movie_length1 in movie_lengths:
    #    movie_length2 = flight_length - movie_length1
    #    if movie_length2 in movie_lengths_seen:
    #        found_match = True
    #        break
    #    # Add movie_length1 after testing for movie_length2 to avoid watching
    #    # movie1 twice.
    #    movie_lengths_seen[movie_length1] = True
    # With `collections.defaultdict`:
    movie_lengths_seen = collections.defaultdict(lambda: False)
    for movie_length1 in movie_lengths:
        movie_length2 = flight_length - movie_length1
        found_match = movie_lengths_seen[movie_length2]
        if found_match:
            break
        # Add movie_length1 after testing for movie_length2 to avoid watching
        # movie1 twice.
        movie_lengths_seen[movie_length1] = True
    return found_match
def print_mult_table(max_fac: int = 12) -> None:
    r"""Print a multiplication table to stdout.
    
    Args:
        max_fac (int, optional, default=12):  Factor up to which to make table.
            `max_fac` >= 0.
            Example: max_fac=12 (default) makes multiplication table
            0x0,  0x1,  ..., 0x12
            1x0,  1x1,  ..., 1x12
            ...,  ...,  ..., ...
            12x0, 12x1, ..., 12x12

    Returns:
        None: Prints table to `stdout`.

    Raises:
        ValueError: Raised if `max_fac` < 0.

    Notes:
        * Example 3 from [1].
        * Complexity:
            * n = max_fac
            * Time: O(n^2)
            * Space: O(1)

    References:
        .. [1] https://sites.google.com/site/steveyegge2/five-essential-phone-screen-questions

    """
    # Check input
    utils.check_arguments(antns=print_mult_table.__annotations__,
                          lcls=locals())
    if max_fac < 0:
        raise ValueError(("`max_fac` must be >= 0\n" +
                          "max_fac = {max_fac}").format(max_fac=max_fac))
    # Define custom print function for factors and products (elements)
    # of multiplication table,
    max_prod = max_fac * max_fac
    max_digits = len(str(max_prod))
    fmt = "{elt:>" + str(max_digits) + "d}"
    print_elt = lambda elt: print(fmt.format(elt=elt), end=' ')
    # Print multiplication table.
    for row_fac in range(max_fac + 1):
        # Print header row
        if row_fac == 0:
            print(' ' * (max_digits - 1) + 'x', end=' ')
            [print_elt(elt) for elt in range(max_fac + 1)]
            print()
        # Print header column element for every row.
        print_elt(elt=row_fac)
        # Print products
        [print_elt(row_fac * col_fac) for col_fac in range(max_fac + 1)]
        print()
    return None
Exemple #9
0
def q15_fib(idx: int) -> int:
    r"""Compute the nth Fibonacci number.
    
    Args:
        idx (int): Nth Fibonacci number to compute.
            `idx` >= 0.
    
    Returns:
        fnum (int): Nth Fibonacci number.
        
    Raises:
        ValueError: Raised if `idx` < 0 or is not `int`.
    
    Notes:
        * interviewcake.com question #15, "Compute Nth Fibonacci Number" [1]_.
        * fib(n) = fib(n-1) + fib(n-2), fib(0) = 0, fib(1) = 1.
        * Complexity:
            * Ideal:
                * Time: O(lg(n))
                * Space: O(1)
            * Realized:
                * Time: O(n)
                * Space: O(1)
    
    References:
        .. [1] https://www.interviewcake.com/question/python/nth-fibonacci

    """
    # Check arguments.
    utils.check_arguments(antns=q15_fib.__annotations__, lcls=locals())
    if idx < 0:
        raise ValueError(
            ("`idx` must be >= 0:\n" + "idx = {idx}").format(idx=idx))
    # Compute nth Fibonacci number.
    for inum in range(idx + 1):
        if inum == 0:
            fnum = 0
            fnum_prev2 = 0
        elif inum == 1:
            fnum = 1
            fnum_prev1 = 1
        else:
            fnum = fnum_prev1 + fnum_prev2
            fnum_prev2 = fnum_prev1
            fnum_prev1 = fnum
    return fnum
def q2(pr_a: float = 0.30, pr_b: float = 0.40, pr_naub: float = 0.35) -> float:
    r"""Calculate P(A intr B).
    
    Args:
        pr_[a,b] (float): [P(A), P(B)]
        pr_naub (float): P(not(A union B))
    
    Returns:
        pr_aib (float): P(A intr B)
    
    Notes:
        * P(A union B) = P(A) + P(B) - P(A intr B)  
          P(A union B) = 1 - P(not(A union B))  
          => P(A intr B) = P(A) + P(B) - (1 - P(not(A union B)))
    
    """
    # Check arguments.
    utils.check_arguments(antns=q2.__annotations__, lcls=locals())
    # Calculate probability of intersection.
    pr_aib = pr_a + pr_b - (1.0 - pr_naub)
    return pr_aib
Exemple #11
0
def q2_get_products_of_all_ints_except_at_index(ints: list) -> list:
    r"""Calculate the products of all integers except for the one each index.

    Args:
        ints (list): `list` of `int` factors.

    Returns:
        prods (list): `list` of `int` products
    
    Notes:
        * interviewcake.com question #2, "Product of All Other Numbers".
        * Complexity:
            * n = len(prices)
            * Ideal: Time=O(n), Space=O(n)
            * Realized: Time=O(n), Space=O(n)

    References:
        ..[1] https://www.interviewcake.com/question/product-of-other-numbers
    
    """
    # Check arguments.
    utils.check_arguments(
        antns=q2_get_products_of_all_ints_except_at_index.__annotations__,
        lcls=locals())
    # Allocate a list of ones for `prods`. Multiply products at indexes by
    # cumulative product then update cumulative product. Repeat iterating in
    # opposite direction through `ints`.
    idxs = range(len(ints))
    prods = [1] * len(ints)
    prod_cuml = 1
    for idx in idxs:
        prods[idx] = prod_cuml
        prod_cuml *= ints[idx]
    prod_cuml = 1
    for idx in reversed(idxs):
        prods[idx] *= prod_cuml
        prod_cuml *= ints[idx]
    return prods
def reverse_string(string: str) -> str:
    r"""Reverse a string.
    
    Args:
        string (str): String with __getslice__ method.

    Returns:
        string_rev (str): Reversed `string`.

    Notes:
        * Example 1 from [1]_.
        * Complexity:
            * n = len(string)
            * Time: O(n)
            * Space: O(n)

    References:
        .. [1] https://sites.google.com/site/steveyegge2/five-essential-phone-screen-questions

    """
    utils.check_arguments(antns=reverse_string.__annotations__, lcls=locals())
    string_rev = string[::-1]
    return string_rev
def calc_nth_fib(nth: int) -> int:
    r"""Calculate the nth Fibonacci number (0-indexed).

    Args:
        nth (int): The index number of the Fibonacci number to calculate.
            `nth` >= 0

    Returns:
        fib (int): The `nth` Fibonacci number in sequence.
    
    Raises:
        ValueError: Raised if `nth` < 0. 

    Notes:
        * fib(0) = 0, fib(1) = 1, fib(n) = fib(n-1) + fib(n-2).
        * Complexity:
            * n = `nth`
            * Time: O(n)
            * Space: O(1)

    """
    # Check arguments.
    utils.check_arguments(antns=calc_nth_fib.__annotations__, lcls=locals())
    if nth < 0:
        raise ValueError(
            ("`nth` must be >= 0\n" + "nth = {nth}").format(nth=nth))
    # Initialize Fibonacci sequence to reach nth Fibonacci number.
    maxlen = 2
    fibs_prev = collections.deque(maxlen=maxlen)
    fibs_prev.extend(range(maxlen))
    if nth < maxlen:
        fib = fibs_prev[nth]
    else:
        idxs_res = range((nth - maxlen) + 1)
        [fibs_prev.append(sum(fibs_prev)) for idx in idxs_res]
        fib = fibs_prev[-1]
    return fib
Exemple #14
0
def q6_calc_intersection(rect1: dict, rect2: dict) -> dict:
    r"""Calculate the intersection of two rectangles.
    
    Args:
        rect1 (dict):
        rect2 (dict):
            Rectangles are `dicts` with keys `x`, `y`, `width`, `height`.
            `x`, `y` are the coordinates of the bottom-left corner.
            Values are `int`.
    
    Returns:
        recti (dict):
            Rectangle intersection as `dict`. Same format at `rect1`, `rect2`.
            All values are `None` if rectangles are disjoint.
    
    Raises:
        ValueError:
            * Raised if missing required keys.
            * Raised if values are not `int`.
            * Raised if width or height < 0

    Notes:
        * interviewcake.com question #6, "Rectangular Love".
        * Complexity:
            * Ideal: Time: O(1); Space: O(1)
            * Realized: Time: O(1); Space: O(1)
    
    References:
        .. [1] https://www.interviewcake.com/question/rectangular-love

    """
    # Check arguments.
    utils.check_arguments(antns=q6_calc_intersection.__annotations__,
                          lcls=locals())
    keys = set(['x', 'y', 'width', 'height'])
    if not keys.issubset(set(rect1.keys())):
        raise ValueError(
            ("`rect1` is missing required keys:\n" +
             "required_keys = {keys}\n" + "rect1.keys() = {r1keys}").format(
                 keys=keys, r1keys=set(rect1.keys())))
    if not keys.issubset(set(rect2.keys())):
        raise ValueError(
            ("`rect2` is missing required keys:\n" +
             "required_keys = {keys}\n" + "rect2.keys() = {r2keys}").format(
                 keys=keys, r2keys=set(rect2.keys())))
    for key in keys:
        if not isinstance(rect1[key], int):
            raise ValueError(
                ("All values must be `int`:\n" +
                 "type(rect1[{key}]) = {tp}").format(key=key,
                                                     tp=type(rect1[key])))
        if not isinstance(rect2[key], int):
            raise ValueError(
                ("All values must be `int`:\n" +
                 "type(rect2[{key}]) = {tp}").format(key=key,
                                                     tp=type(rect2[key])))
    for key in ['width', 'height']:
        if not rect1[key] >= 0:
            raise ValueError(
                ("'width' and 'height' values must be >= 0:\n" +
                 "type(rect1[{key}]) = {tp}").format(key=key,
                                                     tp=type(rect1[key])))
        if not rect2[key] >= 0:
            raise ValueError(
                ("'width' and 'height' values must be >= 0:\n" +
                 "type(rect2[{key}]) = {tp}").format(key=key,
                                                     tp=type(rect2[key])))
    # Define a method to compute the intersection of two segments.
    def calc_segi(seg1: tuple, seg2: tuple) -> tuple:
        r"""Calculate the intersection of a line segment.
        
        Args:
            seg1 (tuple):
            seg2 (tuple):
                Segments are `tuple`s with ('x', 'width') for x-axis or
                ('y', 'height') for y-axis.
        
        Returns:
            segi (tuple):
                Segment intersection as `tuple`. Same format as `seg1`, `seg2`.
                All values are `None` if segments are disjoint.
        
        """
        # Check arguments.
        utils.check_arguments(antns=calc_segi.__annotations__, lcls=locals())
        # Order segments by coordinates of leading edge.
        # Disjoint if first trailing edge < second leading edge.
        if seg1[0] < seg2[0]:
            (seg1st, seg2nd) = (seg1, seg2)
        else:
            (seg1st, seg2nd) = (seg2, seg1)
        if seg1st[0] + seg1st[1] < seg2nd[0]:
            segi = (None, None)
        else:
            segi = (seg2nd[0],
                    min(seg1st[0] + seg1st[1], seg2nd[0] + seg2nd[1]) -
                    seg2nd[0])
        return segi

    # Calculate the rectangle intersections for x-axes and y-axes.
    # If any axes are disjoint, then all axes are disjoint (`None` values).
    recti = dict()
    (recti['x'], recti['width']) = calc_segi(seg1=(rect1['x'], rect1['width']),
                                             seg2=(rect2['x'], rect2['width']))
    (recti['y'],
     recti['height']) = calc_segi(seg1=(rect1['y'], rect1['height']),
                                  seg2=(rect2['y'], rect2['height']))
    for val in recti.values():
        if val is None:
            recti = {'x': None, 'y': None, 'width': None, 'height': None}
            break
    return recti
Exemple #15
0
def q4_condense_meeting_times(times: list) -> list:
    r"""Condense meeting times into contiguous blocks.
    
    Args:
        times (list): `list` of `tuple`s of `int`s as meeting times. `int`s are
            number of 30-minute blocks since 9:00am. Does not need to be sorted.
            Example: `times = [(0, 1), (3, 5), (2, 4)]`

    Returns:
        condensed (list): `list` of combined meeting times as `tuple`s.
            Example: `condensed = [(0, 1), (2, 5)]`

    Notes:
        * interviewcake.com question #4, "Merging Meeting Times".
        * Complexity:
            * n = len(times)
            * Ideal: Time=O(n*lg(n)), Space=O(n)
            * Realized: Time=O(n*lg(n)), Space=O(n)

    References:
        .. [1] https://www.interviewcake.com/question/merging-ranges

    """
    # Check arguments.
    utils.check_arguments(antns=q4_condense_meeting_times.__annotations__,
                          lcls=locals())
    # #########################################
    # # Without sorting: Time: O(n**2); Space: O(n)
    # # Iterate through `times` comparing current time to:
    # # * condensed times in `condensed`, iterating forwards
    # # * uncondensed times in `times`, iterating forwards
    # # * uncondensed times in `times`, iterating backwards
    # # * condensed times in `condensed`, iterating backwards
    # # Backwards and forwards iteration is necessary for unsorted `times`.
    # def do_overlap(time1:tuple, time2:tuple) -> bool:
    #     # Check arguments.
    #     utils.check_arguments(
    #         antns=do_overlap.__annotations__,
    #         lcls=locals())
    #     # Order meeting times by start time.
    #     # Overlap if first stop time >= second start time.
    #     if time1[0] < time2[0]:
    #         (time1st, time2nd) = (time1, time2)
    #     else:
    #         (time1st, time2nd) = (time2, time1)
    #     if time1st[1] >= time2nd[0]:
    #         overlap = True
    #     else:
    #         overlap = False
    #     return overlap
    # # Compare current time to seen condensed times.
    # condensed = [times[0]]
    # for (idx, time) in enumerate(times):
    #     idx_olap = None
    #     # Compare current time with condensed times, forward.
    #     for idx_cmp in range(len(condensed)):
    #         time_cmp = condensed[idx_cmp]
    #         overlap = do_overlap(time1=time, time2=time_cmp)
    #         if overlap:
    #             time = (min(time[0], time_cmp[0]), max(time[1], time_cmp[1]))
    #             if idx_olap is None:
    #                 idx_olap = idx_cmp
    #     # Compare current time with uncondensed times, forward and backward.
    #     for idx_cmp in itertools.chain(
    #         range(idx+1, len(times)), reversed(range(idx+1, len(times)-1))):
    #         time_cmp = times[idx_cmp]
    #         overlap = do_overlap(time1=time, time2=time_cmp)
    #         if overlap:
    #             time = (min(time[0], time_cmp[0]), max(time[1], time_cmp[1]))
    #     # Compare current time with condensed times, backward.
    #     for idx_cmp in reversed(range(len(condensed))):
    #         time_cmp = condensed[idx_cmp]
    #         overlap = do_overlap(time1=time, time2=time_cmp)
    #         if overlap:
    #             time = (min(time[0], time_cmp[0]), max(time[1], time_cmp[1]))
    #             if idx_olap is None:
    #                 idx_olap = idx_cmp
    #     # Update condensed times if overlap, else append.
    #     if idx_olap is not None:
    #         condensed[idx_olap] = time
    #     else:
    #         condensed.append(time)
    ########################################
    # With sorting: Time: O(n*lg(n)); Space: O(n)
    # Sort times first by meeting start then by meeting end
    # to avoid needing to compare all meeting times to each other.
    times = sorted(times, key=operator.itemgetter(0, 1))
    condensed = [times[0]]
    for time in times:
        cond = condensed[-1]
        # If time is disjoint, append as new meeting.
        # Else change condensed meeting time.
        if cond[1] < time[0]:
            condensed.append(time)
        else:
            condensed[-1] = (cond[0], max(cond[1], time[1]))
    return condensed
Exemple #16
0
def q3_calc_highest_product_of_3(ints: list) -> int:
    r"""Calculate the highest product from integers.
    
    Args:
        ints (list): List of `ints` with `len(ints) >= 3`

    Returns:
        prod (int): Highest product from 3 `int`s.

    Raises:
        ValueError: Raised if `len(ints) < 3`.
    
    Notes:
        * interviewcake.com question #3, "Highest Product of 3".
        * Complexity:
            * n = len(ints)
            * Ideal: Time=O(n), Space=O(1)
            * Realized: Time=O(n), Space=O(1)

    References:
        ..[1] https://www.interviewcake.com/question/highest-product-of-3
    
    """
    # Check arguments.
    utils.check_arguments(antns=q3_calc_highest_product_of_3.__annotations__,
                          lcls=locals())
    if len(ints) < 3:
        raise ValueError(("`ints` must have at least 3 items:\n" +
                          "ints =\n{ints}").format(ints=ints))
    # #########################################
    # # With collections, itertools; Python 3.5.
    # max_3 = collections.deque(iterable=[1]*3, maxlen=3)
    # min_2 = collections.deque(iterable=[1]*2, maxlen=2)
    # for item in ints:
    #     # Find the 3 most positive integers.
    #     for idx in range(len(max_3)):
    #         if item > max_3[idx]:
    #             max_3.insert(item, index=idx)
    #             break
    #     # Find the 2 most negative integers.
    #     for idx in range(len(min_2)):
    #         if item < min_2[idx]:
    #             min_2.insert(item, index=idx)
    #             break
    # prod_max_3 = functools.reduce(operator.mul, max_3, 1)
    # prod_min_2 = functools.reduce(operator.mul, min_2, 1)
    # prod_minmax_3 = prod_min_2 * max_3[0]
    # prod = max(prod_max_3, prod_minmax_3)
    # #########################################
    # # With extreme integers ranked.
    # (max_1st, max_2nd, max_3rd) = (1, 1, 1)
    # (min_1st, min_2nd) = (1, 1)
    # for item in ints:
    #     # Find the 3 most positive integers.
    #     if item > max_3rd:
    #         if item > max_2nd:
    #             if item > max_1st:
    #                 max_3rd = max_2nd
    #                 max_2nd = max_1st
    #                 max_1st = item
    #             else:
    #                 max_3rd = max_2nd
    #                 max_2nd = item
    #         else:
    #             max_3rd = item
    #     # Find the 2 most negative integers.
    #     if item < min_2nd:
    #         if item < min_1st:
    #             min_2nd = min_1st
    #             min_1st = item
    #         else:
    #             min_2nd = item
    # prod = max(max_1st*max_2nd*max_3rd, max_1st*min_1st*min_2nd)
    #########################################
    # With bottom-up approach.
    (prod_1_pos, prod_2_pos, prod_3_pos) = (0, 0, 0)
    (prod_1_neg, prod_2_neg) = (0, 0)
    for item in ints:
        # Find the 3 most positive integers.
        if item >= 0:
            prod_3_pos = max(item * prod_2_pos, prod_3_pos)
            prod_2_pos = max(item * prod_1_pos, prod_2_pos)
            prod_1_pos = max(item, prod_1_pos)
        # Find the 2 most negative integers.
        else:
            item *= -1
            prod_2_neg = max(item * prod_1_neg, prod_2_neg)
            prod_1_neg = max(item, prod_1_neg)
    prod = max(prod_3_pos, prod_1_pos * prod_2_neg)
    return prod
 def myfunc(arg0: int, arg1: str) -> float:
     utils.check_arguments(antns=myfunc.__annotations__, lcls=locals())
     return 1.0