Problem: [496. 下一个更大元素 I]
思路
Code
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
map<int,int> hashMap;
stack<int> stk;//单调栈
for(int i=nums2.size()-1;i>=0;i--){
while(!stk.empty()&&nums2[i]>=stk.top())
stk.pop();
if(!stk.empty()){
hashMap[nums2[i]]=stk.top();
}
else{
hashMap[nums2[i]]=-1;
}
stk.push(nums2[i]);
}
vector<int> ans;
for(int i=0;i<nums1.size();i++){
ans.push_back(hashMap[nums1[i]]);
}
return ans;
}
};
Problem: [2866. 美丽塔 II]
思路
Code
class Solution {
public:
long long maximumSumOfHeights(vector<int>& maxHeights) {
vector<long long> pre(maxHeights.size());//以i为山峰时,左侧的高度和最大值(包括自身)
vector<long long> suf(maxHeights.size());//以i为山峰时,右侧的高度和最大值(包括自身)
stack<long long> stk1;//单调栈 帮助构建pre 存下标
stack<long long> stk2;//单调栈 帮助构建suf 存下标
//构建pre
for(long long i=0;i<maxHeights.size();i++){
while(!stk1.empty()&&maxHeights[i]<maxHeights[stk1.top()]){
stk1.pop();
}
if(i>0&&maxHeights[i]>maxHeights[i-1]){
pre[i]=maxHeights[i]+pre[i-1];
}
else{
if(!stk1.empty())
pre[i]=maxHeights[i]*(i-stk1.top())+pre[stk1.top()];
else
pre[i]=maxHeights[i]*(i+1);
}
stk1.push(i);
}
//构建suf
for(long long i=maxHeights.size()-1;i>=0;i--){
while(!stk2.empty()&&maxHeights[i]<maxHeights[stk2.top()]){
stk2.pop();
}
if(i<maxHeights.size()-1&&maxHeights[i]>maxHeights[i+1]){
suf[i]=maxHeights[i]+suf[i+1];
}
else{
if(!stk2.empty())
suf[i]=maxHeights[i]*(stk2.top()-i)+suf[stk2.top()];
else
suf[i]=maxHeights[i]*(maxHeights.size()-i);
}
stk2.push(i);
}
long long maxH=0;
for(long long i=0;i<maxHeights.size();i++){
maxH=max(maxH,pre[i]+suf[i]-maxHeights[i]);
}
return maxH;
}
};
990. 等式方程的可满足性
思路
Code
class Solution {
public:
int N=500;
int father[500];
void Initial(){
for(int i=0;i<N;i++){
father[i]=i;
}
}
int FindRoot(int x){
return x==father[x]?FindRoot(father[x]);
}
//在同一集合返回true
void Union(int x,int y){
int xF=FindRoot(x);
int yF=FindRoot(y);
if(xF!=yF)
father[xF]=yF;
}
bool equationsPossible(vector<string>& equations) {
Initial();
for(int i=0;i<equations.size();i++){
string str=equations[i];
char c1=str[0];
char c2=str[3];
if(str[1]=='='){
Union(c1,c2);
}
}
for(int i=0;i<equations.size();i++){
string str=equations[i];
char c1=str[0];
char c2=str[3];
if(str[1]=='!')
if(FindRoot(c1)==FindRoot(c2))
return false;
}
return true;
}
};
Problem: [LCP 399. 除法求值]
思路
Code
class Solution {
public:
const static int N=500;
int father[N];
double weight[N];//表示该点与其父节点的倍数关系
//初始化
void Initial(){
for(int i=0;i<N;i++){
father[i]=i;
weight[i]=1.0;
}
}
//找根,同时压缩路径(压缩路径后,x指向其根节点)
int FindRoot(int x){
if(x==father[x])
return x;
int orginFather=father[x];
father[x]=FindRoot(father[x]);
weight[x]=weight[x]*weight[orginFather];
return father[x];
}
//合并
void Union(int x,int y,double value){
int xRoot=FindRoot(x);
int yRoot=FindRoot(y);
//FindRoot操作后,x和y都会直接指向其各自树的树根
if(xRoot!=yRoot){
father[xRoot]=yRoot;
weight[xRoot]=weight[y]*value/weight[x];
}
}
//计算x/y,若无法计算(即x与y不在同一集合中)则返回-1.0
double Calculate(int x,int y){
int xRoot=FindRoot(x);
int yRoot=FindRoot(y);
//FindRoot之后,x和y都指向该集合的根节点
if(xRoot!=yRoot){
return -1.0;
}
return weight[x]/weight[y];
}
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
Initial();
vector<double> result;
//建立string和id的映射,同时合并
map<string,int> hashMap;
int id=0;
for(int i=0;i<equations.size();i++){
string str1=equations[i][0];
string str2=equations[i][1];
if(hashMap.find(str1)==hashMap.end()){
hashMap[str1]=id++;
}
if(hashMap.find(str2)==hashMap.end()){
hashMap[str2]=id++;
}
Union(hashMap[str1],hashMap[str2],values[i]);//合并
}
for(int i=0;i<queries.size();i++){
string str1=queries[i][0];
string str2=queries[i][1];
if(hashMap.find(str1)==hashMap.end()||hashMap.find(str2)==hashMap.end()){
result.push_back(-1.0);
}
else{
result.push_back(Calculate(hashMap[str1],hashMap[str2]));
}
}
return result;
}
};
Problem: [LCP 07. 传递信息]
思路
Code
class Solution {
public:
int ans=0;
vector<int> Adj[20];
void DFS(int i,int n,int k,int curK){//当前结点 结点总数 k 当前轮数
if(curK>k){
return;
}
if(i==n-1&&curK==k){
ans++;
}
for(int j=0;j<Adj[i].size();j++){
DFS(Adj[i][j],n,k,curK+1);
}
}
int numWays(int n, vector<vector<int>>& relation, int k) {
for(int i=0;i<relation.size();i++){
Adj[relation[i][0]].push_back(relation[i][1]);
}
DFS(0,n,k,0);
return ans;
}
};
Problem: [133. 克隆图]
思路
Code
/*
// Definition for a Node.
class Node {
public:
int val;
vector neighbors;
Node() {
val = 0;
neighbors = vector();
}
Node(int _val) {
val = _val;
neighbors = vector();
}
Node(int _val, vector _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
*/
class Solution {
public:
map<Node*,Node*> hashMap;//key:原图结点 value:克隆图对应的结点
bool visited[101]={0};
Node* DFS(Node* node){//返回当前遍历的结点的克隆结点
if(node==nullptr){
return nullptr;
}
visited[node->val]=true;
Node* cloneNode=new Node(node->val);
hashMap[node]=cloneNode;
for(int i=0;i<node->neighbors.size();i++){
cout<<node->neighbors[i]->val;
if(!visited[node->neighbors[i]->val]){//未遍历,则遍历,并且返回该结点的克隆结点
cloneNode->neighbors.push_back(DFS(node->neighbors[i]));
}
else{//之前遍历过,我们不再遍历,但是存在当前结点到该点的一条边,我们需要把边构造出来
cloneNode->neighbors.push_back(hashMap[node->neighbors[i]]);
}
}
return cloneNode;
}
Node* cloneGraph(Node* node) {
return DFS(node);
}
};
Problem: [207. 课程表]
思路
Code
class Solution {
public:
vector<int> Adj[2000];
int inDegree[2000];
bool topo(int numCourses, vector<vector<int>>& prerequisites){
queue<int> q;
for(int i=0;i<numCourses;i++){
if(inDegree[i]==0)
q.push(i);
}
int total=0;
while(!q.empty()){
int n=q.front();
q.pop();
total++;
for(int i=0;i<Adj[n].size();i++){
inDegree[Adj[n][i]]--;
if(inDegree[Adj[n][i]]==0){
q.push(Adj[n][i]);
}
}
}
return total==numCourses;
}
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
if(prerequisites.size()==0)
return true;
for(int i=0;i<prerequisites.size();i++){
Adj[prerequisites[i][1]].push_back(prerequisites[i][0]);
inDegree[prerequisites[i][0]]++;
}
return topo(numCourses,prerequisites);
}
};
Problem: [261. 以图判树]
思路
class Solution {
public:
int N;
int father[2000];
void initial(){
for(int i=0;i<N;i++)
father[i]=i;
}
int FindFather(int x){
return x==father[x]?x:FindFather(father[x]);
}
bool Union(int x,int y){
int xFather=FindFather(x);
int yFather=FindFather(y);
if(xFather!=yFather){
father[xFather]=yFather;
return false;
}
else
return true;
}
int TotalUnions(){
int sum=0;
for(int i=0;i<N;i++)
if(father[i]==i)
sum++;
return sum;
}
bool validTree(int n, vector<vector<int>>& edges) {
N=n;
initial();
//判断是否存在环
for(int i=0;i<edges.size();i++){
int start=edges[i][0];
int end=edges[i][1];
bool flag=Union(start,end);
if(flag)
return false;//存在环返回false
}
//判断连通分量是否只有1个
if(TotalUnions()==1)
return true;
else
return false;
}
};
Problem: [277. 搜寻名人]
思路
/* The knows API is defined for you.
bool knows(int a, int b); */
class Solution {
public:
int findCelebrity(int n) {
vector visited(n,0);
for(int i=0;i
Code
/* The knows API is defined for you.
bool knows(int a, int b); */
class Solution {
public:
int findCelebrity(int n) {
//在n次循环后,必当能够排除n-1个不同的顶点(模拟迭代过程可看出来),且candidate最后存放的是我们暂时不能排除那个顶点
int candidate=0;
for(int i=0;i<n;i++){
if(knows(candidate,i)){
candidate=i;
}
}
//检查candidate是否是候选人
for(int i=0;i<n;i++){
if(i!=candidate){
if(knows(candidate,i)||!knows(i,candidate)){
candidate=-1;
break;
}
}
}
return candidate;
}
};
Problem: [930. 和相同的二元子数组]
思路
Code
class Solution {
public:
int numSubarraysWithSum(vector<int>& nums, int goal) {
int preSum[3*10000+1]={0};//preSum[i] nums前i个数之和
for(int i=1;i<=nums.size();i++){
preSum[i]=preSum[i-1]+nums[i-1];
}
/*
寻找满足preSum[j]-preSum[i]==goal(i:0~n-1 j:1~n)的所有i和j即可
即preSum[j]-goal=preSum[i](i
int ans=0;
map<int,int> hashMap;//key:数值preSum[i](i
hashMap[0]=1;
for(int j=1;j<=nums.size();j++){//枚举右端点
if(hashMap.find(preSum[j]-goal)!=hashMap.end()){
ans+=hashMap[preSum[j]-goal];
}
hashMap[preSum[j]]++;
}
return ans;
}
};
Problem: [2845. 统计趣味子数组的数目]
思路
Code
class Solution {
public:
long long countInterestingSubarrays(vector<int>& nums, int modulo, int k) {
vector<int> pre(100000+1,0);
//int pre[100000+1];//pre[i]表示nums前i个元素中,满足nums[i] % modulo == k的个数
pre[0]=0;
for(int i=1;i<=nums.size();i++){
if(nums[i-1]%modulo==k){
pre[i]=pre[i-1]+1;
}
else{
pre[i]=pre[i-1];
}
}
//对于每个左右边界i和j,若满足(pre[j]-pre[i])% modulo=k (i:0~n-1 j:1~n),即为符合题意的一个子数组
//上式可化为 (pre[j]%modulo-k+modulo)%modulo=p[i]%modulo
long long ans=0;
map<int,int> hashMap;//key:数值pre[i]%modulo+k value:该数值出现的次数
hashMap[pre[0]%modulo]=1;
for(int j=1;j<=nums.size();j++){
if(hashMap.find((pre[j]%modulo-k+modulo)%modulo)!=hashMap.end()){
ans+=hashMap[(pre[j]%modulo-k+modulo)%modulo];
}
hashMap[pre[j]%modulo]++;
}
return ans;
}
};
Problem: [146. LRU 缓存]
思路
Code
class LRUCache {
public:
//双向链表存放key-value 表头存放最近使用过的key 表尾存放最久未使用过的key
struct ListNode{
int key;
int value;
ListNode* pre;
ListNode* next;
ListNode(int x,int y){
key=x;
value=y;
}
};
void InsertInHead(int key,int value){
/*
if(hashMap.size()==capacity)
RemoveTail();//如果超了则先移除表尾元素
思考这里为什么不先RemoveTail
因为如果有这种情况capacity=1,put(1,1),put(2,2)就会报错
*/
ListNode* node=new ListNode(key,value);
if(head==nullptr){
head=node;//插入第一个结点的情况
head->next=head;
head->pre=head;
}
else{
node->pre=head->pre;
head->pre->next=node;
node->next=head;
head->pre=node;
head=node;
}
hashMap[key]=node;
}
void MoveToHead(ListNode* node){
if(node==head)
return;
node->pre->next=node->next;
node->next->pre=node->pre;
node->next=head;
node->pre=head->pre;
head->pre->next=node;
head->pre=node;
head=node;
}
void RemoveTail(){
ListNode* tmp=head->pre;
head->pre=head->pre->pre;
head->pre->next=head;
hashMap.erase(tmp->key);
delete(tmp);
}
void print(){//调试用的函数,别管
ListNode* node=head;
for(int i=0;i<hashMap.size();i++){
cout<<node->key<<" ";
node=node->next;
}
cout<<endl;
}
map<int,ListNode*> hashMap;//存放某个key对应的结点,为了O(1)找到value
int capacity;
ListNode *head=nullptr;
LRUCache(int capacity) {
this->capacity=capacity;
}
int get(int key) {
if(hashMap.find(key)==hashMap.end()){
//print();
return -1;
}
else{
ListNode* node=hashMap[key];
MoveToHead(node);
//print();
return node->value;
}
}
void put(int key, int value) {
//如果不存在
if(hashMap.find(key)==hashMap.end()){
InsertInHead(key,value);//插入头部
if(hashMap.size()>capacity)
RemoveTail();//如果超了则移除表尾元素
}
//如果存在,则修改value值并且移到头部
else{
hashMap[key]->value=value;
MoveToHead(hashMap[key]);
}
// print();
}
};
/**
* 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);
*/
Problem: [328. 奇偶链表]
思路
Code
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(head==nullptr||head->next==nullptr||head->next->next==nullptr)
return head;
ListNode *evenL1,*evenL2;//偶数双指针
ListNode *oddL1,*oddL2;//奇数双指针
oddL1=head;
oddL2=head->next->next;
evenL1=head->next;
evenL2=evenL1->next->next;
ListNode *oddHead=oddL1;
ListNode *evenHead=evenL1;
while(evenL2!=nullptr&&oddL2!=nullptr){
oddL1->next=oddL2;
evenL1->next=evenL2;
oddL1=oddL2;
evenL1=evenL2;
if(evenL2!=nullptr){
oddL2=evenL2->next;
}
if(oddL2!=nullptr){
evenL2=oddL2->next;
}
}
if(oddL1!=oddL2)
oddL1->next=oddL2;
if(evenL1!=evenL2)
evenL1->next=evenL2;
//奇数链表尾->偶数链表头
if(oddL2==nullptr){
oddL1->next=evenHead;
evenL2->next=nullptr;
}
else{
oddL2->next=evenHead;
}
return oddHead;
}
};
Problem: [15. 三数之和]
思路
Code
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());//去重1
for(int i=0;i<nums.size();i++){
if(i!=0&&nums[i]==nums[i-1])//去重2
continue;
int target=-nums[i];
int left=i+1,right=nums.size()-1;
while(left<right){
if(left!=i+1&&nums[left]==nums[left-1])//去重3
left++;
else{
if(nums[left]+nums[right]>target)
right--;
else if(nums[left]+nums[right]<target)
left++;
else{
result.push_back({nums[i],nums[left],nums[right]});
left++;
right--;
}
}
}
}
return result;
}
};```
# 优先队列
[Problem: [23. 合并 K 个升序链表]](https://leetcode.cn/problems/merge-k-sorted-lists/description/)
思路
- 优先队列
Code
```cpp
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
struct cmp {
bool operator()(ListNode* a, ListNode* b) {
return a->val > b->val;//小根堆 大于号
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*, vector<ListNode*>, cmp> q;
for(int i=0;i<lists.size();i++){
if(lists[i]!=nullptr)
q.push(lists[i]);
}
ListNode* head=new ListNode(0);
ListNode* curNode=head;
while(!q.empty()){
curNode->next=q.top();
curNode=curNode->next;
q.pop();
if(curNode->next!=nullptr)
q.push(curNode->next);
}
return head->next;
}
};
Problem: [1163. 按字典序排在最后的子串]
思路
class Solution {
public:
string lastSubstring(string s) {
int i=0;//i指向以字典序最大的后缀 j指向当前以s[j]开始的后缀
for(int j=1;j
Code
class Solution {
public:
string lastSubstring(string s) {
//maxIndex指向以字典序最大的后缀 j指向当前以s[j]开始的后缀
int maxIndex=0;
for(int j=1;j<s.size();){
//比较以s[maxIndex]开头的后缀和s[j]开头的后缀
int k=0;
while(j+k<s.size()&&s[maxIndex+k]==s[j+k])
k++;
if(s[maxIndex+k]>s[j+k]){
j=j+k+1;
}
else{
maxIndex=maxIndex+k+1;
if(maxIndex>=j)
j=maxIndex+1;
}
}
return s.substr(maxIndex);
}
};
Problem: [46. 全排列]
思路
Code
class Solution {
public:
vector<vector<int>> result;
bool visited[10];
void dfs(vector<int>& nums,vector<int> arr){
if(arr.size()==nums.size()){
result.push_back(arr);
return;
}
for(int i=0;i<nums.size();i++){
if(!visited[i]){
visited[i]=true;
arr.push_back(nums[i]);
dfs(nums,arr);
arr.pop_back();//恢复现场
visited[i]=false;//恢复现场
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
for(int i=0;i<nums.size();i++)
visited[i]=false;
vector<int> arr;
dfs(nums,arr);
return result;
}
};
Problem: [236. 二叉树的最近公共祖先]
思路
Code
/**
* 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:
TreeNode* ans=nullptr;
//若以curNode为根结点的子树包含q或p则返回true 否则返回false
bool dfs(TreeNode* curNode,TreeNode* p, TreeNode* q){
if(curNode==nullptr)
return false;
bool flag1=dfs(curNode->left,p,q);
bool flag2=dfs(curNode->right,p,q);
if((flag1&&flag2)||(flag1&&curNode->val==p->val)||(flag1&&curNode->val==q->val)||(flag2&&curNode->val==p->val)||(flag2&&curNode->val==q->val)){
ans=curNode;
}
return flag1|flag2|(curNode->val==p->val)|(curNode->val==q->val);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root,p,q);
return ans;
}
};
Problem: [206. 反转链表]
思路
Code
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* ans;
void dfs(ListNode* preNode,ListNode* curNode){
if(curNode->next==nullptr){
curNode->next=preNode;
ans=curNode;
return;
}
dfs(curNode,curNode->next);
curNode->next=preNode;
}
ListNode* reverseList(ListNode* head) {
if(head==nullptr)
return nullptr;
dfs(nullptr,head);
return ans;
}
};
Problem: [LCR 089. 打家劫舍]
思路
Code
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size()==1)
return nums[0];
vector<int> dp(nums.size());//dp[i] 表示前 i 间房屋能偷窃到的最高总金额
//初始化
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
//构造dp
for(int i=2;i<nums.size();i++){
dp[i]=max(nums[i]+dp[i-2],dp[i-1]);
}
return dp[nums.size()-1];
}
};
Problem: [213. 打家劫舍 II]
法一:
思路
Code
class Solution {
public:
int rob(vector<int>& nums) {
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],max(nums[1],nums[2]));
}
//第0家偷 则第1家不能偷 最后一家不能偷
vector<int> dp1(nums.size());
dp1[0]=nums[0];
dp1[1]=nums[0];
dp1[2]=nums[2]+nums[0];
for(int i=3;i<nums.size()-1;i++)
dp1[i]=max(nums[i]+dp1[i-2],dp1[i-1]);
dp1[nums.size()-1]=dp1[nums.size()-2];
//第0家不偷
vector<int> dp2(nums.size());
dp2[0]=0;
dp2[1]=nums[1];
dp2[2]=max(nums[2],nums[1]);
for(int i=3;i<nums.size();i++)
dp2[i]=max(nums[i]+dp2[i-2],dp2[i-1]);
return max(dp1[nums.size()-1],dp2[nums.size()-1]);
}
};
法二
思路:
Code
class Solution {
public:
//在num[left~right]范围内偷,返回最高金额
int fun(vector<int>& nums,int left,int right){
vector<int> dp(right-left+1);
dp[0]=nums[left];
dp[1]=max(nums[left],nums[left+1]);
for(int i=2;i<dp.size();i++){
dp[i]=max(nums[left+i]+dp[i-2],dp[i-1]);
}
return dp[dp.size()-1];
}
int rob(vector<int>& nums) {
if(nums.size()==1)
return nums[0];
if(nums.size()==2)
return max(nums[0],nums[1]);
//不偷第一家:[1,n-1] 不偷最后一家:[0,n-2] (两家都不偷的情况也包含在里面)
return max(fun(nums,0,nums.size()-2),fun(nums,1,nums.size()-1));
}
};
Problem: [122. 买卖股票的最佳时机 II]
思路
Code
class Solution {
public:
int maxProfit(vector<int>& prices) {
//dp[i][0]表示第i天交易结束后手上无股票的最大利润
//dp[i][1]表示第i天交易结束后手上有股票的最大利润
vector<vector<int>> dp(prices.size(),vector<int>(2));
//初始化
dp[0][0]=0;
dp[0][1]=-prices[0];
for(int i=1;i<prices.size();i++){
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
}
return dp[prices.size()-1][0];
//return max(dp[prices.size()-1][0],dp[prices.size()-1][1]);
}
};
Problem: [1143. 最长公共子序列]
思路
Code
class Solution {
public:
//最长公共子序列问题是典型的二维动态规划问题
int longestCommonSubsequence(string text1, string text2) {
//dp[i][j]表示text1前i个字符(text1[0~i-1])与text2前j个字符的最长子序列长度,这里思考为什么不表示text1[0~i]和text2[0~j]
int dp[text1.size()+1][text2.size()+1];
//初始化(回答上面的问题,因为这样便于初始化)
for(int i=0;i<=text1.size();i++)
dp[i][0]=0;
for(int j=0;j<=text2.size();j++)
dp[0][j]=0;
//构造dp
for(int i=1;i<=text1.size();i++)
for(int j=1;j<=text2.size();j++){
if(text1[i-1]==text2[j-1])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
return dp[text1.size()][text2.size()];
}
};
Problem: [5. 最长回文子串]
思路
Code
class Solution {
public:
string longestPalindrome(string s) {
bool dp[s.size()][s.size()];//dp[i][j]表示s[i~j]是否是回文子串
int maxLen=1;
string maxStr=string(1,s[0]);//s.substr(0,1)也行;
//构造边界
for(int i=0;i<s.size();i++){
dp[i][i]=true;
if(i!=s.size()-1){
dp[i][i+1]=s[i]==s[i+1];
if(dp[i][i+1]&&maxLen<2){
maxLen=2;
maxStr=s.substr(i,2);
}
}
}
//斜着向右上方构造dp
//先枚举子串长度
for(int k=0;k<(int)s.size()-2;k++){
//构造长度为k的dp
int i=0,j=i+2+k;
while(j<s.size()){
dp[i][j]=dp[i+1][j-1]&(s[i]==s[j]);
//更新结果
if(dp[i][j]&&maxLen<(j-i+1)){
maxLen=j-i+1;
maxStr=s.substr(i,maxLen);
}
i++;
j++;
}
}
return maxStr;
}
};
Problem: [287. 寻找重复数]
思路
Code
class Solution {
public:
int findDuplicate(vector<int>& nums) {
/*
1.conut[i]表示nums中小于等于i的数字个数,
2.经过分析可知count数组单调非减,且重复的数字是第一个count[i]>i的位置
3.由于count单调非减,所以可用二分法查找所求位置,此时我们无需构造整个count数组,我们只需求每次的count[mid]即可(这样时间复杂度是nlogn级别,不会超时,若构造整个count数组则为n2级别,会超时)
*/
int ans=nums.size()-1;
int left=1,right=nums.size();
while(left<right){
int mid=(left+right)/2;
//计算count[mid]
int countMid=0;
for(int i=0;i<nums.size();i++){
countMid+=(nums[i]<=mid);
}
if(countMid>mid){
right=mid;
}
else{
left=mid;
}
//当left==right-1时,答案必在其中一个
if(left==right-1){
int count1=0;
int count2=0;
for(int i=0;i<nums.size();i++){
count1+=(nums[i]<=left);
count2+=(nums[i]<=right);
}
if(count2>right){
ans=right;
}
if(count1>left){
ans=left;
}
break;
}
}
return ans;
}
};
Problem: [402. 移掉 K 位数字]
思路
Code
class Solution {
public:
string removeKdigits(string num, int k) {
if(k==num.size())
return "0";
string result="";
//对于num[i],直接放入result末尾,但在这之前看上一位数是否大于num[i],若大于则一直移除直到不大于
for(int i=0;i<num.size();i++){
while(k>0&&result.size()>0&&result[result.size()-1]>num[i]){
result.pop_back();
k--;
}
result.push_back(num[i]);
}
//若遍历完num后k仍然大于0,则此时num一定是非递减的,直接取前
if(k>0)
result=result.substr(0,result.size()-k);
//移除前导0
int pos=0;//记录result第一个不为0的下标
if(result[0]=='0')
while(result[pos]=='0')
pos++;
result=result.substr(pos);
if(result.size()==0)
return "0";
else
return result;
}
};
Problem: [1047. 删除字符串中的所有相邻重复项]
思路
Code
class Solution {
public:
string removeDuplicates(string s) {
string result="";//c++的字符串可以当栈用
for(int i=0;i<s.size();i++){
if(!result.empty()&&result.back()==s[i]){
result.pop_back();
}
else{
result.push_back(s[i]);
}
}
return result;
}
};
代码模板
int left = 0, right = 0;//区间 [left, right) 是左闭右开
while (right < s.size()) {
// 右移窗口
char ch=s[right];
if(满足特定条件){
window[ch]++;//更新窗口数据
}
right++;
while (window needs shrink) {
// 左移窗口
char ch=s[left];
if(满足特定条件){
window[ch]--;//更新窗口数据
}
left++;
}
}
关键三个问题:
Problem: [3. 无重复字符的最长子串]
思路
Code
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size()==0)
return 0;
int maxLen=INT_MIN;
map<char,int> window;//s窗口[left,right)中字符出现的次数
int left=0,right=0;
while(right<s.size()){
char ch=s[right];
window[ch]++;
right++;
while(window[ch]>1){
window[s[left]]--;
left++;
}
maxLen=max(maxLen,right-left);
}
return maxLen;
}
};
Problem: [76. 最小覆盖子串]
思路
Code
class Solution {
public:
string minWindow(string s, string t) {
map<char,int> window;//存放s窗口[left,right)中各个字符的个数
map<char,int> tMap;//存放t中各个字符的个数
for(int i=0;i<t.size();i++)
tMap[t[i]]++;
int start=0,minLen=INT_MAX;//最小字串的开始位置和长度
int valid=0;//用于标记当前窗口子串与t中字符匹配的种类数
int left=0,right=0;
while(right<s.size()){
char ch=s[right];
window[ch]++;
if(tMap.find(ch)!=tMap.end()&&window[ch]==tMap[ch]){
valid++;
}
right++;
//左移窗口直到不符合条件的最小left
while(valid==tMap.size()){
//更新结果
if(minLen>right-left){
start=left;
minLen=right-left;
}
window[s[left]]--;//更新窗口
if(tMap.find(s[left])!=tMap.end()&&window[s[left]]<tMap[s[left]]){
valid--;//更新标记参数
}
left++;
}
}
if(minLen==INT_MAX)
return "";
else
return s.substr(start,minLen);
}
};
Problem: [438. 找到字符串中所有字母异位词]
思路
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> result;
map<char,int> window;//s[left,right)中各个字符个数
map<char,int> pMap;
for(int i=0;i<p.size();i++){
pMap[p[i]]++;
}
int valid=0;
int left=0,right=0;
while(right<s.size()){
char ch=s[right];
window[ch]++;
if(pMap.find(ch)!=pMap.end()&&pMap[ch]==window[ch])
valid++;
right++;
while(valid==pMap.size()){
if(right-left==p.size()){
result.push_back(left);
}
char ch=s[left];
window[ch]--;
if(pMap.find(ch)!=pMap.end()&&pMap[ch]>window[ch]){
valid--;
}
left++;
}
}
return result;
}
};
Problem: [209. 长度最小的子数组]
思路
Code
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int minLen=INT_MAX;
int windowSum=0;
int left=0,right=0;//[left,right)
while(right<nums.size()){
windowSum+=nums[right];
right++;
while(windowSum>=target){
minLen=min(minLen,right-left);
windowSum-=nums[left];
left++;
}
}
if(minLen==INT_MAX)
return 0;
else
return minLen;
}
};
Problem: [186. 反转字符串中的单词 II]
思路
Code
class Solution {
public:
void reverse(vector<char>& s,int i,int j){
while(i<j){
char c=s[i];
s[i]=s[j];
s[j]=c;
i++;
j--;
}
}
void reverseWords(vector<char>& s) {
//先反转每个单词 i j分别表示单词的左右边界
for(int i=0;i<(int)s.size();){
int j=i;
while(j<s.size()&&s[j]!=' ')
j++;
reverse(s,i,j-1);
i=j+1;
}
//再反转整个字符串
reverse(s,0,s.size()-1);
}
};```