简体   繁体   English

找到列表中元素总和减半的最小步骤数,其中每个步骤将列表中的项目减半 O(N)

[英]Find the minimum number of steps to half the sum of elements in a list where each step halves an item in the list in O(N)

I came across an interview question that went like this:我遇到了这样一个面试问题:

There are factories in an area which produce a pollutive gas and filters are to be installed at each factory to reduce the pollution.某地区有工厂产生污染气体,每个工厂都安装过滤器以减少污染。 Each filter installed would half the pollution in that factory.每安装一个过滤器,该工厂的污染就会减少一半。 Each factory can have multiple filters.每个工厂可以有多个过滤器。 There is a list of N integers representing the level of pollution in each of the N factories in the area.有一个包含 N 个整数的列表,代表该地区 N 个工厂中每个工厂的污染程度。 Find the minimum number of filters needed to half the overall pollution.找出使总污染减半所需的最少过滤器数量。

Eg - Let [3, 5, 6, 1, 18] be the list of pollution levels in 5 factories例如 - 设 [3, 5, 6, 1, 18] 为 5 家工厂的污染等级列表

  • Overall pollution = 3+5+6+1+18 = 33 (target is 33/2 = 16.5)总体污染=3+5+6+1+18=33(目标为33/2=16.5)

  • Install a filter in factory given by index=4 -- > pollution levels will be [3, 5, 6, 1, 9]在 index=4 给定的工厂中安装过滤器 --> 污染级别为 [3, 5, 6, 1, 9]

  • Install a filter in factory given by index=4 -- > pollution levels will be [3, 5, 6, 1, 4.5]在 index=4 给定的工厂中安装过滤器 --> 污染级别为 [3, 5, 6, 1, 4.5]

  • Install a filter in factory given by index=2 -- > pollution levels will be [3, 5, 3, 1, 4.5]在 index=2 给定的工厂中安装过滤器 --> 污染级别为 [3, 5, 3, 1, 4.5]

  • Need 3 filters minimum to half the overall pollution.至少需要 3 个过滤器才能消除总体污染的一半。

N is an integer within the range [1....30,000]. N 是 [1....30,000] 范围内的 integer。 Each element in the list is an integer within the range [0....70,000]列表中的每个元素都是 [0....70,000] 范围内的 integer

The solution I came up with for this was simple: Find the max in the list and half in every time until the sum is <=target我为此提出的解决方案很简单:在列表中找到最大值,每次都找到一半,直到总和 <=target

def solution(A):
    total = sum(A)
    target = total/2
    count = 0
    while total>target:
        count+=1
        max_p = max(A)
        total-= max_p/2
        A.remove(max_p)
        A.append(max_p/2)
    return count

This works well, except that the time complexity seems to be O(N^2).这很好用,除了时间复杂度似乎是 O(N^2)。 Can someone please suggest an approach to solve this with less time complexity (preferably O(N))?有人可以建议一种时间复杂度较低(最好是 O(N))来解决这个问题的方法吗?

Maybe you could utilize a max heap to retrieve the worst factory more efficiently than you are right now, ie, using a heap would allow for an O(N log N) solution:也许您可以利用最大堆比现在更有效地检索最差工厂,即,使用堆将允许O(N log N)解决方案:

import heapq


def filters_required(factories: list[int]) -> int:
    """Returns minimum filters required to halve pollution."""
    current_pollution = sum(factories)
    goal_pollution = current_pollution / 2
    filters = 0
    factory_pollution_max_heap = [-p for p in factories]
    heapq.heapify(factory_pollution_max_heap)
    while current_pollution > goal_pollution:
        worst_factory = heapq.heappop(factory_pollution_max_heap)
        pollution = worst_factory / 2
        current_pollution += pollution  # Use += since pollution will be a negative number.
        heapq.heappush(factory_pollution_max_heap, pollution)
        print('DEBUG:', [-p for p in factory_pollution_max_heap], current_pollution)
        filters += 1
    return filters


def main() -> None:
    print(f'{filters_required(factories=[3, 5, 6, 1, 18]) = }')


if __name__ == '__main__':
    main()

Output: Output:

DEBUG: [9.0, 6, 3, 1, 5] 24.0
DEBUG: [6, 5, 3, 1, 4.5] 19.5
DEBUG: [5, 4.5, 3, 1, 3.0] 16.5
filters_required(factories=[3, 5, 6, 1, 18]) = 3

My O(N log N) answer in Java:我在 Java 中的 O(N log N) 答案:

public static int pollution(double[] factories) {
    int filters = 0;
    double half = 0, currSum = 0, temp = 0;
    PriorityQueue<Double> pq = new PriorityQueue<>(Collections.reverseOrder());

    for (double i : factories) {
      pq.add(i);
      half += i;
    }

    currSum = half;
    half = half / 2;

    while (currSum > half) {
      temp = pq.poll();
      currSum -= temp / 2;
      pq.add(temp / 2);
      filters++;
    }

    return filters;
}

Wrote Main code for above code to ease the testing..为上面的代码编写了主要代码以简化测试..

import java.util.Arrays;
import java.util.Collections;
import java.util.PriorityQueue;

public final class PCFiltersCount
{
    public static int pollution(final double[] aFactories)
    {
    int lFilters = 0;
    double lHalf = 0, lCurrSum = 0, lTemp = 0;

    final PriorityQueue<Double> lPriorityQueue = new PriorityQueue<>(Collections.reverseOrder());
    for (double i : aFactories)
    {
        lPriorityQueue.add(i);
        lHalf += i;
    }

    lCurrSum = lHalf;
    lHalf = lHalf / 2;

    while (lCurrSum > lHalf)
    {
        lTemp = lPriorityQueue.poll();
        lCurrSum -= lTemp / 2;
        lPriorityQueue.add(lTemp / 2);
        lFilters++;
    }

    return lFilters;
    }

    public static void main(final String[] args)
    {
    double[][][] l = {
        {{15.0, 19, 8, 1}, {3}},
        {{10, 10}, {2}},
        {{3, 0, 51}, {2}},
        {{9.0, 6, 3, 1, 5}, {4}},
        {{6, 5, 3, 1, 4.5}, {5}},
        {{5, 4.5, 3, 1, 3.0}, {5}},
        };

    for (final double[][] lFactoryData : l)
    {
        int lResult = pollution(lFactoryData[0]);
        System.out.println("for Input: " + Arrays.toString(lFactoryData[0]) + " = " + lResult);
        assert lResult == lFactoryData[1][0];
    }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM