一如既往的一题选手
第一题
6233. 温度转换
难度: 简单
给你一个四舍五入到两位小数的非负浮点数 celsius 来表示温度,以 摄氏度(Celsius)为单位。
你需要将摄氏度转换为 开氏度(Kelvin)和 华氏度(Fahrenheit),并以数组 ans = [kelvin, fahrenheit] 的形式返回结果。
返回数组 ans 。与实际答案误差不超过 10-5 的会视为正确答案。
注意:
开氏度 = 摄氏度 + 273.15
华氏度 = 摄氏度 * 1.80 + 32.00
不需要任何思路 直接就能写
class Solution {
public:
vector<double> convertTemperature(double celsius) {
//开氏度 = 摄氏度 + 273.15
//华氏度 = 摄氏度 * 1.80 + 32.00
vector<double> res;
double val1=celsius+273.15;
double val2=celsius*1.8+32.00;
res.push_back(val1);
res.push_back(val2);
return res;
}
};
第二题
6234. 最小公倍数为 K 的子数组数目
难度:中等
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 nums 的 子数组 中满足 元素最小公倍数为 k 的子数组数目。
子数组 是数组中一个连续非空的元素序列。
数组的最小公倍数 是可被所有数组元素整除的最小正整数。
思路 :
#1 暴力尝试
套用2层循环 调用 c++自带的lcm函数 依次去判断k是不是公倍数 如果是 res++ 最后返回res
代码如下:
class Solution {
public:
int subarrayLCM(vector<int>& nums, int k) {
int n = nums.size();
int ans = 0;
for(int i = 0; i < n; i++) {
if(nums[i] == k) ans++;
int t = nums[i];
for(int j = i + 1; j < n; j++) {
t = lcm(nums[j], t);
if(t == k) ans++;
}
}
return ans;
}
};
#2动态规划
首先先来确定几个值的含义 loc:上一个无效地点的下标(很重要) pre:判定这个点 和k的最小公倍数 是不是k 如果不是 直接就break掉 cur:用来不断的判断一个点的左边界点
过程如下 来到一个点 调用lcm函数 判断它是否和k的最小公倍数为k
1不是 则这个点就废掉了 相当于 所以集合都不包括这个点 我们又是从左到右依次计算每一个合格的子数组的 所以 如果判定到了 某一个点 他和k的最小公倍数 不是k 则可以直接 利用 loc 变量 将其接住 表明 之后的子树组 无法在跨越到这个点 或者这个点之前的任何下标
2是 则开始判断 nums[j] 与 cur的最小公倍数 是不是k 是k则跳出循环 不是就一直向前寻找 直到找到合理数组的左边界 然后 res+=j-loc
解释一下这一大段 并用一些例子来辅助说明 nums=[9,9,9,9,1,2,3,6,5] k=6 下标从0开始 我们可以知道 道下标为3 依旧是无法让 lcm(k,nums[i])为 k 所以loc来到了 3 位置 然后 来到下标为4 的位置 发现 lem(nums[i],k 为 k 进入 循环 然后开始 判断 cur是不是 k 然后 如果是 则跳出循环 否则就会一直跳到 loc位置 * 这句是重点 他跳到loc位置 然后 res+=j-loc 会发现 此时 j==loc 即 res不会加 如果他中途跳了出来 例如从 下标为6开始 cur=lcm(cur,nums[j]) 发现 来到 下标为5的时候 2 3的最小公倍数 刚刚好是 6 所以跳出循环 res+=j-loc 代表什么? 代表以i位置结尾 这个子数组至少需要推几个位置才能使得 公倍数为k 为什么是j-loc 就那刚刚的例子来说 来到了 j在 5 位置跳出了循环 现在有2个子数组 是符合条件的 [2,3] 以及[1,2,3] 所以是什么意思呢 因为他是一个连续子数组 所以只能在判断连续的位置 所以每次从j位置向前移动一个 只要他大于loc位置 就说明有一个新的数组一定合格 因为loc已经帮我们排除掉了
代码如下:
class Solution {
public:
int subarrayLCM(vector<int>& nums, int k) {
int ret = 0, i, j, pre = 1, loc = -1, cur = 1;
for (i = 0; i < nums.size(); i ++){
pre = lcm(pre, nums[i]) ;
if (k % pre == 0){
j = i ;
cur = lcm(nums[j], 1);
while(j > loc && k != cur){
j -- ;
if (j <= loc) break ;
cur = lcm(nums[j], cur) ;
}
res += j - loc ;
}else {
loc = i ;
pre = 1 ;
}
}
return res ;
}
};
第三题
6235. 逐层排序二叉树所需的最少操作数目
难度:中等
给你一个 值互不相同 的二叉树的根节点 root 。
在一步操作中,你可以选择 同一层 上任意两个节点,交换这两个节点的值。
返回每一层按 严格递增顺序 排序所需的最少操作数目。
节点的 层数 是该节点和根节点之间的路径的边数。
思路
层序遍历+置换环
根据题目描述 我们知道了他需要来一层一层的比较 所以需要利用队列来实现层序遍历 并且在遍历每层的节点的时候 需要让他实现一个 最小交换次数 的函数 最后用res变量来记住他 最后返回res每层最小的交换次数函数实现 本题是可以交换任意位置的元素,可以通过找环来做。对于数组nums,它排序之后为sortedNums,我们可以通过sortedNums知道原数组中每个数nums[i]应该排在哪个位置,当某个元素不在自己正确的位置 i 上时,若把它排到 i 上,就会把位置 i 上的数字怼出来;再把这个数字往它应该在的位置上怼,就这样下标连续怼可以完成一个小范围(也有可能整个数组都排好序)数字的归位,这个范围内的数形成了一个“环”。在能交换任意位置的两个元素的情况下,使数组升序的最小交换次数就是数组元素总个数减去环的个数。
代码如下:
class Solution {
public:
int minimumOperations(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
int ans = 0;
while(!q.empty()) {
vector<int> layer;
int qs = q.size();
for(int i = 0; i < qs; i++) {
TreeNode* node = q.front();
q.pop();
layer.push_back(node->val);
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
int d = getMinSwaps(layer);
ans += d;
}
return ans;
}
int getMinSwaps(vector<int>& v){
vector<int> v1(v);
sort(v1.begin(), v1.end());
map<int, int> m;
int len = v.size();
for(int i = 0; i < len; i++) {
m[v1[i]] = i;
}
int loops = 0;
vector<bool> flag(len, false);
for(int i = 0; i < len; i++) {
if(!flag[i]) {
int j = i;
while(!flag[j]) {
flag[j] = true;
j = m[v[j]];
}
loops++;
}
}
return len - loops;
}
};
第四题
6236. 不重叠回文子字符串的最大数目
难度:困难
给你一个字符串 s 和一个 正 整数 k 。
从字符串 s 中选出一组满足下述条件且 不重叠 的子字符串:
每个子字符串的长度 至少 为 k 。
每个子字符串是一个 回文串 。
返回最优方案中能选择的子字符串的 最大 数目。
子字符串 是字符串中一个连续的字符序列。
思路:
做法,求出每个子串是不是回文子串。记 g(l,r) 表示第 l 到 r 个字符构成的子串是不是回文子串。
之后维护 f(i)f(i) 表示长度为 ii 的前缀中能选出多少个长度大等于 k 且不重叠的子串,转移方程为
f[i]=max(f[i-1],f[j]+1) 其中 i-j>=k 并且 j+1到i是回文串
上面的转移表示不选择以第 i 个字符为结尾的子串;下面的转移表示选择以第 (j + 1)个字符为开始,第 ii 个字符为结束的回文子串。
初值 f(0) = 0,答案就是 f(n),复杂度 O(n^2);
代码如下:
class Solution {
public:
int maxPalindromes(string s, int K) {
int n = s.size();
bool flag[n][n];
memset(flag, 0, sizeof(flag));
for (int i = 0; i < n; i++)
{
for (int l = i, r = i; l >= 0 && r < n && s[l] == s[r]; l--, r++)
{
flag[l][r] = true;
}
}
for (int i = 0; i + 1 < n; i++) {
for (int l = i, r = i + 1; l >= 0 && r < n && s[l] == s[r]; l--, r++)
{
flag[l][r] = true;
}
}
int f[n + 1];
memset(f, 0, sizeof(f));
for (int i = 1; i <= n; i++) {
f[i] = f[i - 1];
for (int j = i - K; j >= 0; j--) {
if (flag[j][i - 1]) f[i] = max(f[i], f[j] + 1);
}
}
return f[n];
}
};