这是核心排序相关的问题。要找到最小 k 个非相邻元素的总和,需要通过排序将最小值元素彼此相邻。让我们看看这种排序方法,
给定输入数组 = [9, 4, 0, 9, 14, 7, 1] 和 k = 3
创建另一个数组,其中包含输入数组的元素,其索引如下所示,
[9, 0], [4, 1], [0, 2], [9, 3], [14, 4], [7, 5], [@ 987654329@, 6]
然后对该数组进行排序。
这个元素和索引数组背后的动机是,排序后每个元素的索引信息不会丢失。
还需要一个数组来记录使用过的索引,所以排序后的初始信息如下图,
Element and Index array
..............................
| 0 | 1 | 4 | 7 | 9 | 9 | 14 |
..............................
2 6 1 5 3 0 4 <-- Index
Used index record array
..............................
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
..............................
0 1 2 3 4 5 6 <-- Index
在已使用的索引记录数组中0 (false) 表示此索引处的元素尚未包含在最小总和中。
排序数组的前元素是最小值元素,我们将其包含在最小和中,并更新使用的索引记录数组以指示使用该元素,如下所示,
字体元素是索引2 处的0 并且由于使用的索引记录数组的索引2 处设置了1(true),如下所示,
min sum = 0
Used index record array
..............................
| 0 | 0 | 1 | 0 | 0 | 0 | 0 |
..............................
0 1 2 3 4 5 6
迭代到排序数组中的下一个元素,如上所示,它是1,索引为6。要在最小总和中包含1,我们必须找到,1 的左侧或右侧相邻元素是否已使用,因此1 具有索引6,它是输入数组中的最后一个元素,这意味着我们只有检查索引5 的值是否已被使用,这可以通过查看已使用的索引记录数组来完成,如上所示usedIndexRerocd[5] = 0 所以1 可以考虑为最小总和。使用1后,状态更新为关注,
min sum = 0 + 1
Used index record array
..............................
| 0 | 0 | 1 | 0 | 0 | 0 | 1 |
..............................
0 1 2 3 4 5 6
而不是迭代到索引1 处的下一个元素4 但这不能考虑,因为索引0 处的元素已被使用,元素7, 9 也会发生同样的情况,因为这些位于索引5, 3分别与使用的元素相邻。
最后在 index = 0 处迭代到 9 并通过查看使用的索引记录数组 usedIndexRecordArray[1] = 0 这就是为什么 9 可以包含在最小总和中并达到以下最终状态,
min sum = 0 + 1 + 9
Used index record array
..............................
| 1 | 0 | 1 | 0 | 0 | 0 | 1 |
..............................
0 1 2 3 4 5 6
终于minimum sum = 10,
最坏情况场景之一,输入数组已经排序,然后至少必须迭代 2*k - 1 元素以找到非相邻 k 元素的最小总和,如下所示
输入数组 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 和 k = 4
然后应考虑以下突出显示的元素以获得最小总和,
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
注意:您必须包括所有输入验证,就像验证之一是,如果你想找到k 非相邻元素的最小总和,那么输入应该至少有2*k - 1 元素。我不包括这些验证,因为我知道问题的所有输入约束。
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
long minSumOfNonAdjacentKEntries(std::size_t k, const std::vector<int>& arr){
if(arr.size() < 2){
return 0;
}
std::vector<std::pair<int, std::size_t>> numIndexArr;
numIndexArr.reserve(arr.size());
for(std::size_t i = 0, arrSize = arr.size(); i < arrSize; ++i){
numIndexArr.emplace_back(arr[i], i);
}
std::sort(numIndexArr.begin(), numIndexArr.end(), [](const std::pair<int, std::size_t>& a,
const std::pair<int, std::size_t>& b){return a.first < b.first;});
long minSum = numIndexArr.front().first;
std::size_t elementCount = 1;
std::size_t lastIndex = arr.size() - 1;
std::vector<bool> usedIndexRecord(arr.size(), false);
usedIndexRecord[numIndexArr.front().second] = true;
for(std::vector<std::pair<int, std::size_t>>::const_iterator it = numIndexArr.cbegin() + 1,
endIt = numIndexArr.cend(); elementCount < k && endIt != it; ++it){
bool leftAdjacentElementUsed = (0 == it->second) ? false : usedIndexRecord[it->second - 1];
bool rightAdjacentElementUsed = (lastIndex == it->second) ? false : usedIndexRecord[it->second + 1];
if(!leftAdjacentElementUsed && !rightAdjacentElementUsed){
minSum += it->first;
++elementCount;
usedIndexRecord[it->second] = true;
}
}
return minSum;
}
int main(){
cout<< "k = 2, [355, 46, 203, 140, 28], min sum = "<< minSumOfNonAdjacentKEntries(2, {355, 46, 203, 140, 28})
<< '\n';
cout<< "k = 3, [9, 4, 0, 9, 14, 7, 1], min sum = "<< minSumOfNonAdjacentKEntries(3, {9, 4, 0, 9, 14, 7, 1})
<< '\n';
}
输出:
k = 2, [355, 46, 203, 140, 28], min sum = 74
k = 3, [9, 4, 0, 9, 14, 7, 1], min sum = 10