k次运算后求最小和的更有效方法

时间:2019-02-26 12:50:38

标签: python

对数组进行k次操作,以便每次将最大值除以2并四舍五入。 经过这k次操作后,我需要找到它的最小值。 k和数组num> 1中的所有数字。 minSum方法接收一个名为num和整数k的数组。 适用于我的具有很差的时间复杂性的原始Python代码是:

String[] categories = listCategories.toArray(new String[listCategories.size()]);
Double[] values = listValues.toArray(new Double[listValues.size()]);

final int numOfPoints = categories.length;
final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange);
final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values, valuesDataRange);

XDDFPieChartData.Series firstSeries = (XDDFPieChartData.Series) pie.getSeries().get(0);
firstSeries.replaceData(categoriesData, valuesData);
firstSeries.setTitle(chartTitle, chart.setSheetTitle(chartTitle, 0));
firstSeries.setExplosion(25);
chart.plot(pie);

我也尝试过首先对数组进行排序,但是随后我尝试的每个算法都失败了。 您能想到一种具有良好时间复杂度的好的算法吗?最好不使用特殊进口。

5 个答案:

答案 0 :(得分:3)

标准库(即无特殊导入)带有heapq模块,该模块使算法O(3n + k *(2 lg n))=> O(lg n):

import math
import heapq

def minSum(num, k):
    heap = [-n for n in num]  # negate values for max-heap
    heapq.heapify(heap)

    for i in range(k):
        # Find max value
        max_value = heapq.heappop(heap)
        # Change max value to rounded half
        # use floor since we've negated the values
        heapq.heappush(heap, math.floor(max_value/2))

    # Calculate minimum sum
    return -sum(heap)  # reverse polarity again

更新1:(来自@ raury-daulton的评论)结合了pop / push,O(3n + k *(lg n))=> O(lg n):

def minSum(num, k):
    heap = [-n for n in num]  # negate values for max-heap
    heapq.heapify(heap)

    for i in range(k):
        max_value = heap[0]
        heapq.heapreplace(heap, math.floor(max_value/2))

    # Calculate minimum sum
    return -sum(heap)  # reverse polarity again

更新2:直接使用最大堆O(2n + k *(lg n))=> O(lg n)

def heapreplace_max(heap, item):
    "We need to implement this ourselves from primitives."
    returnitem = heap[0]
    heap[0] = item
    heapq._siftup_max(heap, 0)
    return returnitem


def minSum(num, k):
    heap = num   # alias for consistency with other samples
    heapq._heapify_max(heap)  # make it a max heap (no negation hack)

    for i in range(k):
        max_value = heap[0]
        heapreplace_max(heap, math.ceil(max_value/2))

    return sum(heap)

更新3:的最终优化(这要求输入数组必须是int的数组)。

def minSum(num, k):
    heap = num   # alias for consistency with other samples
    heapq._heapify_max(heap)

    for i in range(k):
        max_value = heap[0]
        if max_value == 1:  # exit early if there is no more work
            break
        new_val = (max_value >> 1) + (max_value & 1)  # same as, but much faster than math.ceil(max_value/2)
        heapreplace_max(heap, new_val)

    return sum(heap)

k的上限是sum(math.floor(math.log(v, 2)+1) for v in num)(即表示所有输入数字所需的总位数)。预计算循环变量可能比在循环中包含if max_value == 1:更快,即:

for i in range(min(k, int(sum(floor(log(v, 2)+1) for v in num)))):
    max_value = heap[0]
    new_val = ...

但是我还没有实际测量。

答案 1 :(得分:0)

您的代码的每个循环都会遍历整个数组两次,因此您的算法的执行顺序为kn,其中n是数组的长度。您可以通过在每次操作后不取总和来加快速度,因为您的操作“除以2并四舍五入”不能减少总和。 (这取决于没有一个数组值可以为负的事实。)仅在应用所有k操作之后取总和。这将使您的执行量减少大约一半。

另一个更重要的优化是避免在数组中搜索最大值。我建议您使用heapq(优先级队列)结构。您存储数组值的负数,因此heapq的最小值是数组最大值的负数。然后,找到最大数组值是一个顺序1操作,而更改它是一个顺序log(n)操作。使用heapreplace方法进行替换,以获取最大速度。使用heapify将数组放入堆是唯一的命令n操作,但这仅发生一次。

如果有时间,我将在今天晚些时候添加代码。该算法确实需要一次导入,即heapq,但是它在标准库中,因此实际上不算作“特殊导入”。

答案 2 :(得分:0)

O(n + 10000)= O(n)的解决方案是可能的,每次为了使最终答案最小化,您应该选择最大x值,您可以使用说堆来解决问题,但是由于数字数量少的想法可以在更短的时间内解决问题。

<button 
      type="submit"
      disabled={!fistname && !lastname}
    />

答案 3 :(得分:0)

这个在js中?

s= [89,62,3,4,55,6]
console.log(s.length)
n=3

for(k=0; k < n; k++){
    max = s[0]
    j=0
  for(i=0; i < s.length; i++){
   if(max < s[i]) {
     max = s[i]
      j=i
   }
   if(i === s.length-1){
     s[j]= s[j]/2
   }
  }
}

console.log(s)

答案 4 :(得分:-1)

Java : Minimum sum K operations 
public static int minimumSum(int[] A, int k) {
              int sum = 0;
              Arrays.sort(A);
              for (int i = 0; i < k; i++) {

                     int len = A.length;

                     if (A[len - 1] % 2 == 0) {

                           A[len - 1] = A[len - 1] / 2;

                     } else {

                           A[len - 1] = (int) Math.ceil((double) A[len - 1] / 2);

                     }
                     Arrays.sort(A);
              }

              for (int i = 0; i < A.length; i++) {
                     sum += A[i];
              }
              return sum;

       }