原因
报错的原因是因为std::lower_bound()函数返回的是一个迭代器,而不是一个整数索引。
迭代器本身并不能直接用于索引,所以不能将其作为向量的索引直接使用。
如果想用返回的迭代器得到对应的索引,我们需要对返回的迭代器进行处理。
正确的处理方式是先将迭代器保存起来,然后进行使用和操作。
编译出错的代码:
class Solution {
public:
long long minCost(vector<int>& nums, int x) {
int n = nums.size();
vector<int> prefixSum(2 * n + 1);
for (int i = 0; i < 2 * n; ++i) {
prefixSum[i + 1] = prefixSum[i] + nums[i % n];
}
int totalCost = prefixSum[n], minCost = INT_MAX;
for (int i = 2 * n; i >= n; --i) {
//这里lower_bound返回值处理不当
while (prefixSum[i] - prefixSum[lower_bound(prefixSum.begin(), prefixSum.begin() + i, prefixSum[i] - totalCost)] < totalCost) {
--lower_bound(prefixSum.begin(), prefixSum.begin() + i, prefixSum[i] - totalCost);
}
minCost = min(minCost, (long long)totalCost + x * (i - lower_bound(prefixSum.begin(), prefixSum.begin() + i, prefixSum[i] - totalCost)));
}
return minCost;
}
};
也就是说,我们需要把迭代器的部分转化为整数。迭代器出错的部分:
for (int i = 2 * n; i >= n; --i) {
//这里需要使用auto变量来接收low_bound的返回值
while (prefixSum[i] - prefixSum[lower_bound(prefixSum.begin(), prefixSum.begin() + i, prefixSum[i] - totalCost)] < totalCost) {
--lower_bound(prefixSum.begin(), prefixSum.begin() + i, prefixSum[i] - totalCost);
}
同时,报错代码尝试在while循环中进行了迭代器的自减操作,这是不可行的,因为std::lower_bound()返回的是一个临时迭代器,它不能被自减。
应修改为:
//这个循环内所有用到low_bound返回值的地方,都修改为
for (int i = 2 * n; i >= n; --i) {
//先保存迭代器
auto it = lower_bound(prefixSum.begin(), prefixSum.begin() + i, prefixSum[i] - totalCost);
//再进行保存后的auto it的自减
while (prefixSum[i] - prefixSum[it - prefixSum.begin()] < totalCost) {
--it;
}
minCost = min(minCost, totalCost + x * (long long)(i - (it - prefixSum.begin())));
}
这段代码首先找到一个满足条件的迭代器it,然后在while循环中检查是否需要将这个迭代器前移。如果需要,就将迭代器前移,然后在外部循环中更新最小成本。
注意:迭代器转化为整数(对应元素vector下标)的方法
- it - nums.begin() 能够将迭代器it转化为对应于vector数组nums的整数索引。
将迭代器转化为整数的方法:先auto it接收返回迭代器的函数,然后使用it - nums.begin()的操作,将迭代器转化为vector数组的下标。
auto it = lower_bound(num.begin(),nums.begin()+i,nums[i]-totalCost);
int num = nums[it-nums.begin()]; //将it返回的值下标存入num中
std::lower_bound函数返回的是指向找到对应元素的迭代器,你可以通过将这个迭代器与std::vector的begin()迭代器做减法,就能得到对应元素在vector中的下标。在上面的示例中,it - nums.begin()的结果就是找到的元素在nums这个vector中的下标。
这种将迭代器转换为对应元素的下标的做法非常常见,因为迭代器的主要作用就是用于在容器(如std::vector)中遍历和访问元素,很多时候我们不仅需要访问到元素本身,也需要知道它在容器中的位置(即下标)。
迭代器的整数转换原理
因为迭代器支持一些算术运算,比如递增、递减和两个迭代器之间的距离计算(即相减)。当我们使用it - nums.begin()时,实际上计算的是迭代器it指向的元素与nums.begin()指向的元素之间的距离,这个距离就等于元素在vector中的索引。
因此,如果你想从std::vector的迭代器中获取元素的下标,你可以让迭代器与nums.begin() 相减,这样就能得到一个整数,表示元素在vector中的位置。
修改后的代码:
class Solution {
public:
long long minCost(vector<int>& nums, int x) {
int n = nums.size();
vector<int> prefixSum(2 * n + 1);
for (int i = 0; i < 2 * n; ++i) {
prefixSum[i + 1] = prefixSum[i] + nums[i % n];
}
long long totalCost = prefixSum[n], minCost = LLONG_MAX;
for (int i = 2 * n; i >= n; --i) {
//先保存迭代器
auto it = lower_bound(prefixSum.begin(), prefixSum.begin() + i, prefixSum[i] - totalCost);
//再进行保存后的auto it的自减
while (prefixSum[i] - prefixSum[it - prefixSum.begin()] < totalCost) {
--it;
}
minCost = min(minCost, totalCost + x * (long long)(i - (it - prefixSum.begin())));
}
return minCost;
}
};
lower_bound函数
这段代码是处理周赛题目:6449.收集巧克力 的代码,这个代码逻辑是有问题的,最后这种解法也没有成功。还是推荐用另一篇博客整理的解法。
这种解法使用了C++的lower_bound函数,这个函数可以在一个有序的序列中找到大于或等于某个值的第一个位置。因此,这个解法的时间复杂度是O(n log n),其中n是巧克力的数量。