解决用C++编写http服务器之后,telnet 127.0.0.1可以链接上,但是telnet 本机ip就会超时的问题
本人所用的系统是Ubuntu24.04,用的是阿里云服务器,经过排查之后,发现需要在服务器的防火墙处,添加一条规则。从而就可一解决问题。
题目一
解决代码以及思路:
(1)处理数组长度小于3的情况
如果数组长度小于3,直接返回数组中的最大值。
(2)去重
使用 std::set
对数组进行去重,因为 std::set
会自动去除重复值并按升序排列。
(3)判断去重后的元素个数
如果去重后不足3个,返回最大值。
(4)找到第三大的值
使用逆向迭代器 rbegin()
,然后通过 std::advance
移动到第三个最大值。
cpp
int thirdMax(std::vector<int> nums) {
// 如果数组长度小于3,返回最大值
if (nums.size() < 3) {
int max_val = nums[0];
for (int num : nums) {
if (num > max_val) {
max_val = num;
}
}
return max_val;
}
// 去重(使用 std::set 自动去重)
std::set<int> uniqueNums(nums.begin(), nums.end());
// 如果去重后不足3个,返回最大值
if (uniqueNums.size() < 3) {
return *std::max_element(uniqueNums.begin(), uniqueNums.end());
}
// 取去重后的第三个最大值
auto it = uniqueNums.rbegin(); // 逆向迭代器
std::advance(it, 2); // 移动到第三个最大值
return *it;
}
1. std::advance
std::advance
是一个标准库函数,用于将迭代器向前或向后移动指定的步数。它定义在 <iterator>
头文件中。
用法
cpp复制
cpp
#include <iterator>
template <class InputIt, class Distance>
void advance(InputIt& it, Distance n);
- InputIt:迭代器类型。
- Distance:要移动的步数,可以是正数(向前移动)或负数(向后移动)。
示例
cpp复制
cpp
#include <iostream>
#include <vector>
#include <iterator>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = vec.begin(); // 指向第一个元素
std::advance(it, 2); // 移动2步,指向第三个元素
std::cout << *it << std::endl; // 输出 3
std::advance(it, -1); // 向后移动1步,指向第二个元素
std::cout << *it << std::endl; // 输出 2
return 0;
}
2. std::set
std::set
是一个标准库中的关联容器,用于存储唯一的元素,并且会自动按照升序排列。它定义在 <set>
头文件中。
用法
cpp复制
cpp
#include <set>
std::set<int> mySet;
- 插入元素 :cpp复制
cpp
mySet.insert(10);
mySet.insert(5);
mySet.insert(20);
- 查找元素 :cpp复制
cpp
if (mySet.find(10) != mySet.end()) {
std::cout << "10 is in the set." << std::endl;
}
- 删除元素 :cpp复制
cpp
mySet.erase(5);
- 遍历元素 :cpp复制
cpp
for (const int& elem : mySet) {
std::cout << elem << " ";
}
示例
cpp复制
cpp
#include <iostream>
#include <set>
int main() {
std::set<int> mySet;
mySet.insert(10);
mySet.insert(5);
mySet.insert(20);
std::cout << "Elements in the set: ";
for (const int& elem : mySet) {
std::cout << elem << " ";
}
std::cout << std::endl;
if (mySet.find(10) != mySet.end()) {
std::cout << "10 is in the set." << std::endl;
}
mySet.erase(5);
std::cout << "After erasing 5, elements in the set: ";
for (const int& elem : mySet) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
3. std::max_element
std::max_element
是一个标准库函数,用于找到给定范围内的最大元素。它定义在 <algorithm>
头文件中。
用法
cpp复制
cpp
#include <algorithm>
template <class ForwardIt>
ForwardIt max_element(ForwardIt first, ForwardIt last);
- ForwardIt:迭代器类型。
- first:范围的开始。
- last:范围的结束。
示例
cpp复制
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto maxIt = std::max_element(vec.begin(), vec.end());
std::cout << "The maximum element is: " << *maxIt << std::endl; // 输出 5
return 0;
}
4. rbegin()
rbegin()
是一个成员函数,用于返回一个逆向迭代器,指向容器的最后一个元素。它定义在各种标准库容器中,如 std::vector
、std::set
等。
用法
cpp复制
cpp
std::vector<int> vec = {1, 2, 3, 4, 5};
auto rIt = vec.rbegin(); // 指向最后一个元素
- 逆向迭代器:从容器的末尾向前遍历。
示例
cpp复制
cpp
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto rIt = vec.rbegin(); // 指向最后一个元素
std::cout << "The last element is: " << *rIt << std::endl; // 输出 5
std::advance(rIt, 2); // 向前移动2步,指向第三个元素
std::cout << "The third element from the end is: " << *rIt << std::endl; // 输出 3
return 0;
}
总结
- std::advance:用于将迭代器向前或向后移动指定的步数。
- std::set:一个关联容器,用于存储唯一的元素,并且会自动按照升序排列。
- std::max_element:用于找到给定范围内的最大元素。
- rbegin():返回一个逆向迭代器,指向容器的最后一个元素。
题目二
代码以及思路
-
计算总和 :首先计算数组
nums
的总和totalSum
。 -
目标转换 :我们需要找到一个子数组,其和为
totalSum - x
。如果找到这样的子数组,那么剩余的部分(即移除的元素)的和就是x
。 -
滑动窗口 :使用滑动窗口技术找到和为
totalSum - x
的最长子数组。滑动窗口的长度越长,需要移除的元素就越少,操作数也就越小。 -
特殊情况 :如果
totalSum < x
,直接返回 -1。如果totalSum == x
,返回数组的长度。
cpp
int minOperations(std::vector<int>& nums, int x) {
int n = nums.size();
int totalSum = 0;
// 计算数组的总和
for (int num : nums) {
totalSum += num;
}
// 如果总和小于 x,直接返回 -1
if (totalSum < x) {
return -1;
}
// 如果总和等于 x,返回数组长度
if (totalSum == x) {
return n;
}
// 目标转换:找到和为 totalSum - x 的最长子数组
int target = totalSum - x;
int maxLen = -1;
int currentSum = 0;
int left = 0;
// 使用滑动窗口技术
for (int right = 0; right < n; ++right) {
currentSum += nums[right];
while (currentSum > target && left <= right) {
currentSum -= nums[left];
left++;
}
if (currentSum == target) {
maxLen = std::max(maxLen, right - left + 1);
}
}
// 如果没有找到满足条件的子数组,返回 -1
if (maxLen == -1) {
return -1;
}
// 返回最小操作数
return n - maxLen;
}
滑动窗口技术
基本概念
滑动窗口技术的核心思想是使用两个指针(通常称为 left
和 right
)来表示一个窗口的左右边界。窗口内的元素满足某种条件,通过移动这两个指针来调整窗口的大小和位置,从而找到满足条件的最优解。
滑动窗口的步骤
- 初始化:
-
- 初始化两个指针
left
和right
,通常都从数组的起始位置开始。 - 初始化一个变量
currentSum
(或类似变量)来记录当前窗口内的元素和。 - 初始化一个变量
maxLen
(或类似变量)来记录满足条件的最优解。
- 初始化两个指针
- 扩展窗口:
-
- 移动
right
指针,将nums[right]
加入当前窗口,更新currentSum
。 - 检查当前窗口是否满足条件。如果满足条件,更新最优解
maxLen
。
- 移动
- 收缩窗口:
-
- 如果当前窗口不满足条件,移动
left
指针,将nums[left]
从当前窗口中移除,更新currentSum
。 - 重复步骤 2 和 3,直到
right
指针遍历完整个数组。
- 如果当前窗口不满足条件,移动
- 返回结果:
-
- 根据
maxLen
计算最终结果。如果maxLen
仍然为初始值,表示没有找到满足条件的子数组,返回 -1 或其他适当的结果。
- 根据
示例
假设我们有一个数组 nums = [1, 2, 3, 4, 5]
,我们需要找到一个子数组,其和等于 target = 9
。
- 初始化:
-
left = 0
,right = 0
currentSum = 0
maxLen = -1
- 扩展窗口:
-
right = 0
,currentSum = 1
,不满足条件。right = 1
,currentSum = 3
,不满足条件。right = 2
,currentSum = 6
,不满足条件。right = 3
,currentSum = 10
,不满足条件。
- 收缩窗口:
-
left = 1
,currentSum = 9
,满足条件,更新maxLen = 4
。right = 4
,currentSum = 14
,不满足条件。left = 2
,currentSum = 12
,不满足条件。left = 3
,currentSum = 9
,满足条件,更新maxLen = 3
。
- 返回结果:
-
- 最长满足条件的子数组长度为 3,返回 3。
代码实现
cpp复制
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int minOperations(std::vector<int>& nums, int x) {
int n = nums.size();
int totalSum = 0;
// 计算数组的总和
for (int num : nums) {
totalSum += num;
}
// 如果总和小于 x,直接返回 -1
if (totalSum < x) {
return -1;
}
// 如果总和等于 x,返回数组长度
if (totalSum == x) {
return n;
}
// 目标转换:找到和为 totalSum - x 的最长子数组
int target = totalSum - x;
int maxLen = -1;
int currentSum = 0;
int left = 0;
// 使用滑动窗口技术
for (int right = 0; right < n; ++right) {
currentSum += nums[right];
while (currentSum > target && left <= right) {
currentSum -= nums[left];
left++;
}
if (currentSum == target) {
maxLen = std::max(maxLen, right - left + 1);
}
}
// 如果没有找到满足条件的子数组,返回 -1
if (maxLen == -1) {
return -1;
}
// 返回最小操作数
return n - maxLen;
}
int main() {
std::vector<int> nums = {3, 2, 20, 1, 1, 3};
int x = 10;
std::cout << "Minimum operations: " << minOperations(nums, x) << std::endl; // 输出:5
return 0;
}
总结
滑动窗口技术通过维护一个窗口来高效地解决问题,避免了不必要的重复计算。