leetcode hot100(2)双指针,滑动窗口

目录

一、双指针

283.移动零

11.盛最多水的容器

15.三数之和

42.接雨水

二、滑动窗口

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

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


一、双指针

283.移动零

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n=nums.size();
        int left=0;
        int right=0;
        while(right<n)
        {
            if(nums[right]!=0)
            {
                swap(nums[left],nums[right]);
                left++;
            }
            right++;
        }
    }
};

时间复杂度:O(n)

思路:

一次遍历,将非0向最左移动

左指针指向非零元素的最后一位的下一位,右指针遍历数组,如若当前元素不为0即将其值与左值针指向值互换,随后左值针向右一位。这样每一位不为0的元素都会按顺序移动到左指针前数组右侧,保留了相对顺序与非零性。

11.盛最多水的容器

cpp 复制代码
class Solution {
public:
    int maxArea(vector<int>& height) {
     int n=height.size();
     int left=0;
     int right=n-1;
     int ans=min(height[left],height[right])*(right-left);
     while(left<right)
     {
        ans=max(ans,min(height[left],height[right])*(right-left));
        if(height[left]>=height[right]){
            right--;
        }
        else{
            left++;
        }
     }
     return ans;
};
};

时间复杂度:O(n)

思路:最开始存储雨水为左右两端最小值乘以整个数组长度,如果移动两端长度会变短,故必须要两端最小值增大才能有更大的答案,于是移动较小端即可。

15.三数之和

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>>ans;
        sort(nums.begin(),nums.end(),less<int>());
        for(int i=0;i<n;i++)
        {
            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }
            int tar=-nums[i];
            int k=n-1;
            for(int j=i+1;j<n;j++)
            {
                if(j>i+1&&nums[j]==nums[j-1])
                {
                    continue;
                }
                while(j<k&&nums[j]+nums[k]>tar){
                    k--;
                }
                if(j==k){
                    break;
                }
                if(nums[j]+nums[k]==tar){
                    ans.push_back({nums[i],nums[j],nums[k]});
                }
            }
        }
        return ans;
    }
};

思路:针对每个数都依次遍历他之后的数是否存在两个数和它相加等于0,双重循环为O(n的2次方),可以用双指针进行优化。

数组按从小到大排序过后对于每个左值如果和右值相加大于目标值即可让右指针向左移动,当不大于后只要不是相等就不满足,此时左值真向右移动,左值增加,和原左值相加都大于目标值的肯定也会大于目标值,右指针不用重置到n-1。于是为O(n)。

42.接雨水

cpp 复制代码
class Solution {
public:
    int trap(vector<int>& height) {
        int left=0;
        int n=height.size();
        int right=n-1;
        int leftMax=height[0];
        int rightMax=height[n-1];
        int ans=0;
        while(left<right){
            leftMax=max(leftMax,height[left]);
            rightMax=max(rightMax,height[right]);
            if(height[left]<height[right])
            {
                ans+=(leftMax-height[left]);
                left++;
            }
            else
            {
                ans+=(rightMax-height[right]);
                right--;
            }
        }
        return ans;
    }
};

时间复杂度:O(n)

思路:

根据示例图观察可得一个柱子接的雨水量=min(它左侧最高柱子高度,它右侧最高柱子高度)-它本身高度。于是用双指针的方法,维护leftMax和rightMax两个变量,left,right两个指针。当left所指向的柱子高度小于right所指向柱子的高度时,分为两种情况:

(1)left和right都指向初始位置,则leftMax一定会小于rightMax,则当前柱子雨水量=leftMax-heightleft,并且left++。

(2)当不指向初始位置时,left之前的位置已经有leftMax一定小于rightMax,因为左右指针不相撞,所以之前位置的rightMax值一定在当前left右侧,如果当前left位置柱子高度也低于右侧则仍然是leftMax一定会小于rightMax。

即(1)(2)情况都是柱子雨水量=leftMax-heightleft

若是left所指向柱子高度大于right所指向柱子的高度时候同理。

二、滑动窗口

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

cpp 复制代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
      	unordered_map<char,int>mp;
		int n=s.size();
		int maxv=0;
		int l=0;
		int r=0;
		for(r;r<n;r++)
		{
			//特判最后一次时的长度
			if(mp.find(s[r])==mp.end())
			{
				mp[s[r]]=r;
                if(r==n-1){
                    maxv=max(maxv,r-l+1);
                }
			}
			else{
			
				maxv=max(maxv,r-l);
				int tar=mp[s[r]]+1;
				for(int i=l;i<tar;i++)
				{
					mp.erase(s[i]);
				}
				mp[s[r]]=r;
				l=tar;
			}
        }
        return maxv;
    }
};

思路:

一次遍历,遍历到的字符用哈希表记录位置,遇到重复的字符时候比较当前长度和历史最长长度,并且将之前记录的当前字符位置之前字符全部从哈希表删除,更新当前字符位置并将之前字符位置+1作为子串起点。

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

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int>ans;
        int n=s.size();
        int n1=p.size();
        if(n<n1)return ans;
        vector<int>s_arr(30);
        vector<int>p_arr(30);
        for(int i=0;i<n1;i++)
        {
            s_arr[s[i]-'a']++;
            p_arr[p[i]-'a']++;
        }
        if(s_arr==p_arr)ans.push_back(0);
        for(int i=n1;i<n;i++)
        {
            s_arr[s[i]-'a']++;
            s_arr[s[i-n1]-'a']--;
            if(s_arr==p_arr)ans.push_back(i-n1+1);
        }
        return ans;
    }
};

时间复杂度:O(n) 比较消耗时间为常数,最多30

思路:构造一个字符串p长度的滑动窗口存储包含的每个字母个数,每次向右遍历的时候更改状态并且和p比较。

相关推荐
遥感知识服务几秒前
从局部阈值、双极化到暗地表剔除:NASA OPERA DSWx-S1全球动态水体算法拆解
大数据·人工智能·深度学习·神经网络·算法·机器学习
晚风醉蝶6 分钟前
1-13-TimSort
算法
ZJU_统一阿萨姆15 分钟前
【算子开发】算子融合与Softmax_LayerNorm实现
人工智能·算法·语言模型·硬件架构
叩码以求索2 小时前
浅谈:前序遍历反转法求解N叉树的后序遍历
算法
北风toto3 小时前
中缀、前缀、后缀表达式
算法·软件设计师
听取WA声一片(无恶意)3 小时前
CSP-J/CSP-S 深度优先搜索(DFS)完全讲义
c++·算法·深度优先
码流怪侠4 小时前
2026年8月GitHub热榜深度拆解:Agent Skills席卷开源圈,一个“技能包“收割5万星
算法·程序员·github
hold?fish:palm4 小时前
30 两两交换链表中的节点
数据结构·算法·链表
Nil2084 小时前
leetcode 98验证二叉搜索树
算法·leetcode·职场和发展
kkkkkkkkkk_Z4 小时前
学嵌入式和C语言编程数据结构|学习日记Day21:内核链表与队列学习
c语言·数据结构·学习