矢量自定义总和

时间:2018-06-30 11:02:36

标签: c++ arrays algorithm

我需要从具有以下属性的整数数组中标识变量的位置:

  • 此变量之前的元素之和等于此变量之后的元素之和

  • 如果该变量不存在,我将显示一条消息。

例如,如果为x = {1,2,4,2,1},则结果为4,位置为2,因为1 + 2 == 2 + 1。 有什么建议么?在此示例中,

很简单
if((x[0]+x[1])==(x[3]+x[4]))
print position 2

但是对于n变量?

6 个答案:

答案 0 :(得分:3)

有几种方法可以做到这一点:

蛮力-n / 2次通过:

  • 遍历数组。
  • 对于每个元素,计算该元素之前和之后的总和。
  • 如果它们匹配,则您找到了元素。
  • 如果之前的总和大于之后的总和,请停止处理-找不到匹配项。

这对于较大的阵列并不是很有效。

1.5次通过:

  • 计算所有元素的总和。
  • 将该总和除以2(half_sum)。
  • 从头开始再次汇总元素,直到达到half_sum
  • 检查是否找到有效的元素。

单次通过(仅正数):

  • 保留两个连续的总和:一个从开头(sum1)和一个从结尾(sum2)。
  • 设置sum1 = first elementsum2 = last element
  • 检查两者中的最小者,然后向其添加下一个/上一个元素。
  • 循环直到位置相遇,然后检查元素是否为有效结果。

对于每种方法,您都必须先进行一次小检查,以查看数组是否不太小。

要考虑的特殊情况:

  • 空数组:返回false
  • 具有1个元素的数组:返回元素
  • 具有2个非零元素的数组:返回false
  • 在全零或零组中间有什么? (请参见Deduplicator的评论)
  • 负面因素:单次通过版本在这里不起作用(请参见Cris Luengo的评论)
  • 一般而言,负面因素:不可靠,请考虑+3 +1 -1 +1 -1 -1 +3 +1(请参见Deduplicator的评论)

答案 1 :(得分:2)

这是 O(n)解决方案。

从数组开头(left_sum)开始对一个变量求和,并使用另一个(right_sum)继续从除第一个元素之外的元素之和推导出来。当两者相等时,中断循环并打印。否则,请显示您的消息。

#include <iostream>
#include <vector>
#include <numeric>
#include <cstddef>

int main()
{
    std::vector<int> vec {1,2,4,2,1};

    int left_sum = 0;
    int right_sum = std::accumulate(vec.cbegin()+1, vec.cend(), 0);

    bool Okay = false;
    std::size_t index = 1; // start from index 1 until n-1
    for( ; index < vec.size() - 1; ++index)
    {
        left_sum += vec[index-1];
        right_sum -= vec[index];
        if(left_sum == right_sum)
        {
            Okay = true;
            break;
        }
        // in the case of array of positive integers
        // if(left_sum > right_sum) break;
    }
    (Okay) ? std::cout << vec[index] << " " << index << std::endl: std::cout << "No such case!\n";
    return 0;
 }

答案 2 :(得分:1)

感谢您的回答。我终于做到了。我用了3个循环,而s0是元素前的和,而s1是元素后的和。

var response = client.CreateDocumentQuery<Container>
            (
                UriFactory.CreateDocumentCollectionUri(...),
                new FeedOptions { ... }
            )
            .SelectMany(c => c.Items
                .Select(i => new FlattenedContainer 
                { 
                    Id = c.Id, 
                    Name = i.Name, 
                    Amount = i.Amount 
                }))
            .AsDocumentQuery();

var results = new List<FlattenedContainer>();
while (response.HasMoreResults)
{
    results.AddRange(await response.ExecuteNextAsync<FlattenedContainer>());
}

答案 3 :(得分:1)

好吧,分两个步骤进行:

  1. 所有元素求和。
  2. 从头到尾:
    1. 如果总和等于当前元素,则成功!
    2. 从总和中减去两次(一次不再在右边,一次在左边)。

使用标准算法和范围,它很容易编写:

auto first_balanced(std::span<const int> x) noexcept {
    auto balance = std::accumulate(begin(x), end(x), 0LL);
    for (auto&& n : x) {
        if (balance == n)
            return &n;
        balance -= 2 * n;
    }
    return end(x);
}

答案 4 :(得分:0)

这只是循环。您需要对每个索引之前和之后的元素求和,然后比较这两个和:

#include <iostream>
#include <vector>
#include <numeric>

int main() {

    std::vector<int> x = {1, 2, 4, 2, 1};

    for ( unsigned idx = 0; idx < x.size(); ++idx )
        if ( std::accumulate(x.begin(), x.begin() + idx, 0) == std::accumulate(x.begin() + idx + 1, x.end(), 0) )
            std::cout << idx << std::endl;

    return 0;
}

答案 5 :(得分:0)

尝试使用std :: algorithm构建解决方案, n + lg n而不是n +〜n / 2

警告未经测试的代码。

bool HasHalfSum(int& atIndex, const std::vector<int>& v) {
  std::vector<int> sum;
  sum.reserve(v.size);

  std::partial_sum(v.begin(), v.end(), std::back_iterator(sum));
  // 1,3,7,9,10

  int half = sum.back() / 2; // 5

  auto found = std::lower_bound(sum.begin(), sum.end(), half);

  if (found != sum.begin() && std::prev(found) == sum.back() - *found) {
    index = std::distance(sum.begin(), found);
    return true;
  }

  return false;
}