2025-01-20 学习日记

解决用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::vectorstd::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():返回一个逆向迭代器,指向容器的最后一个元素。

题目二

代码以及思路

  1. 计算总和 :首先计算数组 nums 的总和 totalSum

  2. 目标转换 :我们需要找到一个子数组,其和为 totalSum - x。如果找到这样的子数组,那么剩余的部分(即移除的元素)的和就是 x

  3. 滑动窗口 :使用滑动窗口技术找到和为 totalSum - x 的最长子数组。滑动窗口的长度越长,需要移除的元素就越少,操作数也就越小。

  4. 特殊情况 :如果 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;
}

滑动窗口技术

基本概念

滑动窗口技术的核心思想是使用两个指针(通常称为 leftright)来表示一个窗口的左右边界。窗口内的元素满足某种条件,通过移动这两个指针来调整窗口的大小和位置,从而找到满足条件的最优解。

滑动窗口的步骤
  1. 初始化
    • 初始化两个指针 leftright,通常都从数组的起始位置开始。
    • 初始化一个变量 currentSum(或类似变量)来记录当前窗口内的元素和。
    • 初始化一个变量 maxLen(或类似变量)来记录满足条件的最优解。
  1. 扩展窗口
    • 移动 right 指针,将 nums[right] 加入当前窗口,更新 currentSum
    • 检查当前窗口是否满足条件。如果满足条件,更新最优解 maxLen
  1. 收缩窗口
    • 如果当前窗口不满足条件,移动 left 指针,将 nums[left] 从当前窗口中移除,更新 currentSum
    • 重复步骤 2 和 3,直到 right 指针遍历完整个数组。
  1. 返回结果
    • 根据 maxLen 计算最终结果。如果 maxLen 仍然为初始值,表示没有找到满足条件的子数组,返回 -1 或其他适当的结果。
示例

假设我们有一个数组 nums = [1, 2, 3, 4, 5],我们需要找到一个子数组,其和等于 target = 9

  1. 初始化
    • left = 0, right = 0
    • currentSum = 0
    • maxLen = -1
  1. 扩展窗口
    • right = 0currentSum = 1,不满足条件。
    • right = 1currentSum = 3,不满足条件。
    • right = 2currentSum = 6,不满足条件。
    • right = 3currentSum = 10,不满足条件。
  1. 收缩窗口
    • left = 1currentSum = 9,满足条件,更新 maxLen = 4
    • right = 4currentSum = 14,不满足条件。
    • left = 2currentSum = 12,不满足条件。
    • left = 3currentSum = 9,满足条件,更新 maxLen = 3
  1. 返回结果
    • 最长满足条件的子数组长度为 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;
}
总结

滑动窗口技术通过维护一个窗口来高效地解决问题,避免了不必要的重复计算。

相关推荐
我真不会起名字啊7 分钟前
“深入浅出”系列之C++:(11)推荐一些C++的开源项目
c++·开源
pursuit_csdn9 分钟前
LeetCode 2661. First Completely Painted Row or Column
算法·leetcode
csdn_aspnet27 分钟前
c++ 给定欧氏平面中的一组线可以形成的三角形的数量
c++·算法·平面
csdn_aspnet29 分钟前
C# 给定欧氏平面中的一组线可以形成的三角形的数量
算法·平面·c#
Petrichorzncu1 小时前
算法刷题笔记——图论篇
笔记·算法·图论
半夏知半秋1 小时前
rust学习-函数的定义与使用
服务器·开发语言·后端·学习·rust
LuckyLay1 小时前
Golang学习笔记_28——工厂方法模式(实例)
笔记·学习·golang·工厂方法模式
小殷要努力刷题!1 小时前
每日一刷——1.20——准备蓝桥杯
java·学习·算法·蓝桥杯·刷题·牛客·语法学习
好好学习++1 小时前
【HF设计模式】06-命令模式
java·c++·设计模式·命令模式
zchao94561 小时前
从零开始解决ubuntu2204,pcl-1.8 编译中报错的问题,cmake-gui编译
学习