在刷力扣上 220. 存在重复元素 III 的题目遇到了一个问题,原题目如下:
最开始的思路是维护一个最大长度为 k 的滑动窗口,窗口元素放在有序集合中,然后二分查找有序集合中是否有满足条件的元素。代码如下(超时了):
class Solution {
public:
bool check(multiset<int> &st, long target, long t)
{
auto p = lower_bound(st.begin(), st.end(), target);
if (p != st.end() && abs((long)*p - target) <= t) return true;
if (p != st.begin() && abs((long)*prev(p, 1) - target) <= t) return true;
return false;
}
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
if (k == 0) return false;
multiset<int> st;
for (int i = 0; i < nums.size(); ++i) {
if (st.size() > 0 && check(st, nums[i], t)) return true;
st.emplace(nums[i]);
if (st.size() > k) st.erase(lower_bound(st.begin(), st.end(), nums[i - k]));
}
return false;
}
};
然后超时了,去查阅官方答案发现也是类似的思路,不过官方答案中的lower_bound和我的写法不太一样,如下图是官方答案:
然后我又改了一版自己的代码:
class Solution {
public:
bool check(set<int> &st, long target, long t)
{
// 这里要用set自带的 lower_bound,不能用algorithm 库中的lower_bound
// 因为set 自带的 lower_bound 和 upper_bound 的时间复杂度为 O(logn)。
// 但使用 algorithm 库中的 lower_bound 和 upper_bound 函数对 set 中的元素进行查询,时间复杂度为 0(n)。
auto p = st.lower_bound(target);
if (p != st.end() && abs((long)*p - target) <= t) return true;
if (p != st.begin() && abs((long)*prev(p, 1) - target) <= t) return true;
return false;
}
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
if (k == 0) return false;
set<int> st;
for (int i = 0; i < nums.size(); ++i) {
if (st.size() > 0 && check(st, nums[i], t)) return true;
st.emplace(nums[i]);
if (i >= k) st.erase(nums[i - k]);
}
return false;
}
};
结果就通过了,然后查阅资料发现
set 自带的 lower_bound 和 upper_bound 的时间复杂度为 O(logn)。
但使用 algorithm 库中的 lower_bound 和 upper_bound 函数对 set 中的元素进行查询,时间复杂度为 0(n)。
总结:对于可随机访问的有序容器使用 algorithm 库中的 lower_bound 和 upper_bound 函数时间复杂度为O(logn),
但对于set,multiset这种不能随机访问的有序容器,要用其自带的 lower_bound 和 upper_bound 的时间复杂度才为 O(logn)。
参考: