IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【算法/前缀和/哈希表优化】题解+详细备注(共9题) -> 正文阅读

[数据结构与算法]【算法/前缀和/哈希表优化】题解+详细备注(共9题)

560.和为K的子数组

class Solution {
public:
	// [j..i]的子数组和:pre[i+1] - pre[j]
	// pre[i+1]-pre[j] == k
	// 关键点是想到:考虑以 i 结尾的和为 k 的连续子数组个数时只要统计有多少个前缀和为pre[i+1]?k 的 pre[j] 即可

    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> mp;
        mp[0] = 1;
        int count = 0;
		int n = nums.size();
		vector<int> pre(n+1);
		for(int i{};i<n;++i){
			pre[i+1] = pre[i] + nums[i]; 
			if (mp.find(pre[i+1]- k) != mp.end()) {
                count += mp[pre[i+1]- k];
            }
			mp[pre[i+1]]++;
		}	

        return count;
    }
};

1248.统计「优美子数组」

class Solution {
public:
	// 关键是pre前缀的定义:定义pre[i+1] 为 [0..i] 中奇数的个数,所以pre[i+1] = pre[i] + (nums[i]&1)
	// [j..i] 这个子数组里的奇数个数恰好为 k 这个条件我们可以转化为 pre[i+1]?pre[j]==k
	// pre[j] = pre[i+1] - k
    int numberOfSubarrays(vector<int>& nums, int k) {
        unordered_map<int, int> mp;
        mp[0] = 1;
        int count = 0;
		int n = nums.size();
		vector<int> pre(n+1);
		for(int i{};i<n;++i){
			pre[i+1] = pre[i] + (nums[i]&1); 
			if (mp.find(pre[i+1]- k) != mp.end()) {
                count += mp[pre[i+1]- k];
            }
			mp[pre[i+1]]++;
		}	

        return count;
    }
};

525.连续数组

class Solution {
public:
	// 将原问题转化为求:求最长的连续子数组,其元素和为 0;所以pre[i+1] - pre[i] = 0
	// [j..i] 这个子数组的和恰好为0 pre[i+1] - pre[j]==0
	// pre[j] = pre[i+1] ,所以也就是找前缀和为pre[i+1]的下标
    int findMaxLength(vector<int>& nums) {
   	    unordered_map<int, int> mp;
        mp[0] = -1;
        int result= 0;
		int n = nums.size();
		vector<int> pre(n+1);
		for(int i{};i<n;++i){
			pre[i+1] = pre[i] + (nums[i] == 0 ? -1 : nums[i]); 
			if (mp.find(pre[i+1]) != mp.end()) {
				int j = mp[pre[i+1]];
				result = max(result,i-j);
            }else  mp[pre[i+1]] = i;
		}	

        return result;
    }
};

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

class Solution {
public:
	// 前缀和大于0,[0,i]符合条件
	// 前缀和小于0,在hash中找小于pre[i]的下标;且pre[i]-1的下标一定是小于pre[i]-2的下标
    int longestWPI(vector<int>& hours) {
        unordered_map<int, int> mp;

        int result= 0;
		int n = hours.size();
		vector<int> pre(n+1);
		for(int i{};i<n;++i){
			pre[i+1] = pre[i] + (hours[i] > 8 ? 1 : -1); 
			// 只需记录一次即可,即记录最小的下标
            if(!mp.count(pre[i+1]))
            mp[pre[i+1]] = i;

            if(pre[i+1] > 0){
                result = i+1;
                continue;
            }

            if(mp.count(pre[i+1]-1)){
                result = max(result,i-mp[pre[i+1]-1]);
            }
		}	

        return result;
    }
};

面试题17.05.字母与数字

class Solution {
public:
	// 同525. 连续数组,只是需要在最长的集合中找左下标最小的集合
    vector<string> findLongestSubarray(vector<string>& array) {
        unordered_map<int, int> mp;
        mp[0] = -1;
        int result= 0;
		int n = array.size();
		vector<int> pre(n+1);
        vector<pair<int,int>> vp;
		for(int i{};i<n;++i){
			pre[i+1] = pre[i] + (isdigit(array[i][0])? -1 : 1); 
			if (mp.find(pre[i+1]) != mp.end()) {
				int j = mp[pre[i+1]];

                if(i-j > result){
                    result = i-j;
                    vp.clear();
                    vp.push_back({j,i});
                }else if(i-j == result){
                    vp.push_back({j,i});
                }
            }else  mp[pre[i+1]] = i;
		}	

        if(vp.size() == 0) return {};
        sort(vp.begin(),vp.end());

        return vector<string>(array.begin()+vp[0].first + 1,array.begin()+vp[0].second+1);
    }
};

974.和可被K整除的子数组

class Solution {
public:
	// 关键是想到:(preSum[i+1]?preSum[j]) mod K== 0
	// 即:preSum[j] mod K == preSum[i+1] mod K

    int subarraySum(vector<int>& nums, int k) {
		unordered_map<int, int> mp;// 记录前缀和mod k的数量
        // 注意的一个边界条件是,我们需要对哈希表初始化,记录 record[0]=1,这样就考虑了前缀和本身被 k 整除的情况
        mp[0] = 1;
		int n = nums.size();
		int result{};
		vector<int> pre(n+1);
		for(int i{};i<n;++i){
			pre[i+1] = pre[i] + nums[i]; 
			// 注意 C++ 取模的特殊性,当被除数为负数时取模结果为负数,需要纠正
			// 这个操作不是在简单的取绝对值,负数的取模运算公式如下
			int preMod = (pre[i+1]%k + k)%k;
			if (mp.find(preMod) != mp.end()) {
				result += mp[preMod];
                
            }
            mp[preMod]++;
		}	

        return result ;
    }
};

523.连续的子数组和

class Solution {
public:
	// 关键是想到:(preSum[i+1]?preSum[j]) mod K== 0
	// 即:preSum[j] mod K == preSum[i+1] mod K

    int subarraySum(vector<int>& nums, int k) {
		unordered_map<int, int> mp;// 记录前缀和mod k的数量
        // 注意的一个边界条件是,我们需要对哈希表初始化,记录 record[0]=1,这样就考虑了前缀和本身被 k 整除的情况
        mp[0] = -1;
		int n = nums.size();
		int result{};
		vector<int> pre(n+1);
		for(int i{};i<n;++i){
			pre[i+1] = pre[i] + nums[i]; 
			// 注意 C++ 取模的特殊性,当被除数为负数时取模结果为负数,需要纠正
			// 这个操作不是在简单的取绝对值,负数的取模运算公式如下(需要关注int溢出)
			int preMod = ((long long)pre[i+1]%k + k)%k;
			if (mp.find(preMod) != mp.end()) {
                int left = mp[preMod];
				if(i-left >= 2) return true;
                
            }else{
            	// 一定要放在else里面,保证左下标是最小的
                mp[preMod] = i;
            }
		}	

        return false;
    }
};

1524.和为奇数的子数组数目

class Solution {
public:
	// 确定:奇数+偶数 = 奇数
	// 然后利用前缀和进行奇偶判断
    int numOfSubarrays(vector<int>& arr) {
        const int MODULO = 1000000007;
        
        int odd{};
        int even{1};
        int result{};
        int n = arr.size();

        vector<int> pre(n+1);

        for(int i{};i < n;++i){
            pre[i+1] = pre[i] + arr[i];

            int preMod = pre[i+1]%2;

            result = (result + (preMod == 0 ?odd :  even))%MODULO;
            if(preMod == 0) even++;
            else odd++;
        }

        return result;
    }
};

1590.使数组和能被P整除


class Solution {
public:
	// 设删除的子数组的和:del = preSum[i+1] - preSum[j] 
	// 设总和为sums
    // 根据题意得:(sums- del ) % p == 0 
    // 再由同余定理可知: (sums- del ) % p == 0
    // sums % p = (preSum[i+1]- preSum[j]) % p
    // (sums + preSum[j]) % p = preSum[i+1] % p
    int minSubarray(vector<int>& nums, int p) {
        unordered_map<int, int> mp;
        // 注意的一个边界条件是,我们需要对哈希表初始化,记录 mp[0]=-1。
        // 因为有一个特殊情形, 当区间和(del )对应的前缀和之差中被减数(即这里的preSum[i])%p得到的余数是0时, 区间的起点index会成为0。此时的被减数变得可有可无了, 长度按更长的算, 即j+1或j-(-1)。
        mp[0] = -1;
		int n = nums.size();
		int result{n};
		// 初始值要设为0.0,不然依然会溢出
        long long sums = accumulate(nums.begin(),nums.end(),0.0);
        if(sums < p) return -1;

        int mod = sums % p;
        if(0 == mod) return 0;
        
		vector<long long> pre(n+1);
		for(int i{};i<n;++i){
			pre[i+1] = pre[i] + nums[i]; 
            int curMod = pre[i+1] % p;
            // 注意 C++ 取模的特殊性,当被除数为负数时取模结果为负数,需要纠正
			// 这个操作不是在简单的取绝对值,负数的取模运算公式如下
            int target = (curMod - mod + p) % p;
			if (mp.find(target) != mp.end()) {
                int j = mp[target];
				result = min(i-j,result); 
            }
            mp[curMod] = i;
		}	

        return result == n ? -1 : result;
    }
};

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-14 10:09:04  更:2022-05-14 10:11:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:59:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码