返回

算法练习日志二:最大子序和+假币问题

闲谈

最大子序和(单调队列)

最大子序和问题是指在一个序列中找到一个连续的子序列,使得子序列的和最大。

解法一:暴力法

暴力法的思路很简单,就是枚举所有可能的子序列,然后计算每个子序列的和,最后输出最大的那个子序列的和。

def max_subarray_sum_brute_force(arr):
    max_sum = float('-inf')
    for i in range(len(arr)):
        for j in range(i + 1, len(arr) + 1):
            subarray = arr[i:j]
            subarray_sum = sum(subarray)
            max_sum = max(max_sum, subarray_sum)
    return max_sum

解法二:单调队列

单调队列是一个先进先出的队列,队列中的元素始终保持单调递减。

单调队列可以用来解决最大子序和问题,思路是将队列中的元素从小到大排序,然后将每个元素依次加入队列。当队列中的元素个数大于等于给定的窗口大小时,将队首元素弹出队列。最后,队列中剩下的元素就是最大子序和的子序列。

def max_subarray_sum_deque(arr, window_size):
    if window_size > len(arr):
        return float('-inf')

    # 创建一个单调队列
    deque = collections.deque()

    # 将第一个窗口的元素加入队列
    for i in range(window_size):
        while deque and arr[i] >= arr[deque[-1]]:
            deque.pop()
        deque.append(i)

    # 将剩下的元素依次加入队列
    max_sum = arr[deque[0]]
    for i in range(window_size, len(arr)):
        # 如果队首元素不在当前窗口中,将队首元素弹出队列
        while deque and deque[0] <= i - window_size:
            deque.popleft()

        # 将当前元素加入队列
        while deque and arr[i] >= arr[deque[-1]]:
            deque.pop()
        deque.append(i)

        # 更新最大子序和
        max_sum = max(max_sum, arr[deque[0]])

    return max_sum

假币问题(枚举法)

假币问题是指有一堆硬币,其中有一枚是假的,假的硬币比其他硬币轻。

枚举法的思路很简单,就是枚举所有的硬币,然后用天平称量每一枚硬币。如果某一枚硬币比其他硬币轻,那么它就是假的硬币。

def find_fake_coin(coins):
    # 将硬币分为两堆
    n = len(coins)
    pile1 = coins[:n // 2]
    pile2 = coins[n // 2:]

    # 称量两堆硬币
    if sum(pile1) == sum(pile2):
        # 假币在剩下的硬币中
        return find_fake_coin(coins[n // 2:])
    elif sum(pile1) > sum(pile2):
        # 假币在第一堆硬币中
        return find_fake_coin(pile1)
    else:
        # 假币在第二堆硬币中
        return find_fake_coin(pile2)