重新排列字符串 | 灯泡开关Ⅳ | 好叶子节点对的数量 | 压缩字符串Ⅱ |
---|---|---|---|
3分 简单 | 4分 中等 | 5分 中等 | 8分 困难 |
√ | √ | √ | 写的时候傻逼了,结束后立马过了 |
5472 重新排列字符串
签到题
复杂度
O(n)
执行用时
24ms
内存消耗
15.4MB
class Solution { public: string restoreString(string s, vector<int>& indices) { string ans=s; for(int i=0;i<indices.size();i++){ ans[indices[i]]=s[i]; } return ans; } };
5473 灯泡开关Ⅳ
开关是转变i-n的状态,所以必须要先从将前面的灯泡的状态变成要求的状态
转化下题意,其实就是要求段的个数,段是连续的1或者连续的0
开头全是0的段不计次数
执行用时
44 ms
内存消耗
9.5MB
复杂度
O(n)
class Solution { public: int minFlips(string target) { int len=target.length(); int now=0; int ans=0; while(now<len&&target[now]=='0') now++; if(now<len){ while(now<len){ ans++; int flag=target[now]-'0'; while(now<len&&flag==(target[now]-'0')) now++; } } return ans; } };
5474 好叶子节点对的数量
用vector < int > tmp 维护叶子节点到当前节点的距离 i 的个数tmp[i]
dfs先求出左儿子的集合left和右儿子的集合right
枚举左子树的叶子节点到当前节点的距离i,右子树的叶子节点到当前的距离j
这一对叶子节点的距离就是 i+j+2 , 它们的贡献就是left[i]*right[j]
再将左右子树集合合并
for(int i=0;i<dis;i++){ if(i+1<dis) tmp[i+1]+=(left[i]+right[i]); }
复杂度
O(n * d * d)
n为节点个数,d为传入参数distance
执行用时
96 ms
内存消耗
33.6MB
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: int ans=0; vector<int> dfs(TreeNode* root,int dis){ vector<int>tmp(dis,0); if(root==NULL){ return tmp; } if(root->left==NULL&&root->right==NULL){ tmp[0]=1; return tmp; } vector<int>left=dfs(root->left,dis); vector<int>right=dfs(root->right,dis); for(int i=0;i<dis;i++){ if(i+1<dis) tmp[i+1]+=(left[i]+right[i]); if(left[i]==0) continue; for(int j=0;j<dis;j++){ int sum=i+j+2; if(sum<=dis){ ans+=left[i]*right[j]; } else break; } } return tmp; } int countPairs(TreeNode* root, int distance) { if(distance<2) return 0; dfs(root,distance); return ans; } };
5462 压缩字符串Ⅱ
dp[i][j][k]
表示到字符串第i位,与第i位左边相邻的连续相同字符个数为j
(eg:abcc 与第4位左边相邻的连续相同字符个数为2;与第3位左边相邻的连续相同字符个数为1)
删除了k个字符
枚举前一个状态 f[j][l][m]
for(int i=1;i<=n;i++){ for(int j=i-1;j>=0;j--){ for(int l=0;l<=j;l++){ for(int m=0;m<=min(k,j);m++){ } } } }
当s[i]==s[j]
状态转移方程为:
int flag=0;//flag表示当前字符的个数进位了,如从个位数到达十位数 if((l+1==2)||(l+1==10)||(l+1==100)) flag=1; int tmp=m+i-j-1;//tmp表示删除(j+1~i-1)之间所有的数 else f[i][l+1][tmp]=min(f[i][l+1][tmp],f[j][l][m]+flag);
连续相邻个数加1
当i后面的数都可以被删除时,更新最后的答案if(n-i<=k-tmp) ans=min(ans,f[i][l+1][tmp]);
当s[i]!=s[j]
状态转移方程为
int tmp=m+i-j-1;//tmp表示删除(j+1~i-1)之间所有的数 f[i][1][tmp]=min(f[i][1][tmp],f[j][l][m]+1);
连续相邻个数变为1
当i后面的数都可以被删除时,更新最后的答案 if(n-i<=k-tmp) ans=min(ans,f[i][1][tmp]);
复杂度
O(N^4)
执行用时
1652 ms
内存消耗
11.5MB
class Solution { public: int f[105][105][105]; int getLengthOfOptimalCompression(string ss, int k) { string s="!"+ss; int n=ss.length(); memset(f,-1,sizeof(f)); f[0][0][0]=0; int ans=n-k; for(int i=1;i<=n;i++){ for(int j=i-1;j>=0;j--){ for(int l=0;l<=j;l++){ for(int m=0;m<=min(k,j);m++){ if(f[j][l][m]==-1) continue; int tmp=m+i-j-1; if(tmp>k) break; if(s[i]==s[j]){ int flag=0; if((l+1==2)||(l+1==10)||(l+1==100)) flag=1; if(f[i][l+1][tmp]==-1) f[i][l+1][tmp]=f[j][l][m]+flag; else f[i][l+1][tmp]=min(f[i][l+1][tmp],f[j][l][m]+flag); if(n-i<=k-tmp) ans=min(ans,f[i][l+1][tmp]); } else{ if(f[i][1][tmp]==-1) f[i][1][tmp]=f[j][l][m]+1; else f[i][1][tmp]=min(f[i][1][tmp],f[j][l][m]+1); if(n-i<=k-tmp) ans=min(ans,f[i][1][tmp]); } } } } } return ans; } };