【青训营刷题笔记】sstream 的优化字符串拼接+线性DP

62 阅读4分钟

【青训营刷题笔记】

使用 sstream 优化字符串拼接问题

虽然是个比较简单的问题 豆包AI还是给出了优化

(虽然有时候shasha的)

std::stringstream 是 C++ 标准库中的一个类模板,属于 <sstream> 头文件。它提供了一个字符串流,可以像操作文件一样对字符串进行输入和输出操作。

  • std::stringstream 维护一个内部缓冲区,用于存储流中的字符串数据。
  • 当进行字符串拼接操作时,std::stringstream 直接在内部缓冲区中进行,而不是每次都创建一个新的字符串对象。方式减少了内存频繁开辟的缺点
  • 使用 std::stringstream 进行字符串拼接时,可以像使用 std::cout 一样使用 << 操作符。
  • std::stringstream ss; ss << "Hello" << " " << "World";
  • 这种方式比使用 += 操作符进行字符串拼接更加高效

子数组和的最大值问题

问题描述

小U手上有一个整数数组,他想知道如果从数组中删除任意一个元素后,能得到的长度为 k 的子数组和的最大值。你能帮小U计算出这个结果吗? 如果数组恰好为 k 个元素,那么不进行删除操作。


测试样例

样例1:

输入:n = 5,k = 3,nums = [2, 1, 3, -1, 4] 输出:8

样例2:

输入:n = 6,k = 2,nums = [-1, -1, 5, -2, 3, 4] 输出:8

样例3:

输入:n = 4,k = 2,nums = [-5, -3, 2, 1] 输出:3

解析:

计算长度为 k 的子数组和:首先使用滑动窗口和 dp 数组来记录以每个位置 i 结尾的、长度为 k 的子数组和的最大值。

考虑删除一个元素的情况:通过在每个 k+1 长度的窗口内删除一个元素,计算删除后的长度为 k 的最大和。

输出最大和:将不删除和删除一个元素情况下的所有可能子数组和的最大值记录到 maxSum

int maxSubarraySumAfterDeletion(int n, int k, const vector<int>& nums) {
    if (n == k) {
        // 如果数组长度正好是 k,则直接返回整个数组的和
        return accumulate(nums.begin(), nums.end(), 0);/// in numeric
    }
​
    // dp[i] 表示以 i 结尾的长度为 k 的子数组和的最大值
    vector<int> dp(n, 0);
    int maxSum = 0;
​
    // 初始计算第一个长度为 k 的子数组和
    int windowSum = accumulate(nums.begin(), nums.begin() + k, 0);
    dp[k - 1] = windowSum;
    maxSum = windowSum;
​
    // 使用滑动窗口计算每个长度为 k 的子数组和
    for (int i = k; i < n; ++i) {
        windowSum = windowSum - nums[i - k] + nums[i];
        dp[i] = windowSum;
        maxSum = max(maxSum, dp[i]);
    }
​
    // 计算删除一个元素的情况下的最大子数组和
    for (int i = k; i < n; ++i) {
        // 计算当前窗口(长度为 k+1)的和
        int windowKPlus1 = dp[i] + nums[i - k];
        for (int j = i - k; j <= i; ++j) {
            int sumWithoutOne = windowKPlus1 - nums[j];
            maxSum = max(maxSum, sumWithoutOne);
        }
    }
​
    return maxSum;
}

股票市场交易策略优化

问题描述

小R近期表现出色,公司决定以股票的形式给予奖励,并允许他在市场上进行交易以最大化收益。给定一个数组,数组中的第 i 个元素代表第 i 天的股票价格。小R需要设计一个算法来实现最大利润。

股票交易规则如下:

  • 小R可以多次买卖股票,但在买入新的股票前必须卖出之前的股票。
  • 每次卖出股票后存在一天的冷冻期,在冷冻期内小R不能购买股票。

你的任务是帮助小R计算出在遵守交易规则的情况下能够获得的最大利润。

  • stocks: 一个整数列表,表示连续几天内的股票价格。

测试样例

样例1:

输入:stocks = [1, 2] 输出:1

样例2:

输入:stocks = [2, 1] 输出:0

样例3:

输入:stocks = [1, 2, 3, 0, 2] 输出:3

样例4:

输入:stocks = [2, 3, 4, 5, 6, 7] 输出:5

样例5:

输入:stocks = [1, 6, 2, 7, 13, 2, 8] 输出:12

思路:

设置三个状态

  • 持有股票的状态 : 当天持有股票的最大利润
  • 不持有股票的状态 : 当天不持有股票,且当天刚卖出股票
  • 不持有股票且不处于冷冻期的状态:当天不持有股票且不处于冷冻期

首先初始化为

dp[0][0] = -stocks[0]; // 第一天买

dp[0][1] = 0; // 第一天没有卖出

dp[0][2] = 0; // 第一天没有交易

代码:

#include <iostream>
#include <vector>
​
using namespace  std;
​
int solution(std::vector<int> stocks) {
   
​
   int n = stocks.size();
   int dp[1000][3];
   dp[0][0] = -stocks[0]; // 第一天买
   dp[0][1] = 0;          // 第一天没有卖出
   dp[0][2] = 0;          // 第一天没有交易
​
   for(int i = 1 ;i < n;i ++)
   {
    dp[i][0] = max(dp[i-1][0],dp[i-1][2] - stocks[i] ); // 昨天持有股票 / 今天买入
    dp[i][1] = dp[i-1][0] + stocks[i];                  // 当天 卖出 处于冷却
    dp[i][2] = max(dp[i-1][1],dp[i-1][2]);                                    //没有股票不再冷却器
   }
​
   return max(dp[n-1][1],dp[n-1][2]);   
   
}
​
int main() {
    // You can add more test cases here
    std::cout << (solution({1, 2}) == 1) << std::endl;
    std::cout << (solution({2, 1}) == 0) << std::endl;
    std::cout << (solution({1, 2, 3, 0, 2}) == 3) << std::endl;
    std::cout << (solution({2, 3, 4, 5, 6, 7}) == 5) << std::endl;
    std::cout << (solution({1, 6, 2, 7, 13, 2, 8}) == 12) << std::endl;
    return 0;
}