6

这个问题来自一个很棒的 youtube 频道,提供了可以在面试中提出的问题。

它基本上与在数组中找到平衡点有关。这是一个最好地解释它的例子;{1,2,9,4,-1}。在这里,因为 sum(1+2)=sum(4+(-1)) 使 9 成为平衡点。在没有检查答案的情况下,我决定实施该算法,然后再询问是否可以采用更有效的方法;

  1. 对数组O(n)中的所有元素求和
  2. 得到总和的一半O(1)
  3. 从左边开始扫描数组,当sumleft大于总和的一半时停止。上)
  4. 对右边做同样的事情,以获得求和权。 O(n)
  5. 如果sumleft等于sumright返回arr[size/2]否则返回-1

我之所以问,是因为这个解决方案毫不费力地突然出现在我的脑海中,提供了 O(n) 的运行时间。如果这个解决方案是真的,是否可以开发或者如果不是真的任何替代方法?

4

6 回答 6

6

您的算法不好(反例:)1 -1 1 0 1 -1 1,好的解决方案是计算数组的部分总和(以便您可以计算数组的每个单元sumleftsumright的 O(1) 和然后(或在同一如果您已经知道全局总和,sumleft = sumright则需要在数组中搜索一个 O(n) 的单元格。

数组的部分和A

[A[0], A[0]+A[1], A[0]+A[1]+A[2], …, A[0]+A[1]+A[2]+…+A[n-1]]

例子:

A=[5,2,3,1,4,6]
partial sum = [5,7,10,11,15,21]

使用此数组,您可以计算sumleft[i]=partial_sum[i-1]sumright[i]=partial_sum[n-1]-partial_sum[i]

改进:

如果存储所有 partial_sum 数组,首先计算全局总和,然后仅计算当前索引的部分总和,使您能够仅使用 O(1) 额外空间而不是 O(n) 额外空间。

于 2012-06-13T21:00:51.107 回答
1

我实际上有 2 个起点,一个在最左边的点 (leftLoc),一个在最右边的点 (rightLoc)。持有 sumLeft 和 sumRight 数字。

leftLoc  = 0;
rightLoc = (n - 1);
sumRight = array[rightLoc];
sumLeft  = array[leftLoc];

while(leftLoc < rightLoc){
    if(sumRight > sumLeft){
        leftLoc++;
        sumLeft += array[leftLoc];
    }else{
        rightLoc--;
        sumRight += array[rightLoc];
    } 
}

if( (sumRight + array[rightLoc - 1]) == sumLeft ){
    return rightLoc--;
}else if( (sumLeft + array[leftLoc + 1]) == sumRight){
    return leftLoc++;
}else{
    // return floating point number location in the middle of the 2 locations
}

一直跟踪总共移动了多少位置 O(n)

您可能会发现您的平衡点是一个浮点数,位于最终点的中间(一旦它们位于彼此相邻的整数位置)。

这甚至应该适用于负数示例。也许我遗漏了一些细粒度的细节,但是这个主题的一些变化应该会导致你使用 O(n) 运行时算法。

于 2012-06-13T21:05:33.833 回答
1

基本上先把所有的数字加起来。这将是一个 O(n) 操作。然后从数组的开头开始一次从数组中减去一个元素,直到upper== lower。因此,总订单将是 O(n)。

int BalancePoint(int a[], int begin, int end) // find index of an array (balance point) such that sum of all elements before the index = sum of all elements after it; else return -1
{
    if(!a) return -1;
    else if(begin == end) return begin;

        long long upper = 0;
        long long lower = 0;

    for(int i = begin; i <= end; ++i)
    {
        upper += *(a+i);
    }

    for(int j = begin; j <= end; ++j)
    {
        upper -= *(a+j);
        if(upper == lower) return j;
        lower += *(a+j);
    }
    return -1;
}

使用 STL

int BalancePointSTL( const vector<int> &A ) // find index of an array (balance point) such that sum of all elements before the index = sum of all elements after it; else return -1
{
    if(A.empty()) return -1;

        long long upper = 0;
        long long lower = 0;

    for(unsigned int i = 0; i <= A.size(); ++i)
    {
        upper += A[i];
    }

    for(unsigned int j = 0; j < A.size(); ++j)
    {
        upper -= A[j];
        if(upper == lower) return j;
        lower += A[j];
    }
    return -1;
    }

以下将具有更好的最坏情况性能,但还有更多if-else比较

int BalancePoint2(int a[], int begin, int end) // Better worst case senario by factor of 2
{
    if(!a) return -1;
    else if(begin == end) return begin;

        long long upper = 0;
        long long lower = 0;

        int mid = (end-begin)/2;

        for(int i = begin; i < mid; ++i)
        {
            lower += *(a+i);
        }
        for(int i = mid+1; i <= end; ++i)
        {
            upper += *(a+i);
        } 

        if(upper == lower) return mid;
        else if(lower < upper)
        {
            lower += *(a+mid);
            for(int i= mid + 1 ; i <= end ; ++i)
            {
                upper -= *(a + i);
                if(upper == lower) return i;
                lower += *(a + i);
            }
        }
        else {
            upper += *(a + mid);
            for(int i = mid - 1; i >=begin; --i)
            {
                lower -= *(a + i);
                if(upper == lower) return i;
                upper += *(a + i);
            }
        }
        return -1;
}
于 2012-06-13T21:15:36.793 回答
1

您正在寻找centroidcenter of mass。在纯 Python 中:

def centroid(input_list):
    idx_val_sum = 0.0
    val_sum = 0.0
    for idx,val in enumerate(input_list):
        idx_val_sum += idx*val
        val_sum += val
    return idx_val_sum/float(val_sum)

这是O(n),如果非整数结果格式不正确,您可以通过模检查拒绝它们:

def integer_centroid(input_list):
    idx_val_sum = 0.0
    val_sum = 0.0
    for idx,val in enumerate(input_list):
        idx_val_sum += idx*val
        val_sum += val
    out = idx_val_sum/float(val_sum)
    if out%1.0==0.0:
        return out
    else:
        raise ValueError("Input list has non-integer centorid.")

这篇文章应该是回复trumpetlicks June 14 2012 评论的评论,但我没有足够的声誉。“订单”在 中被隐式跟踪idx_val_sum,这是按值加权的累积位置总和。

编辑:

马特,谢谢你的观察。我以为这是一个伪代码问题,但现在我看到了 C++ 标签。这是一些(未经测试的)C++,带有注释。

一个直观的例子是一个简单的杠杆臂问题:如果你有一个杠杆,两个力f1f2作用在它的位置x1x2上,你可以通过在位置(f1*x1+f2* x2)/(f1+f2)连续系统需要对xf的乘积进行积分,但是具有离散位置和力的杠杆是这个问题的一个很好的类比。

// untested code:

float centroid(float * vec, int vec_length){

  float idx_val_sum = 0.0;
  float val_sum = 0.0;

  for (idx = 0; idx < vec_length; idx++){

    // keep a running sum of the product of the index and the value
    idx_val_sum += float(idx)*vec[idx];

    // similarly, keep a running sum of the index
    val_sum += vec[idx];

  }
  // return the quotient of the product-sum and the index sum:
  return idx_val_sum/val_sum;
}
于 2015-05-27T21:56:56.807 回答
0

一个 O(n) 且不需要更多空间的解决方案

def balance_array(arr):
    if len(arr) < 3:
        return False

    for i in range(1, len(arr)+1):
        lsum = sum(arr[:i])
        rsum = sum(arr[(i+1):])
        if lsum == rsum:
            return True
    return False

测试

test_arrays = [[5, 3, 7, 0, 9], [5,2,3,1,4,6], [1,0,1], [1,6,5,1,2,3,1], [1,1], [], [1], [1,2,9,4,-1], [5, 4, 7, 0, 9], [1, -1, 1, 0, 1, -1, 1]]

for i in test_arrays:
    print(f'{i}\t{balance_array(i)}')

[5, 3, 7, 0, 9]         False
[5, 2, 3, 1, 4, 6]      True
[1, 0, 1]               True
[1, 6, 5, 1, 2, 3, 1]   True
[1, 1]                  False
[]                      False
[1]                     False
[1, 2, 9, 4, -1]        True
[5, 4, 7, 0, 9]         True
[1, -1, 1, 0, 1, -1, 1] True
于 2020-08-09T22:39:30.210 回答
-1

我相信您正在寻找质量中心,这是用 Go 编写的解决方案:

func centerOfGravity(a []int) float64 {
  tot := 0.0
  mass := 0.0
  for i := range a {
    tot += float64(i) * float64(a[i])
    mass += float64(a[i])
  }
  return tot / mass
}

假设一个基于 0 的数组,这将为您提供数组中质心的索引。它可以返回非整数结果,因为质心可以在数组范围内的任何位置。

于 2012-06-14T00:19:50.963 回答