【LeetCode】

目录

知识框架

LeetCode

No.1 按照顺序的结果没坚持下来

1. 两数之和

主要是 哈希表进行优化;

重点是 map的find; it->second ;以及 it != hastable.end();

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        map<int,int>hastable;
        for(int i=0;i<nums.size();i++){
            hastable[nums[i]]=i;
        }
        vector<int>res;
        for(int i=0;i<nums.size();i++){
            auto it = hastable.find(target-nums[i]);
            if(it !=hastable.end()){
                if(i>=it->second){
                    continue;
                }
                res.push_back(i);
                res.push_back(it->second);
                break;
            }
        }
        return res;
        
    }
};

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

滑动窗口:

什么是滑动窗口?

其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!

如何移动?

我们只要把队列的左边的元素移出就行了,直到满足题目要求!

一直维持这样的队列,找出队列出现最长的长度时候,求出解!

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.size() == 0) return 0;
        unordered_set<char> lookup;
        int maxStr = 0;
        int left = 0;
        for(int i = 0; i < s.size(); i++){
            while (lookup.find(s[i]) != lookup.end()){//找到的话;
                lookup.erase(s[left]);
                left ++;
            }
            maxStr = max(maxStr,i-left+1);
            lookup.insert(s[i]);
    }
        return maxStr;
        
    }
};

4. 寻找两个正序数组的中位数

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m=nums1.size();
        int n = nums2.size();

        vector<int>ans;
        int pos1=0,pos2=0;
        while(pos1<m&&pos2<n){
            if(nums1[pos1]<=nums2[pos2]){
                ans.push_back(nums1[pos1]);
                pos1++;
            }else{
                ans.push_back(nums2[pos2]);
                pos2++;
            }
        }
        if(pos1>=m){
            for( ; pos2<n;pos2++)ans.push_back(nums2[pos2]);
        }
        if(pos2>=n){
            for( ; pos1<m;pos1++)ans.push_back(nums1[pos1]);
        }
        double res =0.0;
        if((m+n)%2==0){
            res=(ans[(m+n)/2-1]+ans[(m+n)/2])/2.0;
        }else{
            res=ans[(m+n-1)/2]*1.0;
        }
        return res;
    }
};

5. 最长回文子串

中心扩散法子;

1、从每一个位置出发,向两边扩散即可。遇到不是回文的时候结束

首先往左寻找与当期位置相同的字符,直到遇到不相等为止。
然后往右寻找与当期位置相同的字符,直到遇到不相等为止。
最后左右双向扩散,直到左和右不相等。

为什么是这样呢??

如果长度是单数,那么很明显,最中心的是一个字符;而结果是偶数 的话,那么中心就是两个字符,并且相同。

class Solution {
public:
    string longestPalindrome(string s) {
        //中心扩散法:从每个字母开始 进行扩散遍历判断;
        int n=s.size();
        int left = 0;
        int right = 0;
        int len = 1; //记录选择的字符字串长度
        int maxStart = 0;
        int maxLen = 0;

        for (int i = 0; i < n; i++) {
            len=1;
            left = i - 1;
            right = i + 1;
            while (left >= 0 && s[left]==s[i]) {
                len++;
                left--;
            }
            while (right < n && s[right]==s[i]) {
                len++;
                right++;
            }
            while (left >= 0 && right < n && s[left]==s[right]) {
                len = len + 2;
                left--;
                right++;
            }
            if (len > maxLen) {
                maxLen = len;
                maxStart = left;
            }
        }
        return s.substr(maxStart+1,maxLen);

    }
};

6. N 字形变换


7. 整数反转

弹出最后的数字,

压入;

while循环进行倒转;;;

class Solution {
public:
    int reverse(int x) {
        char resStar='0';
        if(x<0) resStar='-';
        x=abs(x);

        int temp=0;
        int res=0;

        while(x!=0){
            temp=x%10;
            x=x/10;
            
            res=res*10+temp;
            if(res>214748364){
                return 0;
            }
        }
        if(resStar=='-'){
            return -res;
        }else{
            return res;
        }

    }
};

No.2 动态规划

5.最长回文串:

给你一个字符串 s,找到 s 中最长的回文子串。

对于一个子串而言,如果它是回文串,并且长度大于2,那么将它首尾的两个字母去除之后,它仍然是个回文串。例如对于字符串“ababa”,如果我们已经知道“bab”是回文串,那么“ababa”一定是回文串,这是因为它的首尾两个字母都是“a”。
根据这样的思路,我们就可以用动态规划的方法解决本题。我们用P(i,j)表示字符串s的第i到j个字母组成的串 (下文表示成s[i:j])是否为回文串:P(i,j)一false,其它情况这里的「其它情况」包含两种可能性:. s[i,j]本身不是一个回文串;或者 i> j,此时s[i,j]本身不合法。
那么我们就可以写出动态规划的状态转移方程:
P(i,j)=P(i+1,j- 1)乘以(S:== S;)

也就是说,只有s[i+1 :j-1]是回文串,并且s 的第i和j个字母相同时,s[i :j才会是回文串。上文的所有讨论是建立在子串长度大于2的前提之上的,我们还需要考虑动态规划中的边界条件,即子串的长度为1或2。对于长度为1的子串,它显然是个回文串;对于长度为2的子串,只要它的两个字母相同,它就是一个回文串。因此我们就可以写出动态规划的边界条件:
P(i,i)= true
P(i,i+1)=(S== Si+1)
根据这个思路,我们就可以完成动态规划了,最终的答案即为所有P(i,j)= true中j-i+1(即子串长度)的最大值。注意:在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。

#include<bits/stdc++.h>
using namespace std;
#define N 10001

int main()
{
    int dp[N][N];
    string s;
    cin>>s;
    if(s.size()<2){
        //则本身为回文串;
    }
    int n=s.size();
    int maxlen=1;
    int begin=0;
    // dp[i][j] 表示 s[i..j] 是否是回文串
    // 初始化:所有长度为 1 的子串都是回文串
        for (int i = 0; i < n; i++) {
            dp[i][i] = 1;
        }
        // 递推开始
        // 先枚举子串长度
        for(int L=2;L<=n;L++){
            for(int i=0;i<n;i++){
                  // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
                  int j=L+i-1;
                  if(j>=n){
                    break;
                  }
                  if(s[i]!=s[j]){
                    dp[i][j]=0;

                  }else{
                    if(j-i<3){
                        dp[i][j]=1;
                    }else{
                        dp[i][j]=dp[i+1][j-1];
                    }

                  }
                // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }


return 0;
}

42.接雨水

每个位置能够存储的水的量为两步:先找左边的墙的最高的高度h1,再找右边的墙的最高的高度h2;然后计算min(h1,h2)-height;
int trap(vector<int>& height)
{
    int ans = 0;
    int size = height.size();
    //0位置和size-1位置都不行;
    for (int i = 1; i < size - 1; i++) {
        int max_left = 0, max_right = 0;
        for (int j = i; j >= 0; j--) { //Search the left part for max bar size
            max_left = max(max_left, height[j]);
        }
        for (int j = i; j < size; j++) { //Search the right part for max bar size
            max_right = max(max_right, height[j]);
        }
        ans += min(max_left, max_right) - height[i];
    }
    return ans;
}

No.3 周赛

第 79 场双周赛

6083.判断─个数的数字计数是否等于数位的值

#include<bits/stdc++.h>
using namespace std;
#define N 10001
string s;
int check(int x){
    int count=0;
    for(auto i:s){
        if(i-'0'==x)count++;
    }
    return count;
}
int main()
{
    cin>>s;
    int flag=0;
    for(int i=0;i<s.size();i++){
        int num=s[i]-'0';
        if(num==check(i)){
            flag=0;
        }else{
            flag=1;
        }
        if(flag==1)break;
    }
    if(flag==1)cout<<"flase"<<endl;
    else cout<<"true"<<endl;
return 0;
}

6084.最多单词数的发件人

//在一串字符单词中比如:messages = ["Wonderful day Alice"],
//那么如何统计单词的个数,:即只需要统计空格的数量+1;

6085.道路的最大总重要性

思路及算法
计算每个城市的出现次数,排序后,次数多的分配当前最大的值
这里直接加到大根堆中弹出,效果与排序一致

10011.以组为单位订音乐会的门票


第 301 场周赛

6112.装满杯子需要的最短总时长

#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
int n,m,t,k,d;
int x,y,z;
char ch;
string s;
vector<int>v[N];
int main()
{
    vector<int>count;
    for(int i=0;i<3;i++){
        cin>>x;
        count.push_back(x);
    }
    int ans=0;
    //进行贪心:每次装入需求最多的两杯:
    while(count[0]!=0||count[1]!=0||count[2]!=0){
        sort(count.begin(),count.end());
        if(count[2]>0)count[2]--;
        if(count[1]>0)count[1]--;
        ans++;
    }
    cout<<ans<<endl;
    return 0;
}

6113.无限集中的最小数字


第304场周赛:

使数组中所有元素都等于零

//对于N要进行适应性的更改,对于字段错误
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
long long n,m,k,g,d,t;
int x,y,z;
char ch;
string str;
vector<int>v[N];

int main() {

	vector<int>nums;
	set<int>sc;
	for(auto p:nums)sc.insert(p);
	int res=0;
	for(auto p:sc){
		if(p>0)res++;
	}
	cout<<res<<endl;

	return 0;
}

分组的最大数量

//对于N要进行适应性的更改,对于字段错误
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
long long n,m,k,g,d,t;
int x,y,z;
char ch;
string str;
vector<int>v[N];

int main() {

	sort(grades.begin(),grades.end());
	int res=0;
	int num=grades.size();
	for(int i=1; ;i++){
		if(num>=i){
			res++;
			num=num-i;
		}else{
			break;
		}
	}
	return res;

	return 0;
}

找到离给定两个节点最近的节点

最短路径问题:

「最短路径」算法有 最短路径-Dijkstra 和 无权值最短路径算法(BFS)

「Dijkstra」适用于加权有向图,没有负权重边,且无环,一般是求起点到其它所有点的最短路径,也可以改进为求两点的最短路径

「无权值最短路径算法(BFS)」适用于无权有向图,可以有环,一般是求两点的最短路径,也可以改进为求起点到其它所有点的最短路径

对于本题,每条边的权重均为 1,所以可以看作为无权值,我们使用上述的第二种方法「无权值最短路径算法(BFS)」

由于点与点之间最多只有一条边,所以可以简化「无权值最短路径算法(BFS)」

public int closestMeetingNode(int[] edges, int node1, int node2) {
    int n = edges.length;
    // 点 node1 和 node2 到其它所有点的最短路径
    int[] dist1 = getDist(edges, node1);
    int[] dist2 = getDist(edges, node2);
    int ans = -1, min = (int) 1e5 + 7;
    // 遍历可选择的「中间点」
    for (int i = 0; i < n; i++) {
        // 分别为 node1 和 node2 到 i 的最短路径
        int d1 = dist1[i], d2 = dist2[i];
        // 如果有一方到不了,则跳过
        if (d1 == -1 || d2 == -1) continue;
        int max = Math.max(d1, d2);
        if (max < min) {
            min = max;
            ans = i;
        }
    }
    return ans;
}
// 求点 s 到其它所有点的最短路径
private int[] getDist(int[] edges, int s) {
    int d = 0;
    int[] dist = new int[edges.length];
    Arrays.fill(dist, -1);
    while (s != -1) {
        // 已经访问,考虑「环」的存在
        if (dist[s] != -1) break;
        dist[s] = d++;
        // 下一个点
        s = edges[s];
    }
    return dist;
}

图中的最长环

环问题:

图的最大环最长链 - Rogn - 博客园 (cnblogs.com)

	这是一个模板问题、:
最长环问题:
    
  
最长链问题:
    

第306场周赛:

矩阵中的局部最大值

class Solution {
public:
    vector<vector<int>> largestLocal(vector<vector<int>>& grid) {
        vector<vector<int>>res;
        vector<int>ans;
        int n=grid.size();
        int m=grid[0].size();
        int len=n-3+1;
        //以 多少个位置为左上角的起点构成3*3矩阵
        // 每一行
        for(int i=0;i<len;i++){
            //每一列
            ans.clear();
            for(int j=0;j<len;j++){
                int maxx=0;
                for(int p=0;p<3;p++){
                    for(int q=0;q<3;q++){
                        maxx=max(maxx, grid[i+p][j+q]);
                    }
                }

                ans.push_back(maxx);

            }
            res.push_back(ans);

        }

        return res;
    }
};

边积分最高的节点

class Solution {
public:
    int edgeScore(vector<int>& edges) {
        int n=edges.size();
        long long sum[n];
        memset(sum,0,sizeof(sum));
        for(int i=0;i<n;i++){//加对应的值
            sum[edges[i]]+=i;
        }
        long long max=0;
        int loc=0;
        for(int i=0;i<n;i++){//求出最大值
            if(sum[i]>max){
                max=sum[i];
                loc=i;
            }
        }
        return loc;
    }
};

根据模式串构造最小数字


统计特殊整数:数位dp


第309场周赛:

6167. 检查相同字母间的距离
// 蛀牙是进行  字符字母 与数字的转化;和


    ch='a';
    char cc = ch+1;
    cout<<cc<<endl; //结果为 b


class Solution {
public:
    bool checkDistances(string s, vector<int>& distance) {
        set<char>sc;
        for(auto i:s)sc.insert(i);
        for(auto i:sc){
            int num=0;
            for(int j=0;j<s.size();j++){
                if(s[j]==i)num=j-num;
            }
            num--;
            int wei = int(i)-97;
            if(distance[wei]!=num){
                return false;
            }
        }
        return true;
    }
};
6168. 恰好移动 k 步到达某一位置的方法数目
//对于N要进行适应性的更改,对于字段错误
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
int n,m,k,g,d;
int x,y,z,t;
char ch;
string str;
vector<int>v[N];
long long mod = 1000000000+7;
long long sum = 0;

int endstop;
void dfs(int index,int citime,long long &sum){

    if(citime<k){
        dfs(index-1,citime+1,sum);
        dfs(index+1,citime+1,sum);
    }else if(citime==k){
        if(index==endstop){
            sum++;
            sum=sum%mod;
        }
        return;
    }else{
        return;
    }
   
}


int main() {
    cin>>x>>endstop;

    cin>>k;
    dfs(x,0,sum);
    cout<<sum<<endl;


	return 0;
}

2401. 最长优雅子数组

滑动窗口:

res = max(res, right - left +1 ); 这个是关键;res记录过去(因为只是要结果。

class Solution {
public:
    int longestNiceSubarray(vector<int>& nums) {
        int n = nums.size();
        if(n == 1)return 1;
        int res = 1;
        int left = 0;//记录当前优雅子数组
        for(int right = 1;right < n;++i){
            for(int i = right - 1;i >= left;--i){
                if(nums[right] & nums[i]){
                    //说明right指向的位置和i不可以构成优雅子数组
                    left = i + 1;
                    break;
                }
            }
            res = max(res,right - left + 1);
        }
        return res;
    }
};

作者:sdy-r
链接:https://leetcode.cn/problems/longest-nice-subarray/solution/by-sdy-r-glyh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2402. 会议室 III

1.使用sort函数,重写排序规则。

struct node{
	int x;
	int y;
}a[10];
 
bool cmp(node a, node b)
{
	return a.x > b.x; //从大到小排列
//  return a.x < b.x;  从小到大排列 
}

2.在结构体中自定义排序,重小于号

struct node{
	int x;
	int y;
	bool operator<(const node &a) const{
		return x < a.x; //从大到小排序 
	                   //  x > a.x;  //从小到大排序 
	}
	//这里的排序是根据每个结构体内部的x进行排序 
}a[10];


3、优先队列排序(priority_queue)的使用:

结构体排序 + 优先队列排序(priority_queue)

// 优先级队列问题。

第 310 场周赛:

子字符串的最优划分

很经典的题目

将区间分为最少组数

很经典

最长递增子序列 II

线段树知识。。

第312场周赛

2418. 按身高排序
class Solution {
public:
    vector<string> sortPeople(vector<string>& names, vector<int>& heights) {
        vector<int>pos;
        vector<int>heightssss;
        heightssss = heights;
        sort(heights.begin(),heights.end());
        int n =heights.size();
        for(int i=n-1;i>=0;i--){
            for(int j=0;j<n;j++){
                if(heights[i]==heightssss[j]){
                    pos.push_back(j);
                    break;
                }
            }
        }
        vector<string>nameee;
        for(int i=0;i<n;i++){
            nameee.push_back(names[pos[i]]);
        }
        return nameee;
    }
};

按位与最大的最长子数组


按位与最大的最长子数组


好路径的数目


No.4 字符串

二进制数的间距:

#include <bits/stdc++.h>
using namespace std;
#define N 100100
#define inf 0x3f3f3f3f
int x,y,z;
int n,m,s,d,k;
string str;
char ch;
vector<int>v[N];

int main()
{
    cin>>n;
    vector<int>ans;
    while(n!=0){
        ans.push_back(n%2);
        n=n/2;
    }
    for(int i=ans.size()-1;i>=0;i--){
        cout<<ans[i];
    }
    
    return 0;
}

3. 无重复字符的最长子串:滑动窗口+哈希表

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        map<char,int>mp;
        int n=s.size();
        int res=0;
        int right=0,left=0;
        int flag=0;
        for(;right<n;right++){
            if(mp[s[right]]==1){
                flag=1;
                mp[s[right]]++;
            }else{
                mp[s[right]]++;
            }
            while(flag==1){
                mp[s[left]]--;
                if(mp[s[right]]==1)flag=0;
                left++;
            }
            res=max(res,right-left+1);
        }
        return res;
    }
};

20. 有效的括号:栈的对称

class Solution {
public:
    bool isValid(string s) {
        bool flag = true;
        int n=s.size();
        if(n%2!=0)return false;
        stack<char>s1,s2;
        for(int i=0;i<n;i++){
            s1.push(s[i]);
        }
        while(s1.size()!=0){
            char cc = s1.top();
            s1.pop();
            if(cc=='}'||cc==']'||cc==')'){
                s2.push(cc);
            }else{
                if(s2.size()==0){
                    return false;
                }
                if(cc=='{'){
                    if(s2.top()=='}')s2.pop();
                    else return false;
                }else if(cc=='('){
                    if(s2.top()==')')s2.pop();
                    else return false;
                }else if(cc=='['){
                    if(s2.top()==']')s2.pop();
                    else return false;
                }
            }
        }
        if(s2.size()!=0)return false;
        return true;
    }
};

No.5 前缀和

【动画模拟】一文秒杀七道题 - 连续的子数组和 - 力扣(LeetCode)

前缀和+哈希表

要想着变化方程式,,比如哈希表的那个 pre[i] - pre[j-1] = k 变化为 pre[i] - k ; 找存在。

滑动窗口模板

滑动窗口是什么呢? 可能是 一个start指针,一个end指针,进而进行滑动,根据一些题目条件进行移动。。

《挑战程序设计竞赛》这本书中把滑动窗口叫做「虫取法」,我觉得非常生动形象。因为滑动窗口的两个指针移动的过程和虫子爬动的过程非常像:前脚不动,把后脚移动过来;后脚不动,把前脚向前移动。

我分享一个滑动窗口的模板,能解决大多数的滑动窗口问题:

def findSubArray(nums):
    N = len(nums) # 数组/字符串长度
    left, right = 0, 0 # 双指针,表示当前遍历的区间[left, right],闭区间
    sums = 0 # 用于统计 子数组/子区间 是否有效,根据题目可能会改成求和/计数
    res = 0 # 保存最大的满足题目要求的 子数组/子串 长度
    while right < N: # 当右边的指针没有搜索到 数组/字符串 的结尾
        sums += nums[right] # 增加当前右边指针的数字/字符的求和/计数
        while 区间[left, right]不符合题意: # 此时需要一直移动左指针,直至找到一个符合题意的区间
            sums -= nums[left] # 移动左指针前需要从counter中减少left位置字符的求和/计数
            left += 1 # 真正的移动左指针,注意不能跟上面一行代码写反
        # 到 while 结束时,我们找到了一个符合题意要求的 子数组/子串
        res = max(res, right - left + 1) # 需要更新结果
        right += 1 # 移动右指针,去探索新的区间
    return res


滑动窗口中用到了左右两个指针,它们移动的思路是:以右指针作为驱动,拖着左指针向前走。右指针每次只移动一步,而左指针在内部 while 循环中每次可能移动多步。右指针是主动前移,探索未知的新区域;左指针是被迫移动,负责寻找满足题意的区间。

模板的整体思想是:

  1. 定义两个指针 leftright 分别指向区间的开头和结尾,注意是闭区间;定义 sums 用来统计该区间内的各个字符出现次数;

  2. 第一重 while 循环是为了判断 right 指针的位置是否超出了数组边界;当 right 每次到了新位置,需要增加 right 指针的求和/计数;

  3. 第二重 while 循环是让 left 指针向右移动到 [left, right] 区间符合题意的位置;当 left 每次移动到了新位置,需要减少 left 指针的求和/计数;

  4. 在第二重 while 循环之后,成功找到了一个符合题意的 [left, right] 区间,题目要求最大的区间长度,因此更新 res 为 max(res, 当前区间的长度) 。

  5. right 指针每次向右移动一步,开始探索新的区间。

  6. 模板中的 sums 需要根据题目意思具体去修改,本题是求和题目因此把sums 定义成整数用于求和;如果是计数题目,就需要改成字典用于计数。当左右指针发生变化的时候,都需要更新 sums

209. 长度最小的子数组:滑动窗口

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int n = nums.size();
        if (n == 0) {
            return 0;
        }
        int ans = INT_MAX;
        int start = 0, end = 0;
        int sum = 0;
        while (end < n) {
            sum += nums[end];
            while (sum >= s) {
                ans = min(ans, end - start + 1);
                sum -= nums[start];
                start++;
            }
            end++;
        }
        return ans == INT_MAX ? 0 : ans;
    }
};

238. 除自身以外数组的乘积 前缀和+后缀和

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n=nums.size();
        int sumq[n];
        int sumh[n];
        for(int i=0;i<n;i++){
            if(i==0)sumq[i]=nums[i];
            else sumq[i]=sumq[i-1]*nums[i];
        }
        for(int i=n-1;i>=0;i--){
            if(i==n-1)sumh[i]=nums[i];
            else sumh[i]=sumh[i+1]*nums[i];
        }
        vector<int>ans;
        ans.push_back(sumh[1]);
        for(int i=1;i<n-1;i++){
            ans.push_back(sumq[i-1]*sumh[i+1]);
        }
        ans.push_back(sumq[n-2]);
        return ans;
    }
};

1004. 最大连续1的个数 III:滑动窗口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oGuEapDr-1679671888186)(D:/Typora/images/image-20221020153751247.png)]

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int n=nums.size();
        int left = 0,right=0,sum=0;
        int res=0;
        for( ;right<n;right++){
            if(nums[right]==0)sum++;
            while(sum>k){
                if(nums[left]==0)sum--;
                left++;
            }
            res=max(res,right-left+1);
        }
        return res;
    }
};

1124. 表现良好的最长时间段:前缀和+单调栈

// 首先尝试滑动窗口 进行 求解,,但是不行,只能通过一半。
//我一开始也以为是滑动窗口,但想这样的case:[1,2,3,9,9,9,9,9];类似这样的滑窗做不了
class Solution {
public:
    int longestWPI(vector<int>& hours) {
        int n=hours.size();
        int left=0,right=0,sum1=0;
        int res=0;
        for(;right<n;right++){
            if(hours[right]>8)sum1++;
            else sum1--;
            while(sum1<=0&&left<=right){
                if(sum1<=0&&left==right)break;
                if(hours[left]>8)sum1--;
                else sum1++;
                left++;
            }
            
            res=max(res,right-left+1);
        }
        return res;

    }
};



// 下面的有点偏暴力了
class Solution {
public:
    int longestWPI(vector<int>& hours) {
        int n=hours.size();
        int sum[n];
        int nums[n];
        for(int i=0;i<n;i++){
            if(hours[i]>8)nums[i]=1;
            else nums[i]=-1;
        }
        sum[0]=nums[0];
        for(int i=1;i<n;i++){
            sum[i]=nums[i]+sum[i-1];
        }
        int left=0,right=0,sum1=0;
        int res=0;
        for(int i=0;i<n;i++){
            for(int j=i;j<n;j++){
                if(sum[j]-sum[i]+nums[i]>0){   //特别是这个判断条件的  +nums[i]
                    res=max(res,j-i+1);
                }
            }
        }
        return res;
    }
};

724. 寻找数组的中心下标:前缀和

class Solution {
public:
    int pivotIndex(vector<int>& nums) {
        int n=nums.size();
        int sum[n+1];
        sum[0]=0;
        for(int i=0;i<n;i++){
            sum[i+1]=sum[i]+nums[i];
        }
        vector<int>ans;
        for(int i=1;i<=n;i++){
            int left = sum[i-1];
            int right = sum[n]-sum[i];
            if(left==right){
                ans.push_back(i-1);
            }
        }
        if(ans.size()==0)return -1;
        else return ans[0];
    }
};

560. 和为 K 的子数组:前缀和+哈希表

思路:其实我们现在这个题目和两数之和原理是一致的,只不过我们是将所有的前缀和该前缀和出现的次数存到了 map 里。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ikxzAXnr-1679671888186)(D:/Typora/images/image-20221025191243786.png)]

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        map<int,int>mp;
        mp[0]=1;//是从开始到自身即pre[i]-k=0;即
        int n=nums.size();
        int pre[n+1];
        pre[0]=0;
        int res=0;
        for(int i=1;i<=n;i++){
            pre[i]=pre[i-1]+nums[i-1];
            if(mp.find(pre[i]-k)!=mp.end()){
                res+=mp[pre[i]-k];
            }
            mp[pre[i]]++;
        }
        return res;
    }
};

1248. 统计「优美子数组」:前缀和+哈希表

思路”要想着变化方程式;;;

class Solution {
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        int res=0;
        int n=nums.size();
        int pre[n+1];
        pre[0]=0;
        map<int,int>mp;
        mp[0]=1;
        for(int i=0;i<n;i++){
            if(nums[i]%2==0){
                nums[i]=0;
            }else{
                nums[i]=1;
            }
        }
        for(int i=1;i<=n;i++){
            pre[i]=pre[i-1]+nums[i-1];
            if(mp.find(pre[i]-k)!=mp.end()){
                res+=mp[pre[i]-k];
            }
            mp[pre[i]]++;
        }
        return res;

    }
};

974. 和可被 K 整除的子数组:前缀和+哈希表

其中 巧妙的 还是 方程变化。 以及对 负数的处理。

class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k) {
        map<int,int>mp;
        mp[0]=1;
        int n=nums.size();
        int pre[n+1];
        pre[0]=0;
        int res=0;
        for(int i=1;i<=n;i++){
            // 注意负数 的问题。
            pre[i]=pre[i-1]+nums[i-1];
            if(mp.find((pre[i]%k+k)%k)!=mp.end()){
                res+=mp[(pre[i]%k+k)%k];
            }
            mp[(pre[i]%k+k)%k]++;
        }
        return res;

    }
};

523. 连续的子数组和:前缀和+哈希表

class Solution {
public:
    bool checkSubarraySum(vector<int>& nums, int k) {
        int n = nums.size();
        map<int,int>mp;
        mp[0]=1;
        int pre[n+1];
        pre[0]=0;
        int res = 0;
        pre[1]=pre[0]+nums[0];
        for(int i=2;i<=n;i++){
            pre[i]=pre[i-1]+nums[i-1];
            if(mp.find(pre[i]%k)!=mp.end()){
                res+=mp[pre[i]%k];
            }
            mp[pre[i-1]%k]++; // 因为个数限制。
        }
        if(res==0)return false;
        else return true;

    }
};

930. 和相同的二元子数组:前缀和+哈希表

class Solution {
public:
    int numSubarraysWithSum(vector<int>& nums, int goal) {
        map<int,int>mp;
        mp[0]=1;
        int n=nums.size();
        int pre[n+1];
        pre[0]=0;
        int res=0;
        for(int i=1;i<=n;i++){
            pre[i]=pre[i-1]+nums[i-1];
            if(mp.find(pre[i]-goal)!=mp.end()){
                res+=mp[pre[i]-goal];
            }
            mp[pre[i]]++;           
        }
        return res;

    }
};

904. 水果成篮:滑动窗口+哈希表

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int res = 0;
        int n =fruits.size();
        int right=0,left=0;
        set<int>sc;
        map<int,int>mp;
        for(;right<n;right++){
            sc.insert(fruits[right]);
            mp[fruits[right]]++;
            while(sc.size()>2){
                mp[fruits[left]]--;
                if(mp[fruits[left]]==0)sc.erase(fruits[left]);
                left++;
            }
            res=max(res,right-left+1);
        }
        return res;
    }
};

1]=pre[0]+nums[0];
for(int i=2;i<=n;i++){
pre[i]=pre[i-1]+nums[i-1];
if(mp.find(pre[i]%k)!=mp.end()){
res+=mp[pre[i]%k];
}
mp[pre[i-1]%k]++; // 因为个数限制。
}
if(res==0)return false;
else return true;

}

};






## [930. 和相同的二元子数组](https://leetcode.cn/problems/binary-subarrays-with-sum/):前缀和+哈希表

```c++
class Solution {
public:
    int numSubarraysWithSum(vector<int>& nums, int goal) {
        map<int,int>mp;
        mp[0]=1;
        int n=nums.size();
        int pre[n+1];
        pre[0]=0;
        int res=0;
        for(int i=1;i<=n;i++){
            pre[i]=pre[i-1]+nums[i-1];
            if(mp.find(pre[i]-goal)!=mp.end()){
                res+=mp[pre[i]-goal];
            }
            mp[pre[i]]++;           
        }
        return res;

    }
};

904. 水果成篮:滑动窗口+哈希表

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int res = 0;
        int n =fruits.size();
        int right=0,left=0;
        set<int>sc;
        map<int,int>mp;
        for(;right<n;right++){
            sc.insert(fruits[right]);
            mp[fruits[right]]++;
            while(sc.size()>2){
                mp[fruits[left]]--;
                if(mp[fruits[left]]==0)sc.erase(fruits[left]);
                left++;
            }
            res=max(res,right-left+1);
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值