首页 > 其他分享 >20天 hot 100 速通计划-day02

20天 hot 100 速通计划-day02

时间:2023-08-04 11:33:21浏览次数:38  
标签:子串 字符 right 20 速通 nums ++ day02 left

双指针

15. 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        
      	//要求返回数字而非下标,可以无需引入副本,直接对原数组排序
        sort(nums.begin(), nums.end());
        
      	//剪枝:排序后第一个元素大于 0,必不可能存在三数之和等于 0
        if(nums[0] > 0) return res;
				
      	//只有两数之和可以用双指针,三数之和要在两数之和外部套一层遍历
      	//要预留用双指针处理的两数之和,所以外部第 n 层被遍历的元素不能超过原数组长度 -(n - 1)
        for(int i = 0; i < nums.size() - (3-1); i++){ 
          	//剪枝:重复的直接跳过,无需做后续处理
            if(i>0 && nums[i] == nums[i-1]){
               continue;
           }        
          
          	//内部复用两数之和的逻辑,但是左指针为外层遍历元素的下一个数,即 i + 1
            int left = i + 1;
            int right = nums.size() - 1;
            while(left < right){   
                //如果去重逻辑放在找到第一个三元组之前,则可能直接导致漏掉 [0,0,0] 的情况
                if(nums[i]+nums[left]+nums[right]==0){
                    //返回的不是下标,故可以直接操纵原本
                    res.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    
                  //去重逻辑应该放在找到第一个三元组之后
                  //注意区分内外去重逻辑的差异
                  //内部去重主要考虑边界问题,所以向前看
                  //外部去重主要考虑排序问题,所以往回看
                    while(left < right && nums[right] == nums[right - 1]){
                        right--;
                    }
                    while(left < right && nums[left] == nums[left + 1]){
                        left++;
                    }
                    //找到答案时,双指针同时收缩,因为还要继续搜索
                  	//其实两数之和也应该同时收缩,但是两数之和题目中给明只有一个有效答案,所以当时直接返回
                    right--;
                    left++;
                }else if(nums[i]+nums[left]+nums[right]>0){
                    right--;
                }else if(nums[i]+nums[left]+nums[right]<0){
                    left++;
                }
            }
            
       }
       return res;
    }
};

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

img

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105
class Solution {
public:
    //双指针,按列求 ↓
    int trap(vector<int>& height) {
      	//剪枝:宽度小于 3,接不到雨水
        if (height.size() <3) return 0;
        
      	//定义首尾指针
        int left = 0, right  = height.size()-1;
        //定义左右最高柱子高度
        int maxLeft = 0, maxRight = 0;
        //定义结果
        int res = 0;

        while(left < right){
            // 短板效应合并:下标 i (第 i 列)所能接水的面积,由 maxLeft 和 maxRight 决定
          	//1. 确定下标 i By 比较 height[left] 和 height[right]
          	//2-1. 计算下标面积 By maxLeft - height[left](前提:height[left] < maxLeft)
            //2-2. 计算下标面积 By maxRight - height[right](前提:height[right] < maxRight)
            // 短板效应视角一:下标 i 取 left 还是 right,由 height[left] 和 height[right] 决定
            if(height[left] < height[right]){
                //短板效应视角二:只有内部小于外部,才能接到水
                if(height[left] < maxLeft){
                    res+=(maxLeft - height[left]);
                }
                //else res += 0;
                maxLeft = max(height[left], maxLeft);
                left++;
            }else{
                //短板效应视角二:只有内部小于外部,才能接到水
                if(height[right] < maxRight){
                    res+=(maxRight - height[right]);
                }
                //else res += 0;
                maxRight = max(height[right],maxRight);
                right--;
            }
        }
        return res;
    }
};
图示

图示源于 leetcode 图解

  • 较矮的墙的高度大于当前列的墙的高度:注水量 = 较矮的一边 - 当前列的高度

image.png

image.png

  • 较矮的墙的高度小于当前列的墙的高度:不注水

image.png

image.png

  • 较矮的墙的高度等于当前列的墙的高度:不注水

image.png

image.png

滑动窗口

3. 无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

提示:

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int res = 0;
				//无需引入 need 和 valid,因为只要求 window 中不出现重复子串
      	//伸缩逻辑为:有重复则移出,无重复则移入
        unordered_map<char, int> window;
      
        
        int left = 0, right = 0;
        //保证可行解:子串
        while(right < s.size()) {
          //获取移入字符
          char in = s[right];
          //移入信号
          right++;
          //移入执行
          window[in]++;
            
          //保证最优解(限制解):不重复
          while(window[in] > 1) {
              //获取移出字符
            	char out = s[left];
            	//移出信号
            	left++;
              //移出执行
            	window[out]--;
          }
          //答案处理
          res = max(res, right - left);
        }
        return res;
    }
};

438. 找到字符串中所有字母异位词

给定两个字符串 sp,找到 s 中所有 p异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

示例 2:

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

提示:

  • 1 <= s.length, p.length <= 3 * 104
  • sp 仅包含小写字母
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
      	vector<int> res;
      	
      	//滑动窗口常规初始化
      	//need:需要满足字符数量的字母及其所需的字符数量
      	//window:当前窗口中字母对应的字符数量
      	//valid:已满足字符数量的字母数量
        unordered_map<char, int> need, window;
        for(char c: p) need[c]++;
				int valid = 0;
      
      	//快慢指针
        int left = 0, right = 0;        

        while(right < s.size()){
          	//获取移入字符
            char in = s[right];
          	//移入信号
            right++;
          	//当移入字符为所需字符时,才做移入处理
            if(need.count(in)){
              	//移入处理
                window[in]++;
              	//当移入字母的字符数量满足所需的字符数量时,已满足字符数量的字母数量 ++
                if(window[in] == need[in])
                    valid++;
            }
          
          	//只有大于 p.size() 才有可能为可行解
            while(right - left >= p.size()){
              	//满足字符数量要求的字母数量等于需要满足字符数量的字母时,记录结果
                if(valid == need.size())
                    res.push_back(left);
                //获取移出字符
              	char out = s[left];
                //移出信号
              	left++;
              	//当移出字符为所需字符时才做处理
                if(need.count(out)){
                  	//当窗口内满足要求的字母数量等于所需要满足要求的字母数量时移出
                  	//移出后满足要求的字母数量--
                    if(window[out] == need[out])
                        valid--;
                  	//移出执行
                    window[out]--;
                }
            }
        }
        return res;
    }
};

子串

560. 和为 K 的子数组(前缀和)

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数

示例 1:

输入:nums = [1,1,1], k = 2
输出:2

示例 2:

输入:nums = [1,2,3], k = 3
输出:2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
  	// 前缀和是指从数组的开头到当前位置的所有元素的和
  	// 利用前缀和可以快速计算出任意子数组的总和
  	// 记录前缀和出现的次数,key 为前缀和,value 为该前缀和出现的次数
    unordered_map<int, int> preSumCount; 
    preSumCount[0] = 1; // 初始化前缀和为0的计数为1(源于规定,并无实际意义)
    int preSum = 0; // 记录前缀和
    int count = 0; // 记录f和为k的子数组个数

    for (int i = 0; i < nums.size(); i++) {
        preSum += nums[i]; // 计算前缀和
        if (preSumCount.find(preSum - k) != preSumCount.end()) { 
          	//判断当前的前缀和 preSum 减去 k 是否在之前的前缀和中出现过
            //如果出现过,则说明存在一个子数组的和为 k,需要将该子数组的数量累加到 count 中
            count += preSumCount[preSum - k];
        }
        preSumCount[preSum]++; // 更新前缀和的计数
    }
    return count;
	}
}

标签:子串,字符,right,20,速通,nums,++,day02,left
From: https://www.cnblogs.com/ba11ooner/p/17605432.html

相关文章

  • [岗位能力--判断推理1--贾鹏]军队文职2023-01-03之前笔记
    day1 ......
  • [安洵杯 2019]game
    [安洵杯2019]game将文件放入IDA中打开,查看main()函数发现读取用户的输入,并存入v8这个变量当中,下面有两个关键函数check1()和check3()使用到了该变量,我们首先分析check1()发现有大量的循环,根据以往的经验,这是一种混淆手段,此题的程序流程不算复杂,可以跟着流程一步步分析经......
  • 【2023-08-03】不是遗憾
    20:00所食愈少,心愈开,年愈益。所食众多,心愈塞,年愈损焉。                                                 ——张华前几天,看到香港表哥发的一个朋友圈,他感慨说:“当你回......
  • 2023年XCode升级GameCenter必读
    一、GameCenter功能介绍iOS中的GameCenter是Apple提供的游戏中心服务,它具有以下核心功能:玩家账号系统-提供玩家帐号系统,可以在不同游戏中使用统一的GameCenter账号。成就与排行榜-可以设置游戏内的成就系统,以及查看不同游戏的排行榜。多人对战-支持通过WiFi或......
  • 2023年CSPM-3国标项目管理中级证书含金量高吗?想考一个
    CSPM-3中级项目管理专业人员评价,是中国标准化协会(全国项目管理标准化技术委员会秘书处),面向社会开展项目管理专业人员能力的等级证书。旨在构建多层次从业人员培养培训体系,建立健全人才职业能力评价和激励机制的要求,培养我国项目管理领域复合型人才。  【证书含金量】 ·竞聘优先......
  • 2023年8月杭州/宁波/深圳CDGA/CDGP数据治理认证招生
    DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义,帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力,促进开展工作实践应用及实际问题解决,形成企业所需的新数字经济下的核心职业竞争能力。DAMA是数据管理方面的认证,帮助数据从业者提升......
  • 2023年8月杭州/宁波/深圳制造业产品经理NPDP认证招生
    产品经理国际资格认证NPDP是新产品开发方面的认证,集理论、方法与实践为一体的全方位的知识体系,为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。  【认证机构】 产品开发与管理协会(PDMA)成立于1979年,是全球范围内产品开发与管理专业人士最杰出的倡导者,协助个人、企业......
  • 2023年下半年杭州/宁波/深圳软考信息系统项目管理师报名
    信息系统项目管理师是全国计算机技术与软件专业技术资格(水平)考试(简称软考)项目之一,是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试,既属于国家职业资格考试,又是职称资格考试。信息系统项目管理师,属于软考三个级别中的“高级”。  【报考要求】 不设学历与资历......
  • 2023年9月杭州/宁波/深圳DAMA-CDGA/CDGP认证考试报名
    据DAMA中国官方网站消息,2023年度第三期DAMA中国CDGA和CDGP认证考试定于2023年9月23日举行。 报名通道现已开启,相关事宜通知如下: 考试科目: 数据治理工程师(CertifiedDataGovernanceAssociate,CDGA)数据治理专家(CertifiedDataGovernanceProfessional,CDGP) 考试时间: CDGA:2023......
  • ftp的主动模式,非20数据端口
    某银行之间ftp文件传输,修改了模式端口21,改成1021,数据传输端口就变成了1020,就是ftp端口-1FTP协议使用两个端口来处理数据传输:一个用于命令(默认为21),另一个用于数据(默认为20)。当你改变命令端口时,这并会影响数据端口。在主动模式下,FTP服务器会从它的数据端口(默认是20)向客户端的一......