这段时间经历了组会、开题、回家等等,这才发现周赛已经打到325场了,而我还没有写完321场的题解记录,真是汗颜啊。
LeetCode周赛第321场记录
这场周赛的题目相对比较简单一些,在此简单做个梳理:
这道题比较简单,就是找出[1,n]之间的一个"中枢"值。
这道题我使用了等差数列的求和公式来快速计算一个范围内的和,随后通过一次遍历来实现中枢值的查找,代码如下:
class Solution {
int getSum(int Start, int End)
{
int Length = End - Start + 1;
return (int)((Start + End) * ((double)Length / 2));
}
public:
int pivotInteger(int n)
{
int Ans = -1;
for(int i = 1 ; i <= n ; ++i)
if(getSum(1, i) == getSum(i, n))
{
Ans = i;
break;
}
return Ans;
}
};
、 注意在上述代码计算范围和时,除以2的部分一定要转成double类型,否则0.5会被整除抹去导致结果出错。
2486. 追加字符以获得子序列(贪心)
这道题也同样非常简单,因为子序列是不连续的,所以只需要贪心地统计字符串s中已经出现了的t的子序列长度即可,再用t的长度减去已经匹配的长度即可,代码如下:
class Solution {
public:
int appendCharacters(string s, string t)
{
int n = s.size(), m = t.size();
int i = 0, j = 0;
while(i < n and j < m)
{
while(i < n and s[i] != t[j])
++i;
if(i == n)
break;
else
{
++i;
++j;
}
}
return m - j;
}
};
2487. 从链表中移除节点(单调递增栈)
这道题一种比较好的解法就是单调栈,在使用单调栈时可以先将一个很大的Dummy节点推到栈中,这个节点是始终不会被推出栈的,这可以帮助我们快速索引到栈底元素从而返回答案。
随后开始遍历链表,并同时使用单调栈维护一个单调不增的序列,这样就可以在
O
(
n
)
O(n)
O(n)的时间复杂度内完成本题的求解,代码也非常简洁优雅,所以这道题中Dummy节点的使用是非常漂亮的,很好地利用了题目中链表节点取值范围的信息。
ListNode* removeNodes(ListNode* head) {
ListNode* ans = new ListNode(1e6);
stack<ListNode*> st;
st.push(ans);
while(head) {
while(head->val > st.top()->val) st.pop();
st.top()->next = head;
st.push(head);
head = head->next;
}
return ans->next;
}
2488. 统计中位数为 K 的子数组(数学转换)——O(n)
这道题是一道考察转化的问题,这里记录一下灵茶山艾府的笔记。 注意这道题对于中位数的定义,当子数组长度为偶数时,直接取中间两个元素的靠左的元素,而不是平均数,这和数学上的中位数定义是不一样的。
int countSubarrays(vector<int> &nums, int k)
{
int pos = find(nums.begin(), nums.end(), k) - nums.begin(), n = nums.size();
unordered_map<int, int> cnt;
cnt[0] = 1;
for (int i = pos + 1, c = 0; i < n; ++i) {
c += nums[i] > k ? 1 : -1;
++cnt[c];
}
int ans = cnt[0] + cnt[1];
for (int i = pos - 1, c = 0; i >= 0; --i) {
c += nums[i] < k ? 1 : -1;
ans += cnt[c] + cnt[c + 1];
}
return ans;
}
下面是一个具体的例子:
|