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-height[left],并且left++。

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

即(1)(2)情况都是柱子雨水量=leftMax-height[left]。

若是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比较。

相关推荐
风筝在晴天搁浅1 小时前
LeetCode CodeTop 113.路径总和Ⅱ
算法·leetcode
张赫轩(不重名)1 小时前
加权重心(换根DP)
c++·算法·动态规划·图论
水木流年追梦1 小时前
【python因果库实战26】逆概率加权模型1
开发语言·python·算法·leetcode
2401_840105201 小时前
题解: [GESP202409 八级] 美丽路径
数据结构·c++·算法·动态规划
今儿敲了吗2 小时前
链表篇(五)——链表中间结点
数据结构·笔记·算法·链表
码农的神经元2 小时前
2026 年数维杯A 题:抱轨式磁浮列车的悬浮电磁铁故障检测问题
人工智能·算法·数学建模
SiYuanFeng2 小时前
面试大厂leetcode重点题型简洁明快复习(dfs/bfs,动态规划,链表,滑动窗口/双指针,回溯,ACM型输入输出,二分)
leetcode·面试·coding
gumichef2 小时前
栈和队列(1)
开发语言·数据结构
小新同学^O^2 小时前
算法学习 --> 快速输入和输出
java·学习·算法