首页 > 其他分享 >构建前缀信息解决子数组问题

构建前缀信息解决子数组问题

时间:2024-09-30 22:01:24浏览次数:12  
标签:map 前缀 nums int res prefixSum 构建 数组 include

构建前缀信息解决子数组问题

303. 区域和检索 - 数组不可变

#include <vector>

using namespace std;

class NumArray {
public:
    // 前缀和数组
    vector<int> prefixSum;

    NumArray(vector<int> &nums) {
        prefixSum.resize(nums.size() + 1);
        prefixSum[0] = 0;
        for (int i = 0; i < nums.size(); ++i)
            prefixSum[i + 1] = prefixSum[i] + nums[i];
    }

    int sumRange(int left, int right) {
        return prefixSum[right + 1] - prefixSum[left];
    }
};

未排序数组中累加和为给定值的最长子数组长度

#include <vector>
#include <iostream>
#include <unordered_map>

using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> nums(n);
    for (int i = 0; i < n; ++i)
        cin >> nums[i];

    // 记录前缀和最早出现的位置,这样才能使子数组更大
    unordered_map<int, int> map;
    // 前缀和 0 首次出现在下标 -1 的位置
    map.emplace(0, -1);
    int prefixSum = 0;
    int res = 0;

    for (int i = 0; i < n; ++i) {
        prefixSum += nums[i];
        // 只记录第一次出现的位置
        if (map.find(prefixSum) == map.end())
            map[prefixSum] = i;
        // 之前的某个位置到当前位置构成的子数组,和为 k
        if (map.find(prefixSum - k) != map.end())
            res = max(res, i - map[prefixSum - k]);
    }
    cout << res;
}

560. 和为 K 的子数组

#include <vector>
#include <iostream>
#include <unordered_map>

using namespace std;

class Solution {
public:
    int subarraySum(vector<int> &nums, int k) {
        // 记录前缀和出现的次数
        unordered_map<int, int> map;
        map.emplace(0, 1);
        int res = 0;
        int prefixSum = 0;
        for (int i = 0; i < nums.size(); ++i) {
            prefixSum += nums[i];
            // 和为 k 的子数组个数
            if (map.find(prefixSum - k) != map.end())
                res += map[prefixSum - k];
            map[prefixSum]++;
        }
        return res;
    }
};

未排序数组中累加和为给定值的最长子数组系列问题补1

#include <vector>
#include <iostream>
#include <unordered_map>

using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> nums(n);
    for (int i = 0; i < n; ++i)
        cin >> nums[i];

    // 记录正数负数个数的差值的最早出现位置
    unordered_map<int, int> map;
    map.emplace(0, -1);
    // 正数负数个数的差值
    int prefix = 0;
    int res = 0;
    for (int i = 0; i < n; ++i) {
        if (nums[i] > 0) prefix++;
        if (nums[i] < 0) prefix--;
        // 之前出现过,说明那个位置到当前位置的累加和为 0
        if (map.find(prefix) != map.end())
            res = max(res, i - map[prefix]);
        // 记录最早出现位置
        if (map.find(prefix) == map.end())
            map.emplace(prefix, i);
    }
    cout << res;
}

1124. 表现良好的最长时间段

#include <vector>
#include <iostream>
#include <unordered_map>

using namespace std;

class Solution {
public:
    int longestWPI(vector<int> &hours) {
        // 某个前缀和,最早出现的位置
        unordered_map<int, int> map;
        map.emplace(0, -1);
        // 记录前缀中大于 8h 的天数和小于等于 8h 的天数之差
        int prefix = 0;
        int res = 0;

        for (int i = 0; i < hours.size(); i++) {
            prefix += hours[i] > 8 ? 1 : -1;
            if (prefix > 0) {
                // 说明从数组开头到当前位置就是表现良好的时间段
                res = i + 1;
            } else {
                // 若当前 prefix 为 -3,则找 -4 是否已经出现,若出现,则说明 -4 出现的位置到当前位置的子数组是符合条件的(大于8h的天数严格大于一半)
                // 若之前还有 -5、-6 啥的,其之前一定出现过 -4,因为是从 0 开始加一减一的,先出现 -4 才可能出现 -5、-6
                if (map.find(prefix - 1) != map.end())
                    res = max(res, i - map[prefix - 1]);
            }
            // 只记录第一次出现的位置
            if (map.find(prefix) == map.end())
                map.emplace(prefix, i);
        }
        return res;
    }
};

1590. 使数组和能被 P 整除

#include <vector>
#include <iostream>
#include <unordered_map>

using namespace std;

class Solution {
public:
    int minSubarray(vector<int> &nums, int p) {
        // 总体和模 p 的余数,也是需要删除的部分的累加和模 p 的余数
        int remove = 0;
        for (int num: nums) remove = (remove + num) % p;
        // 不需要移除子数组
        if (remove == 0) return 0;

        int res = INT_MAX;
        // 记录累加和
        int prefixSum = 0;
        // key 为模 p 的余数,value 为该值最后一次出现的位置
        unordered_map<int, int> map;
        map.emplace(0, -1);
        for (int i = 0; i < nums.size(); i++) {
            prefixSum = (prefixSum + nums[i]) % p;
            // 当前位置的前缀和模 p 的值为 prefixSum,整体数组累加和模 p 的值为 remove
            // 需要删除子数组的累加和模 p 的值为 remove,这样删除元素后的整体数组模 p 的值才能为 0,才能被 p 整除
            // 所以要往前寻找累加和模 p 的值为 find 最后一次出现的位置,才能使删除的数组长度最小
            int find = (prefixSum - remove + p) % p;
            if (map.find(find) != map.end())
                res = min(res, i - map[find]);
            // 记录 prefixSum 最后一次出现的位置
            map[prefixSum] = i;
        }
        // 没得删或者要全删时返回 -1
        return (res == INT_MAX || res == nums.size()) ? -1 : res;
    }
};

1371. 每个元音包含偶数次的最长子字符串

#include <vector>
#include <iostream>

using namespace std;

class Solution {
public:
    int findTheLongestSubstring(string s) {
        int ans = 0;
        int len = s.length();
        // 只有 5 个元音字符,状态 5 位,状态总数 32 种,-2 表示这个状态之前没出现过
        vector<int> map(32, -2);
        // aeiou 00000
        map[0] = -1;
        // status 低 5 位从低到高分表表示 aeiou 的奇偶性,0 为偶,1 为奇
        int status = 0;

        for (int i = 0, m; i < len; i++) {
            // 当前字符 在 status 中对应的位置
            m = move(s[i]);
            // 情况1 : 当前字符不是元音,status 不变
            // 情况2 : 当前字符是元音,a~u(0~4),修改相应的状态,亦或运算改变对应元音字符的奇偶性
            if (m != -1) status ^= 1 << m;
            if (map[status] != -2) {
                // 同样的状态,之前最早出现在哪
                ans = max(ans, i - map[status]);
            } else {
                // 记录状态第一次出现的位置
                map[status] = i;
            }
        }
        return ans;
    }

    int move(char ch) {
        switch (ch) {
            case 'a':
                return 0;
            case 'e':
                return 1;
            case 'i':
                return 2;
            case 'o':
                return 3;
            case 'u':
                return 4;
            default:
                // 不是元音
                return -1;
        }
    }
};

标签:map,前缀,nums,int,res,prefixSum,构建,数组,include
From: https://www.cnblogs.com/sprinining/p/18442490

相关文章

  • 65结构体-结构体数组。在C++中,结构体的定义是什么呢?如何新建一个结构体呢?新建好的结构
    问题描述:根据下列代码和结果回答下列问题。//Createdby黑马程序员.#include"iostream"usingnamespacestd;#include<string>//结构体定义structstudent{//成员列表stringname;//姓名intage;//年龄intscore;//分数}stu3;/......
  • 网站二级域名+cploar+shinyproxy构建web APP私有服务器
    网站二级域名+cploar+shinyproxy构建webAPP私有服务器WebAPP是一种功能相对单一的,可以在浏览器中运行的应用程序,构建相对容易且易于传播,被认为是临床预测模型最佳的载体。一种理想的情况,就是我们将构建的各种临床预测模型放置到网上,以“微服务”的形式存在,需要的时候登......
  • 数组中洛谷p1427小鱼的数字游戏
    先来看看题目吧:然后先来复习一下数组:你需要了解:数组的定义,数组的创建,数组的初始化,数组的使用(尤其是数组下标是从零开始的!)然后就来看思路吧:......
  • 鹏哥C语言54.一维数组(知识点)
    1.1一维数组的创建✌️✌️✌️ 举个例子:! 1.2数组的初始化 特别注意上面第6个,arr6[]实际上算是arr6[7]因为字符串末尾默认放了一个\0......
  • React响应式修改数组和对象
    在React中,响应式地修改数组数据是一个常见的需求,它涉及到状态(state)的管理和更新。React的状态是不可变的,这意味着你不能直接修改状态对象中的数组元素,而是需要创建一个新的数组来更新状态。下面将详细解释React中如何响应式地修改数组数据。1.为什么要不可变地更新数组状态?......
  • 用C/C++构建自己的Redis——第五章、Redis中的AVL树实现
    用C/C++构建自己的Redis——第五章、Redis中的AVL树实现文章目录用C/C++构建自己的Redis——第五章、Redis中的AVL树实现前言一、键值对集查询概念1.1键值对集合查询1.2数据结构排序的复习排序数组(SortedArrays)树形数据结构(TreeDataStructures)通过随机性平衡(Balan......
  • 构建未来城市天际线:低空经济基础设施的发展趋势
    随着科技的不断进步和城市化进程的加快,低空经济正在成为推动城市发展的重要力量。低空经济不仅包括传统的航空业务,还涵盖了无人机物流、空中游览、农业植保、应急救援、空中交通等多个领域。在这一背景下,低空经济基础设施的建设显得尤为重要。 1.低空经济基......
  • 10789 神秘指数 数组 枚举 check
    解决思路 计算总和:首先计算所有神秘物品的神秘指数和 sum。 枚举分组数:从 n 开始枚举分组数 i,尝试将神秘物品分成 i 组。 检查分组可行性:对于每个分组数 i,检查是否可以将神秘物品分成 i 组且每组的神秘指数和相同。 输出结果:找到最小的可行分组数 i,......
  • Link-local地址是IPv6中一种特殊类型的地址,用于在同一链路(网络段)内进行通信。这些地址
    IPv6的link-local地址定义:Link-local地址是IPv6中一种特殊类型的地址,用于在同一链路(网络段)内进行通信。这些地址的前缀是FE80::/64,并且每个IPv6设备在其网络接口上都会自动生成一个link-local地址。来源:Link-local地址的设计目的是为了支持IPv6设备之间的本地通信,而不需要依......
  • 【大模型指令微调: 从零学会炼丹】第一章: 微调数据集构建
    大模型指令微调:从零学会炼丹系列目录第一章:微调数据集构建文章目录大模型指令微调:从零学会炼丹系列目录第一章:微调数据集构建Alpaca格式编写Instructioninstruction-key读取本地数据定义format函数第一章:微调数据集构建Alpaca格式Alpaca格式是一......