leetCode刷题记录(五月)

一个月没更新了。。
最近近况:
h公司试用期的第二个月。压力挺重,每天基本都是各种加班,9点或者十点半的班车,甚至错过班车,从东莞回到宿舍都是10点以后的事。。实在没这个精力每天晚上都跑来这更新一下(吐槽一下公司内网保密不能更博,要不然平时上班时间闲暇的时候还可以更一下)
打卡还是有打的,一次性把这个月的所有题目都发出来就算了。。图也懒得贴了,主要写解题思路以及贴代码

2020.5.1 合并两个有序链表(简单)
思路:略

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode head(0);
        ListNode* cur=&head;
        while(l1!=NULL && l2!=NULL){
            if(l1->val>l2->val)
            {
                cur->next=l2;
                l2=l2->next;
                cur=cur->next;
            }else{
                cur->next=l1;
                l1=l1->next;
                cur=cur->next;
            }
        }
        if(l1!=NULL)
            cur->next=l1;
        if(l2!=NULL)
            cur->next=l2;
        return head.next;
    }
};

2020.5.2 无重复字符的最长子串(中等)
思路:双指针 + set,如果set中已存在,则更新当前长度,同时移除重复字符自身以及之前的其他字符,统计新的子串长度(突然发现这道题在之前面试考过,当时是手写代码,然后面试官还给我说错题意了,按他的意思给了有问题的答案,在面试快结束之后才意识到不对,重新更正了一遍,并且指出错误,有点怀疑是故意给我设的坑)

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        set<char> chars;
        int L=0,R=0,maxLength=0;
        while(R>=L && R<s.size()){
            if(chars.find(s[R])==chars.end()){
                chars.insert(s[R]);
                maxLength=max(maxLength,R-L+1);
                R++;
            }else{
                chars.erase(s[L]);
                L++;
            }
        }
        return maxLength;
    }
};

2020.5.3 最大子序和(简单)
思路:从L到R的求和等价于0-R的求和 - 0-L的求和

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int L=0,R=1,res=nums[0];
        vector<int> sums(nums.size()+1,0);
        for(int i=0;i<nums.size();i++){
            sums[i+1]=sums[i]+nums[i];
        }
        while(L<=R && R<=nums.size()){
            if(R>L && sums[R]-sums[L]>res)
                res=sums[R]-sums[L];
            cout<<L<<","<<R<<","<<sums[R] - sums[L]<<endl;
            while(R<sums.size() && R>L && sums[R]-sums[L]<sums[R]-sums[L+1])
            {
                L++;
            }
            if((R+1<sums.size() && sums[R+1]-sums[L]>0)|| L>=R)
                R++;
            else
                L++;
            
        }
        return res;
    }
};

2020.5.4 跳跃游戏(困难)
思路:
当处在某个位置x时,这个位置的值是y则代表可以跳到x+1 - x+y这些范围之内,然后通过BFS
和是否访问的标志进行去重即可,当当前格子加上格子的值可以到达最后一个位置,则说明是最终解(到达终点是必然的,但是第一个到达终点的必然是步数最少的)

class Solution {
public:
	int jump(vector<int>& nums) {
		if(nums.size()<=1)
            return 0;
        queue<int> q,steps;
        vector<int> visited(nums.size(),0);
        q.push(0);
        steps.push(0);
        while(!q.empty()){
            int pos=q.front();
            int lastStep=steps.front();
            q.pop();
            steps.pop();
            if(visited[pos])
                continue;
            visited[pos]=1;
            if(pos+nums[pos]>=nums.size()-1)
                return lastStep+1;
            for(int i=nums[pos];i>=1;i--)
            {
                q.push(pos+i);
                steps.push(lastStep+1);
            }
        }
        return 0;
	}
};

2020.5.5 验证二叉搜索树(中等)
思路:二叉搜索树:父节点比左节点值大,小于右节点值
同时,左节点和右节点也有另一个边界,如对于父节点的右节点的左子节点,值是在父节点和父节点的右节点之间
验证二叉搜索树的合法性:可以通过递归即可,每次为当前节点设定其范围值,以验证当前节点和当前节点的子节点

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        if(root==NULL)
            return 1;
        return check(root->left,root->val,LONG_MIN)&&check(root->right,LONG_MAX,root->val);
    }
    bool check(TreeNode* cur,long max,long min){
        if(cur==NULL)
            return 1;
        if(cur->val>min && cur->val<max){
            return check(cur->left,cur->val,min) && check(cur->right,max,cur->val);
        }else
            return 0;
    }
};

2020.5.6 最低票价(中等)
思路:动态规划,从价格低的票价开始,类似爬楼梯,每次只能爬固定的台阶

class Solution {
public:
	int mincostTickets(vector<int>& days, vector<int>& costs) {
		int costdays[3] = { 1, 7, 30 };
		vector<int> dp(366, 0);
		int day = 1;
		for (int date : days){
			while (day < date)
			{
                dp[day] = dp[day - 1];
                day++;
            }
			int cost = INT_MAX;
			for (int i = 0; i < 3; i++){
				int start = max(0, day - costdays[i]);
				cost = min(cost, dp[start] + costs[i]);
			}
			dp[day] = cost;
			day++;
		}

		return dp[days.back()];
	}
};

2020.5.7 另一个树的子树(简单)
思路:BFS,当遇到节点值和子树节点的值相同时,分别进行BFS

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        queue<TreeNode* > q;
        q.push(s);
        while(!q.empty()){
            auto f=q.front();
            q.pop();
            if(f->val==t->val){
                queue<TreeNode*> qf,qt;
                qf.push(f);
                qt.push(t);
                bool equal=1;
                while(!qt.empty() &&!qf.empty()){
                    auto tf=qf.front();
                    auto tt=qt.front();
                    //cout<val<<","<val<
                    qf.pop();
                    qt.pop();
                    if(tf->val!=tt->val)
                    {
                        equal=0;
                        break;
                    }
                    if(tt->left!=NULL)
                        qt.push(tt->left);
                    if(tt->right!=NULL)
                        qt.push(tt->right);
                    if(tf->left!=NULL)
                        qf.push(tf->left);
                    if(tf->right!=NULL)
                        qf.push(tf->right);
                }
                if(equal && qf.empty() && qt.empty())
                    return true;
            }
            if(f->left!=NULL)
                q.push(f->left);
            if(f->right!=NULL)
                q.push(f->right);
        }
        return false;
    }
};

2020.5.8 最大正方形(中等)
思路:动态规划
dp[i][j]表示以这个位置为右下角的正方形边长
假设当前格子的值是1,则最大长度为dp[i-1][j],dp[i][j-1],dp[i-1][j-1]这三个值中的最小值 +1

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if(matrix.size()==0 || matrix[0].size()==0)
            return 0;
        vector<vector<int>> dp(matrix.size(),vector<int>(matrix[0].size(),0));
        for(int i=0;i<matrix.size();i++)
            dp[i][0]=matrix[i][0]=='1';
        for(int i=0;i<matrix[0].size();i++)
            dp[0][i]=matrix[0][i]=='1';
        int n=0;
        for(int y=0;y<matrix.size();y++){
            for(int x=0;x<matrix[0].size();x++){
                if(matrix[y][x]=='0')
                    continue;
                if(y==0 || x==0)
                {
                    n=max(n,1);
                    continue;
                }
                dp[y][x]=min(min(dp[y-1][x],dp[y][x-1]),dp[y-1][x-1])+1;
                n=max(n,dp[y][x]);
            }
        }
        return n*n;
    }
};

2020.5.9 x的平方根(简单)
思路:
递归,不断逼近左右边界

class Solution {
public:
    int mySqrt(int x) {
        if(x<=1)
            return x;
        return search(x,1,x);
    }
    int search(int x,int L,int R){
        if(R-L<=1)
            return L;
        int Mid=L+ (R-L)/2;
        if(Mid  > x/Mid)
            R=Mid;
        else if(Mid < x/Mid)
            L=Mid;
        else
            return Mid;
        return search(x,L,R);
    }
};

2020.5.10 二叉树的最近公共祖先(中等)
思路:遇到根节点相同的时候进行BFS比较

class Solution {
public:
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
		stack<TreeNode*> s;
		stack<TreeNode*> ps, qs;
		set<int> visited;
		s.push(root);
		while (!s.empty()){
			auto n = s.top();
			visited.insert(n->val);
            if (n->val == p->val && ps.empty()){
				ps = s;
			}
			if (n->val == q->val && qs.empty())
			{
				qs = s;
			}
			if(!qs.empty() && !ps.empty())
                break;
			
			if (n->left != NULL && visited.find(n->left->val)==visited.end())
			{
				s.push(n->left);
				continue;
			}
			if (n->right != NULL && visited.find(n->right->val)==visited.end())
			{
				s.push(n->right);
				continue;
			}
			s.pop();
		}
		while (ps.top()->val != qs.top()->val){
			if (qs.size() > ps.size())
				qs.pop();
			else
				ps.pop();
		}
		return qs.top();
	}
};

2020.5.11 Pow(x,n) (中等)
思路:首先:x的n次幂
n可以很大,所以这题不能无脑的乘n次
然后对于负数:可以变成1/x的 -n次方
对于x的n次幂,同样还可转换成 x*x 的 n/2次幂,再根据奇偶乘以x即可,写成递归形式

class Solution {
public:
    double myPow(double x, int n) {
        if(n==INT_MIN)
            return myPow(x*x,n/2);
        if(n==1)
            return x;
        else if(n==0)
            return 1;
        else if(n<0)
            return myPow(1.0/x,-n);
        else{
            if(n%2!=0)
                return x*myPow(x*x,n/2);
            else            
                return  myPow(x*x,n/2);
        }        
    }
};

2020.5.12 最小栈(简单)
思路:
双栈或双vector都可

class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {
        
    }
    vector<int> stack;
    vector<int> mins;
    void push(int x) {
        stack.push_back(x);
        if(mins.size()==0)
            mins.push_back(x);
        else
            mins.push_back(min(x,mins.back()));
        
    }
    
    void pop() {
        stack.pop_back();
        mins.pop_back();
    }
    
    int top() {
        return stack.back();
    }
    
    int getMin() {
        return mins.back();
    }
};

2020.5.13 二叉树的层序遍历(中等)
思路:BFS,存层数和节点

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if(root==NULL)
            return res;
        queue<pair<TreeNode*,int>> q;
        q.push({root,0});
        while(!q.empty()){
            auto f=q.front();
            q.pop();
            if(res.size()>f.second)
                res[f.second].push_back(f.first->val);
            else
                res.push_back(vector<int>(1,f.first->val));
            if(f.first->left!=NULL)
                q.push({f.first->left,f.second+1});
            if(f.first->right!=NULL)
                q.push({f.first->right,f.second+1});
        }
        return res;
    }
};

2020.5.14 只出现一次的数字(简单)
思路:位运算,进行异或’^’,因为所有数字中只有一个出现了一次,其他都出现了两次,两次的和自身异或会变成0,而一次的不会,所以仅需要对所有数字进行异或即可

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int i=0;
        for(int n:nums)
            i^=n;
        return i;
    }
};

2020.5.15 和为K的子数组(中等)
思路:哈希表
和为K的子数组,L-R数组的和 可以通过从0-R 和 0-L相减得到
只需要统计从0到某个位置的和S,有多少个数组,及记录其索引,同时找到对应的值S+K,找出对应的索引,两两进行组合可得到和为K的子数组个数

class Solution {
public:
	int subarraySum(vector<int>& nums, int k) {
		vector<int> sum;
        if(nums.size()<=0)
            return 0;
        if(nums.size()<=1)
            return nums[0]==k;
		sum.push_back(0);
		map<int, vector<int>> sumMap;
		for (int i : nums){
			sum.push_back(sum.back() + i);
			sumMap[sum.back()].push_back(sum.size() - 1);
		}
        sumMap[0].push_back(0);
		int res = 0;
		for (pair<int, vector<int>> p : sumMap){
			int LSum = p.first;
			int RSum = k + LSum;

			if (sumMap.find(RSum) == sumMap.end())
				continue;
            
			int L = 0, R = 0;
			//vector LIndex = sumMap[LSum], RIndex = sumMap[RSum];
			while (L < sumMap[LSum].size() && R<sumMap[RSum].size()){
                if (sumMap[LSum][L]>=sumMap[RSum][R])
				{
                    R++;
                    if(k!=0)
                        continue;
                }
				res += sumMap[RSum].size() - R;
				L++;
			}

		}
		//sum(R)-sum(L)=Σ(L,R]
		return res;
	}
};

2020.5.16 K个一组翻转链表(困难)
思路:栈(或用长度为K+1的vector替代)
首个为上次的末尾节点/本次的头节点的上个节点
之后K个是待翻转的节点

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        if(k<=1)
            return head;
        vector<ListNode*> Nodes(k+1,NULL);
        ListNode* head0=new ListNode(0);
        Nodes[0]=head0;
        int index=1;
        ListNode* cur=head;
        while(cur!=NULL){            
            Nodes[index++]=cur;
            cur=cur->next;
            
            if(index>k){
                ListNode* nextNode=cur;
                ListNode* cur1=Nodes[--index];
                while(index>0){
                    cur1->next=Nodes[--index];
                    if(index>0)
                        cur1=cur1->next;
                }
                
                cur1->next=nextNode;
                Nodes[0]->next=Nodes[k];
                index=1;
                Nodes[0]=cur1;
            }                        
        }
        return head0->next;
    }
};

2020.5.17 课程表II(中等)
思路:
维护两个vector
一个是先决条件:
学习了预备课程后,可以使下个课程所需要的条件-1
另一个是课程需要多少门前置预备课程
每次从前置预备课程vecotr中找到为0的课程进行学习,同时对其影响到的其他课程进行前置条件数量-1

class Solution {
public:
	vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
		vector<list<int>> prerequires(numCourses, list<int>());
		vector<int> requireCnt(numCourses, 0);
		for (int i = 0; i < prerequisites.size(); i++){
			prerequires[prerequisites[i][1]].push_back(prerequisites[i][0]);
			requireCnt[prerequisites[i][0]]++;
		}
		queue<int> q;
		vector<int> res;
		for (int i = 0; i < numCourses; i++)
		{
			if (requireCnt[i] == 0)
			{
				q.push(i);
			}
		}
		if (q.empty())
			return res;
		while (!q.empty()){
			int canlearned = q.front();
			q.pop();
			res.push_back(canlearned);
            for (int i : prerequires[canlearned])
			{
            	if (requireCnt[i] > 0){
					requireCnt[i]--;
					if (requireCnt[i] == 0){
						q.push(i);
					}
				}
			}
        }
		if (res.size() < numCourses)
			return vector<int>();
		return res;
	}
};

2020.5.18 乘积最大子数组(中等)
思路:动态规划
维护二维vector,分别存储最大和最小值

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int dp[nums.size()+1][2];
        dp[0][0]=1;
        dp[0][1]=1;
        int res=INT_MIN;
        for(int i=1;i<=nums.size();i++){
            int curNum=nums[i-1];
            dp[i][0]=max(dp[i-1][0]*curNum,max(dp[i-1][1]*curNum,curNum));
            dp[i][1]=min(dp[i-1][0]*curNum,min(dp[i-1][1]*curNum,curNum));
            res=max(dp[i][0],res);
        }
        return res;
    }
};

2020.5.19 验证回文字符串II(简单)
思路:双指针+递归
因为字符串最多删一个字符串,可以用一个bool表示
同时,双指针,一个最左一个最右,两个重合或者相遇时,则代表这个字符串回文串判断完成,遇到不同的时候,第一次可以删除,则返回删除左边或删除右边两个同时的递归,如果不可删除,则返回false

class Solution {
public:
    bool candelete=1;
    bool validPalindrome(string str) {
        return validPalindrome(str,0,str.size()-1);
    }

    bool validPalindrome(string str,int L,int R){
        while(L<R && str[L]==str[R]){
            L++;
            R--;
        }
        if(L>=R)
            return 1;
        if(!candelete)
            return 0;
        candelete=0;
        return validPalindrome(str,L,R-1)||validPalindrome(str,L+1,R);
    }
};

2020.5.20 每个元音包含偶数次的最长子字符串(中等)
思路:
aeiou总共有5个元音字母,可以使用一个char对其表示,其中1-5位分别表示对应字母的奇偶状态,为0时则为偶,为1时则为奇,对应的是按位进行异或操作
这个char总共有2^5(32)种状态,存储这每一种状态出现时的位置,下一次出现时,这两个位置之间的元音字符必定为偶数

class Solution {
public:
    int findTheLongestSubstring(string s) {
        int ans = 0, status = 0, n = s.length();
        vector<int> pos(1 << 5, -1);
        pos[0] = 0;
        for (int i = 0; i < n; ++i) {
            if (s[i] == 'a') {
                status ^= 1<<0;
            } else if (s[i] == 'e') {
                status ^= 1<<1;
            } else if (s[i] == 'i') {
                status ^= 1<<2;
            } else if (s[i] == 'o') {
                status ^= 1<<3;
            } else if (s[i] == 'u') {
                status ^= 1<<4;
            }
            if (~pos[status]) {
                ans = max(ans, i + 1 - pos[status]);
            } else {
                pos[status] = i + 1;
            }
        }
        return ans;
    }
};

2020.5.21 最长回文子串(中等)
思路:从中间开始往两边扩张,看能达到最远的长度,分为两种:初始左右指针相同,初始左右指针差1

class Solution {
public:
    string longestPalindrome(string s) {
        string res="";
        for(int i=0;i<s.size();i++){
            int L=i,R=i;
            while (L-1>=0 && R+1<s.size() && s[L-1]==s[R+1])
            {
                L--;
                R++;
            }
            if(R-L+1>res.size())
            {
                res=s.substr(L,R-L+1);
            }
            if(i+1<s.size() && s[i]==s[i+1]){
                L=i,R=i+1;
                while(L-1>=0 && R+1<s.size() && s[L-1]==s[R+1]){
                    L--;
                    R++;
                }
                if(R-L+1>res.size()){
                    res=s.substr(L,R-L+1);
                }
            }
        }
        return res;
    }
};

2020.5.22 从前序与中序遍历序列构造二叉树
思路:
前序:
根左右
中序:
左根右
即:
当我们拿到前序第一个时,可以确认根节点的值,可以在中序找到对应根节点的索引,而根节点左边全属于当前根节点的左部分,根节点的索引+1恰好反应了前序遍历种左部分的最后一个节点的位置,以此规律对序列进行拆分递归,最终还原得到二叉树

class Solution {
public:
	TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
		if (preorder.size() <= 0)
			return NULL;
		return build(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1);
	}
	TreeNode* build(vector<int>& pre, vector<int>& in, int preL, int preR, int inL, int inR) {

		if (preL == preR)
			return new TreeNode(pre[preL]);
		TreeNode* root = new TreeNode(pre[preL]);
		int nextinSplit = inL;
		while (nextinSplit < inR && in[nextinSplit] != pre[preL])
			nextinSplit++;
		int LeftPart = nextinSplit - inL;
		if (LeftPart)
			root->left = build(pre, in, preL + 1, preL + LeftPart, inL, nextinSplit - 1);
		int RightPart = inR - nextinSplit;
		if (RightPart)
			root->right = build(pre, in, preR - RightPart+1, preR, nextinSplit + 1, inR);
		return root;
	}
};

2020.5.23 最小覆盖子串(困难)
思路:用哈希表存储t中各字符出现的次数m,再用LR双指针进行滑动窗口
遍历s字符串,每一截的开始点为在t中出现过的字符的位置,当m中各字符对应的次数均小于等于0时,则说明此时包含字符串t,如果次数小于0,说明前面的可以匀一段到后面去,这时需对左指针进行检查
(比较繁琐的一题,但是按照很常规的想法就能做出来了)

class Solution {
public:
	string minWindow(string s, string t) {
		if (t == "")
			return "";

		map<char, int> m;
		for (char c : t)
			m[c]++;
		int L = 0;
		string res = "";
		while (L < s.size() && m.find(s[L]) == m.end())
			L++;
		if (L >= s.size())
			return "";
		m[s[L]]--;
		int R = L;
		bool isContains = 0;
		while (R < s.size()) {
			isContains = 1;
			for (pair<char, int> p : m) {
				if (p.second > 0)
				{
					isContains = 0;
					break;
				}
			}
            //cout<
			if (isContains) {
				if (res=="" || res.size() > R - L + 1)
					res = s.substr(L, R - L + 1);

				m[s[L]]++;
				L++;
				while (L<=R && m.find(s[L]) == m.end())
					L++;
				continue;
			}
			else {
				R++;
                while (R < s.size() && m.find(s[R]) == m.end())
					R++;
				if (R >= s.size())
					break;
				m[s[R]]--;
                
			}
		}
		return res;
	}
};

2020.5.24 寻找两个正序数组的中位数(困难)
思路:直接优先队列

class Solution {
public:
	double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
		priority_queue<int> q;
		for (int i : nums1)
			q.push(i);
		for (int i : nums2)
			q.push(i);
		int mid = (q.size()+1) / 2;
		int size = q.size();
		int cnt = 0;
		double m;
		while (cnt < mid)
		{
			m = q.top();
			q.pop();
			cnt++;
		}
		if (size % 2 == 0)
		{
			m += q.top();
			m /= 2.0;
		}
		return m;
	}
};

2020.5.25 LRU缓存机制(中等)
思路:需要插入顺序与存储顺序保持一致的map,这个c++里没提供,但是java里有个LinkedHashMap
当时赶着去打球,就没时间仔细想了,用的java版:

class LRUCache {

		private LinkedHashMap<Integer, Integer> map;
		int MaxCount;
		int Count;

		public LRUCache(int capacity) {
			map = new LinkedHashMap<>();
			MaxCount = capacity;
			Count = 0;
		}

		public int get(int key) {
			Integer value = map.remove(key);
			if (value != null) {
				map.put(key, value);
				return value;
			} else
				return -1;
		}

		public void put(int key, int value) {
			if (map.containsKey(key)) {
				map.remove(key);
				map.put(key, value);
				return;
			}
			map.put(key, value);
			Count++;
			if (Count > MaxCount) {
				Count--;
				Integer firstKey = (Integer) map.keySet().toArray()[0];
				map.remove(firstKey);
			}
		}
	}
/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

c++中实现类似功能的方法:
用list链表加上value为迭代器的map

2020.5.26 寻找重复数(中等)
思路:用set或者数组也行,因为nums中数字是在1-n(n为数组长度)
只需要遍历一遍这个数组,统计某个数字出现的次数,次数不为0则找到重复数
下面贴的是懒方法

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        set<int> s;
        for(int i:nums){
            if(s.find(i)==s.end())
                s.insert(i);
            else
            {
                return i;
            }
            
        }
        return 0;
    }
};

2020.5.27 和可被K整除的子数组(中等)
思路:类似和为K的子数组
当前求和进行取模,能反映出有多少个位置,这些位置的和都满足与K取模等于a的条件,这些数之中两两可组成一个子数组,而子数组之间的和,必为可被K整除的数

class Solution {
public:
    int subarraysDivByK(vector<int>& A, int K) {
        unordered_map<int, int> record = {{0, 1}};
        int sum = 0;
        for (int elem: A) {
            sum += elem;
            // 注意 C++ 取模的特殊性,当被除数为负数时取模结果为负数,需要纠正
            int modulus = (sum % K + K) % K;
            ++record[modulus];
        }

        int ans = 0;
        for (auto [x, cx]: record) {
            ans += cx * (cx - 1) / 2;
        }
        return ans;
    }
};

2020.5.28 字符串解码(中等)
思路:双栈,一个存储栈顶的字符串,一个存储重复次数

class Solution {
public:
    string decodeString(string s) {
        stack<string> strstack;
        stack<int> repeatstack;
        string tmp = "",num = "";
        for(int i=0;i<s.size();i++){
            if(s[i]=='[')
            {
                strstack.push(tmp);
                tmp="";
                int repeatcnt=stoi(num);
                num="";
                repeatstack.push(repeatcnt);
            }
            else if(s[i]==']'){
                string top=strstack.empty()?"":strstack.top();
                strstack.pop();

                int repeat = repeatstack.top();
                repeatstack.pop();
                string str="";
                while(repeat > 0)
                {
                    str += tmp;
                    repeat--;
                }
                tmp = top + str;
            }
            else if(isdigit(s[i])){
                num += s[i];
            }
            else
            {
                tmp += s[i];
            }            
        }
        return tmp;
        
    }
};

2020.5.29 打家劫舍(简单)
思路:动态规划,条件是跨过下一个值

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() <= 0)
            return 0;
        if(nums.size() <= 1)
            return nums[0];
        if(nums.size() <= 2)
            return max(nums[0], nums[1]);
        if(nums.size() <= 3)
            return max(nums[0] + nums[2], nums[1]);
        vector<int> dp(nums.size(), 0);
        dp[0] = nums[0];
        dp[1] = nums[1];
        dp[2] = nums[0] + nums[2];
        for(int i = 3; i < dp.size(); i++)
        {
            dp[i] = max(dp[i], max(dp[i-2],dp[i-3]) + nums[i]);
        }
        return max(dp[nums.size() - 1], dp[nums.size() - 2]);
    }
};

2020.5.30 柱状图中最大的矩形(困难)
思路:单调栈
对于每一个索引i,维护一个左指针,以及右指针,使其对于i是最低高度时的极限左右边界
维护单调栈:当栈顶对应的高度比当前i对应的高度满足大于等于的关系,不满足单调性时,确定i的左边界,同时弹出,直到栈空或者栈顶对应高度比当前对应高度小时
同时更新i的左索引并入栈
维护完成后,遍历每个位置,计算其左右边界总共的长度乘以当前的高度

class Solution {
public:
	int largestRectangleArea(vector<int>& heights) {
		vector<int> left(heights.size()), right(heights.size(), heights.size());
		int res = 0;
		stack<int> s;
		for (int i = 0; i < heights.size(); i++){
			while (!s.empty() && heights[s.top()] >= heights[i]){
				right[s.top()] = i;
				s.pop();
			}
			left[i] = s.empty() ? -1 : s.top();
			s.push(i);
		}
		for (int i = 0; i < heights.size(); i++){
			res = max(res, (right[i] - left[i] - 1)* heights[i]);
		}
		return res;
	}
};

//之前用递归,java能过但是c++超时了。。

2020.5.31 对称二叉树(简单)
思路:两个BFS,但是要注意对称,即左部分的右部分与右部分的左部分相比较

class Solution {
public:
	bool isSymmetric(TreeNode* root) {
		if (root == NULL)
			return 1;
		if (root->left == NULL || root->right == NULL)
		{
			return root->left == NULL && root->right == NULL;
		}
		queue<TreeNode*> ql, qr;
		ql.push(root->left);
		qr.push(root->right);
		while (!ql.empty() && !qr.empty()){
			if (ql.size() != qr.size())
				return 0;
			TreeNode* l = ql.front();
			TreeNode* r = qr.front();
			ql.pop();
			qr.pop();
			if (l->val != r->val){
				return 0;
			}
			if (l->left == NULL || r->right == NULL){
				if (!(l->left == NULL && r->right == NULL))
				{
					return 0;
				}
			}
			else{
				ql.push(l->left);
				qr.push(r->right);
			}
			if (l->right == NULL || r->left == NULL){
				if (!(l->right == NULL && r->left == NULL)){
					return 0;
				}
			}
			else{
				ql.push(l->right);
				qr.push(r->left);
			}
		}
		return 1;
	}
};

目前,总算打卡完5月了。。贴个最终图:
leetCode刷题记录(五月)_第1张图片
真是累死了。。最近更博没啥动力(最主要平时上班没法更)

你可能感兴趣的:(leetCode,数据结构相关,c++)