算法小白malloc利于低端基础理论解决领扣周赛问题的过程,并在最后附上第4道题目Divide Array Into Increasing Sequences(将数组分成几个递增序列)找到的hack数据,不喜勿喷。。。。。。
1118. 一个月有多少天(Easy)
指定年份 Y
和月份 M
,请你帮忙计算出该月一共有多少天。
示例:
输入:Y = 1992, M = 7
输出:31
解析:基础题目,使用一个switch语句即可实现。依据为:一三五七八十腊,三十一天永不差。闰年二月为28天,平年二月为29天。
int numberOfDays(int Y, int M)
{
switch (M)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:return 31;
case 2:{if(Y % 400 == 0 || (Y % 4 == 0 && Y % 100 != 0))
return 29;
else return 28;}
default:return 30;
}
}
1119. 给你一个字符串 S
,请你删去其中的所有元音字母( 'a'
,'e'
,'i'
,'o'
,'u'
),并返回这个新字符串(Easy)
示例:
输入:"leetcodeisacommunityforcoders"
输出:"ltcdscmmntyfrcdrs"
解析:基础题目,可以通过遍历字符串依次判断每个字母是否为元音实现。删除元音时有两种方式,一种为在原字符串上通过STL的erase函数进行删除,但该方法的时间复杂度较高,亲测运行超时;另一种为定义一个新的字符串,若遍历时的当前字符串为非元音,则将其追加到新的字符串上。
//AC代码
string removeVowels(string S)
{
for (int i = 0; i < S.size(); ++i)
{
if (S[i] == 'a' || S[i] == 'e' || S[i] == 'i' || S[i] == 'o' || S[i] == 'u')
S.erase(S.begin() + i);
--i;
}
return S;
}
//运行超时的代码
string removeVowels(string S)
{
string temp;
for (int i = 0;i < S.size();++i)
{
if(!(S[i] == 'a' || S[i] == 'e' || S[i] == 'i' || S[i] == 'o' || S[i] == 'u'))
temp += S[i];
}
return temp;
}
1120. 子树的最大平均值(Medium)
给你一棵二叉树的根节点 root
,找出这棵树的 每一棵 子树的 平均值 中的 最大 值。
子树是树中的任意节点和它的所有后代构成的集合。
树的平均值是树中节点值的总和除以节点数。
示例:
输入:[5,6,1]
输出:6.00000
解释:
以 value = 5 的节点作为子树的根节点,得到的平均值为 (5 + 6 + 1) / 3 = 4。
以 value = 6 的节点作为子树的根节点,得到的平均值为 6 / 1 = 6。
以 value = 1 的节点作为子树的根节点,得到的平均值为 1 / 1 = 1。
所以答案取最大值 6。
解析:如果采用某种遍历顺序遍历整个二叉树,并计算以当前遍历节点为根的子树的平均值,那么运行时间对于节点数目将是指数型的增长,毫无疑问会运行超时。本文采用的方法通过两次后续遍历即可解决该问题。
第一次后续遍历(dfs_value)用来将节点值val替换成以该节点为根的子树的总值,实现方式为:后续遍历,若当前节点的左子树不为空则将其值加到当前节点上,同样若当前节点的右子树不为空则将其值加到当前节点上;由于后续遍历左->右->中的遍历顺序,所以对当前节点值进行处理之前,其左右节点的值已经被处理过(即存储的是以该节点为根的子树的总值)。
第二次后续遍历(dfs_cnt)用来将节点值val替换成以该节点为根的子树的节点总数,同时计算出其以该节点为根的子树的均值用来与需要返回的值result进行比较,若其大于result,则用其替代result。具体实现为:后续遍历,遍历到某一个节点时(可将其称之为当前节点),可定义整型变量cnt用来暂时存储以该节点为根的子树的节点总数(即1 + 左节点val + 右节点val),用当前节点的val值(这时未被替换,仍为以该节点为根的子树的总值)除以cnt和result进行比较进行相应的处理,比较完成后将当前节点的val值替换成cnt以供其父节点使用。
最后的result值即为需要返回的结果。
static void dfs_value(TreeNode* root)
{
if (root->left)
dfs_value(root->left);
if (root->right)
dfs_value(root->right);
if(root->left != NULL)
root->val += root->left->val;
if(root->right != NULL)
root->val += root->right->val;
}
static void dfs_cnt(TreeNode* root, double &result)
{
if (root->left)
dfs_cnt(root->left, result);
if (root->right)
dfs_cnt(root->right, result);
int cnt = 1;
if(root->left != NULL)
cnt += root->left->val;
if(root->right != NULL)
cnt += root->right->val;
if (root->val * 1.0 / cnt > result)
result = root->val * 1.0 / cnt;
root->val = cnt;
}
double maximumAverageSubtree(TreeNode* root)
{
double result = 0;
dfs_value(root);
dfs_cnt(root, result);
return result;
}
1121. 将数组分成几个递增序列
给你一个 非递减 的正整数数组 nums
和整数 K
,判断该数组是否可以被分成一个或几个 长度至少 为 K
的 不相交的递增子序列。
示例:
输入:nums = [1,2,2,3,3,4,4], K = 3
输出:true
解释:
该数组可以分成两个子序列 [1,2,3,4] 和 [2,3,4],每个子序列的长度都至少是 3。
解析:给定的数组为非递减数组,即数组中可能会有相同的元素值;而要求将其分为一个或几个长度至少为K的不相交的递增子序列,即该子序列中不能包含重复的元素值。现将重复个数最多的元素的个数称为minDigitNum,则由以上分析可知至少应将其分为minDigitNum组,每组至少K个;如果没有重复的元素,则将其分为1组即可。
现在就需要根据给定元素的重复情况计算出要组成minDigitNum组字符列至少需要多少个元素,并将其与给定的数量进行比较,若小于等于给定的数量则可以满足要求,否则不能。
现将给定元素重复组数定义为num,则计算最少需要元素数量的方法为:
若K大于等于num则至少需要K*minDigitNum个元素,可简单理解为下图:
若K小于num,则对重复的元素按重复的个数从少到多进行排序,至少需要K*minDigitNum加上前num - K 种重复元素的总数,可理解为下图:
bool canDivideIntoSubsequences(vector<int>& nums, int K) {
vector<int>repEleNum;
int start = -1;
for (int i = 0;i < nums.size() - 1;++i)
{
if (nums[i] == nums[i + 1] && start == -1)
start = i;
if (nums[i] != nums[i + 1] && start != -1)
{
repEleNum.push_back(i + 1 - start);
start = -1;
}
}
if (start != -1)
repEleNum.push_back(nums.size() - start);
sort(repEleNum.begin(), repEleNum.end());
int minDigitNum = repEleNum.size() > 0 ? K * *(repEleNum.rbegin()) : 1;
if(K < repEleNum.size())
{
for (int i = 0;i < repEleNum.size() - K;++i)
minDigitNum += repEleNum[i];
}
if(minDigitNum <= nums.size())
return true;
else
return false;
}
关于hack数据
起初将需要的最少元素数目简单的理解为了上面的minDigit(下面的代码中为maxReNumLen)乘 max{K, num}(num在下面的代码中为repeatNum),同样通过了测试。但提交的代码并不是完全正确的,例如
Input:[1,2,2,2,3,3,4,4] 2
Output应该为true,但是提交的AC代码返回了false。
代码实现如下:
class Solution {
public:
bool canDivideIntoSubsequences(vector<int>& nums, int K) {
int repeatNum = 0, start = -1, maxReNumLen = 0;
for (int i = 0;i < nums.size() - 1;++i)
{
if (nums[i] == nums[i + 1] && start == -1)
{
start = i;
++repeatNum;
}
if (nums[i] != nums[i + 1] && start != -1)
{
if (i + 1 - start > maxReNumLen)
maxReNumLen = i + 1 - start;
start = -1;
}
}
if (start != -1)
{
if (nums.size() - start > maxReNumLen)
maxReNumLen = nums.size() - start;
}
if(K > repeatNum)
repeatNum = K;
if((long)repeatNum * maxReNumLen <= nums.size())
return true;
else
return false;
}
};