当前位置: 首页 > news >正文

89.迷人子序列计数问题|Marscode AI刷题

1.题目

问题描述

当一个数列,最大值和最小值的差低于某一阈值时,称这个数列是迷人数列。

现给定一个由 n 个整数构成的数列和阈值 k,问存在多少个连续子序列是迷人的。

输入格式

第一行包含 2 个数字 n, k (1 <= n <= 1000000 < k <= 10^9)

第二行包含 n 个整数:a[1], a[2],..., a[n] (0 <= a[i] <= 10^9)

输出格式

输出迷人连续子序列的数目

输入样例

4 2

3 1 2 4

输出样例

5

数据范围

共 10 组数据。2 组数据 n 小于 1000;其余数据 n 等于 100000。

2.样例解析

输入样例

4 2

3 1 2 4

输出样例

5

当一个数列,最大值和最小值的差小于等于某一阈值时,称这个数列是迷人数列,此处的输出应该是8。

8个迷人子序列为:{3},{1},{2},{4},{3,1}{1,2},{2,4},{3,1,2}

3.思路

由于我们需要找到的是满足 max(a[i...j]) - min(a[i...j]) < k 的所有连续子序列,可以考虑使用 滑动窗口(即双指针法)来解决。

  1. 我们使用两个指针 leftright,维护一个当前的子序列 a[left...right],并逐步扩展右指针。
  2. max(a[left...right]) - min(a[left...right]) 满足条件时,我们可以将子序列的左指针 left 继续向右移动,直到不满足条件为止。
  3. 统计符合条件的连续子序列的数量。

4.代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int solution(int n, int k, std::vector<int> sequence) {
    // Please write your code here
    int left = 0;
    int right = 0;
    int result = 0;
    int min_val = sequence[0];
    int max_val = sequence[0];
    while (left < n && right < n && left <= right) {
        // 更新当前窗口的最大值和最小值(右移之后)
        min_val = min(min_val, sequence[right]);
        max_val = max(max_val, sequence[right]);
        if ((max_val - min_val) < k) { // 符合条件,右指针右移
            result++;
            right++;
        }else { //不符合条件,左指针右移
            left++;
            //更新当前窗口的最大值和最小值
            min_val = *min_element(sequence.begin() + left, sequence.begin() + right + 1);
            max_val = *max_element(sequence.begin() + left, sequence.begin() + right + 1);
        }
    } 
    return result;
}

int main() {

    // You can add more test cases here
    std::vector<int> sequence1 = {3, 1, 2, 4};
    std::vector<int> sequence2 = {7, 3, 5, 1, 9};
    std::vector<int> sequence3 =  {2, 2, 3, 1, 1, 2};

    std::cout << (solution(4, 2, sequence1) == 8) << std::endl;
    std::cout << (solution(5, 3, sequence2) == 6) << std::endl;
    std::cout << (solution(6, 1, sequence3) == 12) << std::endl;

    return 0;
}

代码修改:

  • result++改为result += (right - left + 1)
  • (max_val - min_val)< k改为(max_val - min_val) ≤ k
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int solution(int n, int k, std::vector<int> sequence) {
    // Please write your code here
    int left = 0;
    int right = 0;
    int result = 0;
    int min_val = sequence[0];
    int max_val = sequence[0];
    while (left < n && right < n && left <= right) {
        // 更新当前窗口的最大值和最小值(右移之后)
        min_val = min(min_val, sequence[right]);
        max_val = max(max_val, sequence[right]);
        if ((max_val - min_val) <= k) { // 符合条件,右指针右移
            result += (right - left + 1);
            right++;
        }else { //不符合条件,左指针右移
            left++;
            //更新当前窗口的最大值和最小值
            min_val = *min_element(sequence.begin() + left, sequence.begin() + right + 1);
            max_val = *max_element(sequence.begin() + left, sequence.begin() + right + 1);
        }
    } 
    return result;
}

int main() {

    // You can add more test cases here
    std::vector<int> sequence1 = {3, 1, 2, 4};
    std::vector<int> sequence2 = {7, 3, 5, 1, 9};
    std::vector<int> sequence3 =  {2, 2, 3, 1, 1, 2};

    std::cout << (solution(4, 2, sequence1) == 8) << std::endl;
    std::cout << (solution(5, 3, sequence2) == 6) << std::endl;
    std::cout << (solution(6, 1, sequence3) == 12) << std::endl;

    return 0;
}

代码详解:

result += (right - left + 1)

对于每个 right,如果窗口 [left, right] 的最大值和最小值之差小于等于 k,则此窗口中的所有子序列都符合条件。

具体的子序列数量:

  • 对于每个固定的 right,所有以 leftright 为子序列的组合都满足条件。

  • 这些子序列的个数就是窗口内的所有可能的子序列数,即从 leftright 形成的连续子序列。

  • 例如,如果窗口是 [left, right],那么所有可能的子序列是:

    • sequence[left]
    • sequence[left+1]
    • sequence[left+2]
    • ...
    • sequence[right]

    这些子序列的数量就是 (right - left + 1)。因此,每次窗口扩展时,我们就可以通过 result += (right - left + 1) 来累加符合条件的子序列数量。

min_val = *std::min_element(sequence.begin() + left, sequence.begin() + right + 1);
max_val = *std::max_element(sequence.begin() + left, sequence.begin() + right + 1);
  1. std::min_element:
    • 这个函数返回指定范围内的最小元素的迭代器。
    • 语法:std::min_element(first, last)
      • first:指向范围的起始位置的迭代器。
      • last:指向范围的结束位置的迭代器(不包括该位置)。
    • 返回值:指向范围内最小元素的迭代器。
  2. std::max_element:
    • 这个函数返回指定范围内的最大元素的迭代器。
    • 语法:std::max_element(first, last)
      • first:指向范围的起始位置的迭代器。
      • last:指向范围的结束位置的迭代器(不包括该位置)。
    • 返回值:指向范围内最大元素的迭代器。
  3. std::min_element 和 std::max_element 是 C++ 标准库中的函数,用于在给定的范围内找到最小值和最大值的迭代器。为了获取这些迭代器指向的实际值,你需要对它们进行解引用操作,即使用 * 运算符。

相关文章:

  • vue2中,打包报错ERROR in /node_modlules/@types/lodash/common/common.d.ts 26
  • python全栈-并发和网络通信
  • GO 快速升级Go版本
  • 【Qt之QQuickWidget】QML嵌入QWidget中
  • c++day4
  • 【嵌入式Linux应用开发基础】网络编程(1):TCP/IP协议栈
  • WIN10 本地部署 BGE Embedding 向量化模型
  • unxi-进程间通信
  • 使用PHP接入纯真IP库:实现IP地址地理位置查询
  • akka现有的分布式定时任务框架总结
  • 条件渲染
  • .Net 9下使用Tensorflow.net---DNN_Keras
  • AI时代前端开发技能变革与ScriptEcho:拥抱AI,提升效率
  • MongoDB 复制(副本集)
  • Uncaught TypeError: Module._malloc is not a function
  • 【学习笔记16】Java中常见的Exception(异常)
  • ROS2 同一个pkg里定义自定义action、msg报错
  • 爬虫解析库:Beautiful Soup的详细使用
  • 怎样把外网的文件放到内网?
  • Python3 运算符
  • 魔都眼|84岁美琪大戏院焕新回归:《SIX》开启中国首演
  • 始祖鸟母公司一季度净利大增超25倍:中国营收增超四成,从容应对关税影响
  • 在上海国际科创中心建设中发挥重要战略科技力量作用!陈吉宁调研上海科技大学
  • 夜读丨在雨中撒欢儿
  • 云南陆良一装载机因制动失效致6死,操作者被采取刑事强制措施
  • “抵沪第一杯咖啡”送进虹桥机场到达层,刚下飞机就能免费喝