O(nlogS)中+ ve整数的连续子阵列的第K个最大和

时间:2016-01-27 08:59:19

标签: arrays algorithm binary-search

我正在阅读this社论,并对此声明感到困惑:

  

如果数组元素都是非负数,我们可以使用二进制搜索在O(n log S)时间内找到答案,其中S是子数组的最大总和。"

任何人都可以解释上述陈述。

3 个答案:

答案 0 :(得分:3)

假设我们有一个数组<a href="<?php echo site_url('student/update/'.$r->Id) ?>">Update Student</a> ,它在索引var pkgcloud = require('pkgcloud-bluemix-objectstorage'); var fs = require('fs'); // Create a config object var config = {}; // Specify Openstack as the provider config.provider = "openstack"; // Authentication url config.authUrl = 'https://identity.open.softlayer.com/'; config.region= 'dallas'; // Use the service catalog config.useServiceCatalog = true; // true for applications running inside Bluemix, otherwise false config.useInternal = false; // projectId as provided in your Service Credentials config.tenantId = '234567890-0987654'; // userId as provided in your Service Credentials config.userId = '098765434567890'; // username as provided in your Service Credentials config.username = 'admin_34567890-09876543'; // password as provided in your Service Credentials config.password = 'sdfghjklkjhgfds'; **//This is part which is NOT in original pkgcloud. This is how it works with newest version of bluemix and pkgcloud at 22.12.2015. //In reality, anything you put in this config.auth will be send in body to server, so if you need change anything to make it work, you can. PS : Yes, these are the same credentials as you put to config before. //I do not fill this automatically to make it transparent. config.auth = { forceUri : "https://identity.open.softlayer.com/v3/auth/tokens", //force uri to v3, usually you take the baseurl for authentication and add this to it /v3/auth/tokens (at least in bluemix) interfaceName : "public", //use public for apps outside bluemix and internal for apps inside bluemix. There is also admin interface, I personally do not know, what it is for. "identity": { "methods": [ "password" ], "password": { "user": { "id": "098765434567890", //userId "password": "sdfghjklkjhgfds" //userPassword } } }, "scope": { "project": { "id": "234567890-0987654" //projectId } } };** //console.log("config: " + JSON.stringify(config)); // Create a pkgcloud storage client var storageClient = pkgcloud.storage.createClient(config); // Authenticate to OpenStack storageClient.auth(function (error) { if (error) { console.error("storageClient.auth() : error creating storage client: ", error); } else { //OK var new_fname = dir + "__" + file.originalname; var readStream = fs.createReadStream('uploads/' + file.filename); var writeStream = storageClient.upload({ container: 'chat-files', remote: new_fname }); writeStream.on('error', function(err) { // handle your error case console.log("concluido o upload com erro!"); console.log(err); }); writeStream.on('success', function(file) { // success, file will be a File model console.log("concluido o upload com sucesso!"); }); readStream.pipe(writeStream); } });存储从0到sum的所有元素的总和,因此,如果所有元素都是非负数,那么< / p>

ith

我们注意到,数组ith的子数组 sum[0] <= sum[1] <= sum[2] ... <= sum[i] ... <= sum[n - 1] 之和为(i, j)

所以,给定一个数字X,我们可以很容易地从A的子数组的总和中计算出这个数字的等级,如下所示:

A

最后,要查找哪个数字是sum[j] - sum[i - 1]数字,我们可以在范围int rank = 0; for(int i = 0; i < n; i++){ int index = minimum index which sum[i] - sum[index] >= X; //As sum[0] <= sum[1] <=... , we can use binary search to find index rank += index; } 中使用二分搜索,并使用上述算法计算排名,其中S是子数组的最大总和。

Kth

因此,时间复杂度为O(nlogS log n)。

答案 1 :(得分:0)

我认为可以在O(Klogn)中完成。 sum[i]被定义为给定数组的前缀和,直到索引i。它有时可能比以前的解决方案更快。

  1. 构建包含索引Q对的最大队列(i, j)。订单为(a, b) < (c, d) iff sum[b] - sum[a - 1] < sum[d] - sum[d - 1] else if b - a < d - c else if b < d
  2. 将以下对插入Q(0, 0), (0, 1) ... (0, N - 1)
  3. 迭代K - 1次,并在每次迭代中弹出e = (i, j)的顶部元素Q,如果i < j,则插入(i + 1, j)
  4. 您的元素位于队列的顶部。

答案 2 :(得分:0)

现有答案均不正确,因此这是正确的方法。

首先,如@PhamTrung所指出的,我们可以在O(n)中生成数组的累加和,然后减去两个累加和,便可以计算O(1)中任何连续子数组的累加和。到那时,我们的答案就限制在0和所有事物的总和S之间。

接下来,我们知道有多少个连续的子数组。只需选择端点,就有n*(n-1)/2)这样的对。

问题的核心是,给定X,我们需要在O(n)中计算小于m的对数。为此,我们使用一对ij指针。我们并行运行它们,使总和从ij低于X,但在这种情况下应将它们保持尽可能远的距离。然后,我们继续添加它们之间有多少对也将位于X以下。伪代码如下所示:

count_below = 0
i = 0
j = -1
while i < n:
    while j+1 < n or sum(from i to j+1) < X:
        count_below += 1 # Add the (i, j+1) interval
        j += 1
    if j+1 == n:
        count_below += (n-i-1) * (n-i-2) / 2 # Add all pairs with larger i
        i = n
    else:
        while X <= sum(from i+1 to j+1):
            i += 1
            count_below += j - i # Add a block of (i, ?) pairs

我不能发誓我正确地建立了索引,但这就是想法。棘手的一点是,每次前进j时,我们只会添加一个,但每次前进i时,我们会将每个(i, mid)包含在i < mid <= j中。

现在我们对值进行二进制搜索。

lower = 0
upper = S
while lower < upper:
   mid = floor((upper + lower)/2)
   if count below mid < count_intervals - k:
       lower = mid+1
   else:
       upper = mid

假定和为整数,则将在O(log(S))搜索中找到正确的答案。每个都是O(n)。总时间为O(n log(S))

请注意,如果我们对二进制搜索比较聪明,并且同时跟踪计数和最接近的两个和,可以通过将O(n log(min(n, S)))减至最大和{ {1}},并将upper提升到下一个更高的金额。删除<= mid,该方法也将适用于浮点数,以在lower中产生答案。 (随着floor实际上是无限的。)