这次题目有点过于简单了…
都是没几行就能干出来的
给你一个字符串 s
,字符串的「能量」定义为:只包含一种字符的最长非空子字符串的长度。
请你返回字符串的能量。
示例 1
输入:s = “leetcode”
输出:2
解释:子字符串 “ee” 长度为 2 ,只包含字符 ‘e’ 。
示例 2
输入:s = “abbcccddddeeeeedcba”
输出:5
解释:子字符串 “eeeee” 长度为 5 ,只包含字符 ‘e’ 。
示例 3
输入:s = “triplepillooooow”
输出:5
示例 4
输入:s = “hooraaaaaaaaaaay”
输出:11
示例 5
输入:s = “tourist”
输出:1
提示
- 1 <= s.length <= 500
注意题目的关键 连续 和 一种字符
那么在遍历字符串的时候 会有两种情况:
按照以上思路代码立刻就出来了
总的时间复杂度是遍历字符串的O(n)
class Solution {
public:
int maxPower(string s) {
int ans=1;
int cnt=1; //计数
for(int i=1;i<s.size();i++)
if(s[i]==s[i-1]){ //连续的
cnt++;
ans=max(ans,cnt); //更新答案
}
else cnt=1; //不连续 重置
return ans;
}
};
给你一个整数 n
,请你返回所有 0 到 1 之间(不包括 0 和 1)满足分母小于等于 n
的 最简 分数 。分数可以以 任意 顺序返回。
示例 1
输入:n = 2
输出:[“1/2”]
解释:“1/2” 是唯一一个分母小于等于 2 的最简分数。
示例 2
输入:n = 3
输出:[“1/2”,“1/3”,“2/3”]
示例 3
输入:n = 4
输出:[“1/2”,“1/3”,“1/4”,“2/3”,“3/4”]
解释:“2/4” 不是最简分数,因为它可以化简为 “1/2” 。
示例 4
输入:n = 1
输出:[]
提示
1<= n <= 100
看到题目和范围脑海中一现的就是暴力
把符合题目要求的分子和分母都枚举出来
显然 分母的取值为1~n 而分子的取值为1~分母-1
那么对于每个分数是否是最简 根据高中的知识我们可以知道
当分子和分母没有约数可以化简时候就是最简了
那么我们只需要求一下分子和分母的最大公约数看是否为1就行了
由于此处不会出现分子大于分母以及分子分母都为1的情况 所以不需要额外的判断
总的时间复杂度为暴力枚举的O(n^2)以及不值一提的gcd O(logn)
所以一共是O(n^2logn)
class Solution {
public:
vector<string> simplifiedFractions(int n) {
vector<string> ans;
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
if(gcd(i,j)==1){ //是最简了
string s;
s+=to_string(j);
s+="/";
s+=to_string(i);
ans.push_back(s); //加入答案
}
return ans;
}
int gcd(int a,int b){return b?gcd(b,a%b):a;} //gcd辗转相除法 百度学习即可
};
给你一棵根为 root
的二叉树,请你返回二叉树中好节点的数目。
「好节点」X 定义为:从根到该节点 X 所经过的节点中,没有任何节点的值大于 X 的值。
示例 1
输入:root = [3,1,4,3,null,1,5]
输出:4
解释:图中蓝色节点为好节点。
根节点 (3) 永远是个好节点。
节点 4 -> (3,4) 是路径中的最大值。
节点 5 -> (3,4,5) 是路径中的最大值。
节点 3 -> (3,1,3) 是路径中的最大值。
示例 2
输入:root = [3,3,null,4,2]
输出:3
解释:节点 2 -> (3, 3, 2) 不是好节点,因为 “3” 比它大。
示例 3
输入:root = [1]
输出:1
解释:根节点是好节点。
提示
- 二叉树中节点数目范围是 [1, 10^5] 。
观察可以得知 每个节点的最大值只会影响到他及其的子树 且子树的值对当前节点无影响
因为会影响到它自身 所以树的遍历方式选择先序遍历
先更新完最大值 且判断完当前节点是否加入答案
既然只会影响到子树且子树不影响自己 那么这个当前最大值完全可以作为参数来传递到子树 而不需要额外的数据结构来把子树的影响保存到当前
总的时间复杂度是只有遍历一遍树的节点O(n)
class Solution {
public:
int ans=0;
int goodNodes(TreeNode* root) {
dfs(root,INT_MIN); //初始化要最小的保证根节点
return ans;
}
void dfs(TreeNode* t,int Max)
{
if(!t)return; //空的返回
if(t->val>=Max){ //先更新最大值
ans++; 并且更新答案
Max=t->val;
}
//传进去是更新完的最大值
dfs(t->left,Max);
dfs(t->right,Max);
}
};
给你一个整数数组 cost
和一个整数 target
。请你返回满足如下规则可以得到的 最大 整数:
(i + 1)
的成本为 cost[i]
(cost 数组下标从 0 开始)。target
。由于答案可能会很大,请你以字符串形式返回。
如果按照上述要求无法得到任何整数,请你返回 “0” 。
示例 1
输入:cost = [4,3,2,5,6,7,2,5,5], target = 9
输出:“7772”
解释:添加数位 ‘7’ 的成本为 2 ,添加数位 ‘2’ 的成本为 3 。所以 “7772” 的代价为 23+ 31 = 9 。 “997” 也是满足要求的数字,但 “7772” 是较大的数字。
数字 成本
1 -> 4
2 -> 3
3 -> 2
4 -> 5
5 -> 6
6 -> 7
7 -> 2
8 -> 5
9 -> 5
示例 2
输入:cost = [7,6,5,5,5,6,8,7,8], target = 12
输出:“85”
解释:添加数位 ‘8’ 的成本是 7 ,添加数位 ‘5’ 的成本是 5 。“85” 的成本为 7 + 5 = 12 。
示例 3
输入:cost = [2,4,6,2,4,6,4,4,4], target = 5
输出:“0”
解释:总成本是 target 的条件下,无法生成任何整数。
示例 4
输入:cost = [6,10,15,40,40,40,40,40,40], target = 47
输出:“32211”
提示
- cost.length == 9
非常直观这就是一个完全背包dp问题
在这道题中
target
**cost[i]
**i+1+'0'
的数位另外题目还有额外要求要注意就是 target大小的背包必须全部用完 那么这里参考一般背包的话就要在初始化dp数组留点心
还有一个地方就是 总价值的大小判断
此处我们可以另外开一个函数去处理
dp[0]
外的都赋值为非法值)由于背包的遍历加入是一个一个的 且是无序加入的 但是字符串显然不同顺序加入会得到不同的总价值
这里需要采用贪心 把cost从后往前加入
因为无序得到物品后 较大的数位肯定全部排列在前总价值会更大
这也恰好符合背包是一个接一个加入的顺序
总的时间复杂度是dp状态的遍历 时间复杂度为O(9target)
class Solution {
public:
string largestNumber(vector<int>& cost, int target) {
vector<string> dp(target+5,"a"); //初始化为非法状态
dp[0]=""; //只有0空间是合法的
for(int i=8;i>=0;i--) //采用一维空间压缩做法
for(int j=cost[i];j<=target;j++)
{
string s=dp[j-cost[i]];
s.push_back(i+1+'0');
if(check(s,dp[j]))dp[j]=s;
}
return dp[target]=="a"?"0":dp[target]; //注意题目要求 非法即用不完要输出0
}
inline bool check(string a,string b)
{
if(a[0]=='a')return false; //非法
if(b[0]=='a')return true; //非法
if(a.size()==b.size())return a>b; //字典序
return a.size()>b.size(); //长度
}
};