LeetCode 321 周赛

news2025/2/2 18:44:08

2485. 找出中枢整数

给你一个正整数 n ,找出满足下述条件的 中枢整数 x

  • 1x 之间的所有元素之和等于 xn 之间所有元素之和。

返回中枢整数 x 。如果不存在中枢整数,则返回 -1 。题目保证对于给定的输入,至多存在一个中枢整数。

提示

  • 1 <= n <= 1000

示例

输入:n = 8
输出:6
解释:6 是中枢整数,因为 1 + 2 + 3 + 4 + 5 + 6 = 6 + 7 + 8 = 21 。

思路

由于数据范围很小,暴力模拟即可。

class Solution {
public:
    int pivotInteger(int n) {
        int tot = (1 + n) * n / 2, sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += i;
            if (sum == tot - sum + i) return i;
        }
        return -1;
    }
};

2486. 追加字符以获得子序列

给你两个仅由小写英文字母组成的字符串 st

现在需要通过向 s 末尾追加字符的方式使 t 变成 s 的一个 子序列 ,返回需要追加的最少字符数。

子序列是一个可以由其他字符串删除部分(或不删除)字符但不改变剩下字符顺序得到的字符串。

提示

  • 1 <= s.length, t.length <= 10^5
  • st 仅由小写英文字母组成

示例

输入:s = "coaching", t = "coding"
输出:4
解释:向 s 末尾追加字符串 "ding" ,s = "coachingding" 。
现在,t 是 s ("coachingding") 的一个子序列。
可以证明向 s 末尾追加任何 3 个字符都无法使 t 成为 s 的一个子序列。

思路

双指针,看下t中最多有多少个字符可以在s中得到。

class Solution {
public:
    int appendCharacters(string s, string t) {
        int n = s.size(), m = t.size();
        int i = 0, j = 0;
        while (i < n && j < m) {
            if (s[i] == t[j]) j++;
            i++;
        }
        return m - j; // 还差多少个
    }
};

2487. 从链表移除节点

给你一个链表的头节点 head

对于列表中的每个节点 node ,如果其右侧存在一个具有 严格更大 值的节点,则移除 node

返回修改后链表的头节点 head

提示

  • 给定列表中的节点数目在范围 [1, 10^5]
  • 1 <= Node.val <= 10^5

示例

输入:head = [5,2,13,3,8]
输出:[13,8]
解释:需要移除的节点是 5 ,2 和 3 。
- 节点 13 在节点 5 右侧。
- 节点 13 在节点 2 右侧。
- 节点 8 在节点 3 右侧。

思路

单调栈,维护一个单调递减的栈即可。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNodes(ListNode* head) {
        ListNode* hh = new ListNode(1e5 + 5, head);
        stack<ListNode*> stk;
        stk.push(hh);
        for (ListNode* cur = head; cur != nullptr; cur = cur->next) {
            while (!stk.empty() && stk.top()->val < cur->val) stk.pop();
            // 中间部分的节点全部要被移除, 只需要连接第一个大于cur的节点即可
            stk.top()->next = cur;
            stk.push(cur);
        }
        return hh->next;
    }
};

另:递归做法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNodes(ListNode* head) {
        if (head->next == nullptr) return head;
        ListNode* x = removeNodes(head->next);
        return head->val >= x->val ? new ListNode(head->val, x) : x;
    }
};

2488. 统计中位数为K的子数组

给你一个长度为 n 的数组 nums ,该数组由从 1n不同 整数组成。另给你一个正整数 k

统计并返回 num 中的 中位数 等于 k 的非空子数组的数目。

注意:

  • 数组的中位数是按 递增 顺序排列后位于 中间 的那个元素,如果数组长度为偶数,则中位数是位于中间靠 的那个元素。
    • 例如,[2,3,1,4] 的中位数是 2[8,4,3,5,1] 的中位数是 4
  • 子数组是数组中的一个连续部分。

提示:

  • n == nums.length
  • 1 <= n <= 10^5
  • 1 <= nums[i], k <= n
  • nums 中的整数互不相同

示例:

输入:nums = [3,2,1,4,5], k = 4
输出:3
解释:中位数等于 4 的子数组有:[4]、[4,5] 和 [1,4,5] 。

思路

首先找到k的下标,假设为x,我们需要找到所有的[i, j],其中ix左侧,jx右侧。设区间[i, x]内小于k的元素个数为leftLessCnt,大于k的元素个数为leftGreatCnt;同理设区间[x, j]中小于k的元素个数为rightLessCnt,大于k的元素个数为rightGreatCnt。由于k是中位数,那么需要满足[i, j]整个区间内,小于k的元素个数,与大于k的元素个数,相等,或者左侧比右侧少1。

那么我们需要找出所有的[i, j],使其满足

leftLessCnt + rightLessCnt = leftGreatCnt + rightGreatCnt或者

leftLessCnt + rightLessCnt = leftGreatCnt + rightGreatCnt - 1

我周赛当天的想法是对于左右两侧,分别维护一下小于k的元素个数与大于k的元素个数的差值。下面是我周赛当天的代码。

const int N = 1e5 + 10;
class Solution {
public:
    
    vector<vector<int>> rFreq;
    
    int countSubarrays(vector<int>& nums, int k) {
        int pos = 0, n = nums.size();
        for (int i = 0; i < n; i++) {
            if (nums[i] == k) {
                pos = i;
                break;
            }
        }
        
        // printf("pos = %d\n", pos);
        
        // f[i][0] 表示 lCnt < gCnt, 相差i
        // f[i][1] 表示 lCnt > gCnt, 相差i
        rFreq = vector<vector<int>>(n + 1, vector<int>(2, 0));
        
        // 求一下右侧的cnt
        int lCnt = 0, gCnt = 0;
        for (int i = pos + 1; i < n; i++) {
            if (nums[i] < k) lCnt++;
            else gCnt++;
            
            if (lCnt == gCnt) rFreq[0][0]++, rFreq[0][1]++;
            else if (lCnt < gCnt) rFreq[gCnt - lCnt][0]++;
            else rFreq[lCnt - gCnt][1]++;
        }
        rFreq[0][0]++;
        rFreq[0][1]++;
        
        // for (int i = 0; i <= n; i++) {
        //     if (rFreq[i][0]) printf("freq[%d][0] = %d\n", rFreq[i][0]);
        //     if (rFreq[i][1]) printf("freq[%d][1] = %d\n", rFreq[i][1]);
        // }
        
        
        int ans = 0; // 长度为1的
        // 计算左侧
        lCnt = gCnt = 0;
        for (int i = pos; i >= 0; i--) {
            if (nums[i] < k) lCnt++;
            else if (nums[i] > k) gCnt++;
            
            // printf("i = %d, lCnt = %d, gCnt = %d\n", i, lCnt, gCnt);
            int d = gCnt - lCnt;
            if (d == 0) {
                // printf("d = %d, [0][0] = %d, [1][0] = %d\n", d, rFreq[0][0], rFreq[1][0]);
                ans += rFreq[0][0] + rFreq[1][0]; // g > l
            }
            else if (d < 0) {
                // printf("d = %d, [-d][0] = %d, [-d+1][0] = %d\n", d, rFreq[-d][0], rFreq[-d+1][0]);
                ans += rFreq[-d][0] + rFreq[-d + 1][0];
            }
            else {
                // printf("d = %d, [d][1] = %d, [d - 1][1] = %d\n", d, rFreq[d][1], rFreq[d - 1][1]);
                ans += rFreq[d][1] + rFreq[d - 1][1];
            }
            // printf("ans = %d\n", ans);
        }
        
        return ans;
    }
};

很遗憾,当时边界问题没处理好,直到12点04分才调试通过,然而12点比赛就结束了,痛失AK机会。并且我代码写的可谓又臭又长,十分难看。下面是今天(2022/12/20)重写的代码。

class Solution {
public:
    int countSubarrays(vector<int>& nums, int k) {
        int n = nums.size(), x = n;
        unordered_map<int, int> freq;

        int lCnt = 0, gCnt = 0; // 小于k和大于k的元素个数
        for (int i = 0; i < n; i++) {
            if (nums[i] == k) x = i;
            // 一次遍历同时找出坐标x, 并处理右侧的情况
            if (i >= x) {
                if (nums[i] < k) lCnt++;
                if (nums[i] > k) gCnt++;
                freq[gCnt - lCnt]++;
            }
        }

        // 处理左边
        int ans = 0;
        lCnt = gCnt = 0;
        for (int i = x; i >= 0; i--) {
            if (nums[i] < k) lCnt++;
            if (nums[i] > k) gCnt++;
            ans += freq[lCnt - gCnt] + freq[lCnt - gCnt + 1];
        }
        return ans;
    }
};

再提供一个版本,这个版本是今天重做时,没有回看之前代码的情况下,自己重新写的。相对而言更多是推公式。

l[i]表示区间[i, x]内小于k的元素数量,那么很明显的,[i, x]内大于k的元素数量应该是x - i - l[i]

同理设r[j]表示区间[x, j]内小于k的元素数量,那么,[x, j]内大于k的元素数量是j - x - r[j]

我们需要找到所有的[i, j]对,使得其满足

l[i] + r[j] = x - i - l[i] + j - x - r[j]

l[i] + r[j] = x - i - l[i] + j - x - r[j] - 1

整理一下,将i相关的项全部移到一边,j相关的项全部移到另一边,整理一下有

2 * l[i] + i = j - 2 * r[j]

2 * l[i] + i = j - 2 * r[j] - 1

那么我们可以处理x右侧的所有位置j,计算出j - 2 * r[j],并计数。

然后遍历x左侧的所有位置,对于每个i,找到与之匹配的所有j即可。

class Solution {
public:
    int countSubarrays(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> l(n), r(n);
        // 先找到k这个数的所在位置
        int x = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] == k) {
                x = i;
                break;
            }
        }
        // 预处理l
        int cnt = 0;
        for (int i = x; i >= 0; i--) {
            if (nums[i] < k) cnt++;
            l[i] = cnt;
        }

        unordered_map<int, int> m;

        // 预处理r
        cnt = 0;
        for (int i = x; i < n; i++) {
            if (nums[i] < k) cnt++;
            r[i] = cnt;
            int u = i - 2 * r[i];
            m[u]++; // 计数+1
        }

        int ans = 0;
        for (int i = 0; i <= x; i++) {
            int u = 2 * l[i] + i;
            ans += m[u] + m[u + 1];
        }
        return ans;
    }
};

同样的,可以对代码进行一下优化。

class Solution {
public:
    int countSubarrays(vector<int>& nums, int k) {
        // 先找到k这个数的所在位置
        int n = nums.size(), x = n, cnt = 0, ans = 0;
        unordered_map<int, int> freq;
        for (int i = 0; i < n; i++) {
            if (nums[i] == k) x = i;
            if (i >= x) {
                if (nums[i] < k) cnt++;
                freq[i - 2 * cnt]++;
            }
        }

        cnt = 0;
        for (int i = x; i >= 0; i--) {
            if (nums[i] < k) cnt++;
            int u = 2 * cnt + i;
            ans += freq[u] + freq[u + 1];
        }
        return ans;
    }
};

总结

image-20221220174817736

这次的T4难度不大,有机会AK的,但很可惜。

T1简单模拟;T2双指针模拟;T3栈;T4哈希表。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/103780.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32单片机直流电机PID速度控制正反转控制(霍尔磁铁测速)LCD1602

实践制作DIY- GC0116-直流电机PID速度控制 一、功能说明&#xff1a; 基于STM32单片机设计-直流电机PID速度控制 功能介绍&#xff1a; STM32F103C系列最小系统LCD1602直流电机磁铁霍尔传感器MX15系列驱动模块4个按键&#xff08;速度减、速度加、开/关、正转/反转&#xff0…

【复习笔记】【嵌入式】嵌入式系统及其原理复习重点——篇二

嵌入式系统及其原理复习重点笔记 2 ARM处理器和指令集 ARM处理器简介 ARM架构与ARM处理器对应关系 V1版架构 该版架构只在原型机ARM1出现过,处理能力有限&#xff0c;其基本性能&#xff1a; 寻址空间&#xff1a;64M字节(26位)基本的数据处理指令(无乘法)字节、半字和字的…

4个封神的电脑软件,颠覆你对白嫖的认知,干货奉上

闲话少说&#xff0c;直上干货。 1、TinyWow TinyWow虽说是国外网站工具&#xff0c;但不得不承认真的无敌好用&#xff0c;收纳工具超200个&#xff0c;完全免费&#xff0c;无任何弹屏广告&#xff0c;更为良心的是&#xff0c;不需要注册登录&#xff0c;随用随走&#xff0…

如何优化大场景实时渲染?HMS Core 3D Engine这么做

在先前举办的华为开发者大会2022&#xff08;HDC&#xff09;上&#xff0c;华为通过3D数字溪村展示了自有3D引擎“HMS Core 3D Engine”&#xff08;以下简称3D Engine&#xff09;的强大能力。作为一款高性能、高画质、高扩展性的3D引擎&#xff0c;3D Engine不仅能通过实时光…

C++文件流

1、【转】string和stringstream用法总结 - 小金乌会发光&#xff0d;Z&M - 博客园 2、C&#xff1a;std::stringstream【数据类型转换、多个字符串拼接、分割字符串】_u013250861的博客-CSDN博客_c stringstream转string 3、C使用stringstream进行数据类型转换_puppylpg的…

TCP延迟应答、捎带应答、粘包问题、异常处理

TCP延迟应答、捎带应答、粘包问题、异常处理一、延迟应答二、捎带应答三、面向字节流 -- 粘包问题四、TCP中的异常处理五、补充一、延迟应答 上篇博客我们讲到TCP滑动窗口、流量控制、拥塞控制。 如果接收数据的主机立刻返回ACK应答&#xff0c;这时候返回的窗口可能比较小。…

[ vulhub漏洞复现篇 ] Airflow dag中的命令注入漏洞复现 CVE-2020-11978

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

web前端-javascript-function函数的arguments对象(类数组对象,它也可以通过索引来操作数据,也可以获取长度)

arguments 对象 1. 引出 arguments 在调用 function 函数时&#xff0c;浏览器每次都会传递进两个隐含的参数 函数的上下文对象 this封装实参的对象 arguments 2. 说明 arguments 是一个类数组对象,它也可以通过索引来操作数据&#xff0c;也可以获取长度在调用函数时&#…

ACL会议介绍 - Call for Main Conference Papers

The 61st Annual Meeting of the Association for Computational Linguistics Toronto, Canada July 9-14, 2023 网址&#xff1a;The 61st Annual Meeting of the Association for Computational Linguistics - ACL 2023 目录 征集主要会议文件 Submission Topics 主题轨迹…

Stm32标准库函数3——BlueTooth 蓝牙通讯测试 Stm32中继

//在使用本程序前&#xff0c;先将模块与手机端匹配成功&#xff0c;波特率38400 //串口1&#xff08;A9、A10&#xff09;接电脑&#xff0c;串口2&#xff08;A2、A3&#xff09;接蓝牙模块 //所有的波特率都为38400&#xff0c;蓝牙的供电为3.3-5v //程序功能&#xff0c;转…

Discrete Optimization课程笔记(4)—混合整数规划

目录​​​​​​​ 1.MIP介绍(Mixed Integer Program) Case1: Warehouse Location Case2: Knapsack Problem(Branch and Bound) 2.MIP模型(modeling) Case3: Coloring Problem(Big-M Transformation) 3.割平面法(Cutting planes) 4.多面体切割(Polyhedral Cuts) Cas…

前端工程化VUE-cli

六 前端工程化vue-cli Vue是渐近式框架&#xff0c;你可以用它一个功能&#xff0c;也可以用全家桶。前面的章节中&#xff0c;我们是在html中引入vue.js&#xff0c;只用它核心的数据绑定功能。但基于vue的扩展还有很多&#xff0c;比如vueRouter&#xff0c;axios&#xff0…

Base64编码剖析

文章目录Base64编码概述Base64原理索引表如何转换&#xff1f;Java实操Java代码实现Base64参考文章Base64编码概述 百度百科中对Base64有一个很好的解释&#xff1a;“Base64是网络上最常见的用于传输8Bit字节码的编码方式之一&#xff0c;Base64就是一种基于64个可打印字符来…

【面试题】5年前端 - 历时1个月收获7个offer

大厂面试题分享 面试题库 前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 前言 省流&#xff1a;最终拿到了58、UMU、便利蜂、虾皮、快手、腾讯、字节的offer。 金三银四面试的, 这次整体面试通过率还挺高的, …

深入解读云场景下的网络抖动

一、网络抖动背景 延时高&#xff0c;网络卡&#xff0c;卡住了美好&#xff01; 应用抖&#xff0c;业务惊&#xff0c;惊扰了谁的心&#xff1f; 当你在观看世界杯梅西主罚点球突然视频中断了几秒钟 当你在游戏中奋力厮杀突然手机在转圈圈无法响应 当你守候多时为了抢一…

数据结构与算法-二叉树

什么树 树是 n&#xff08;n>0&#xff09;个有限集。n0是空树&#xff0c;在n>1的非空树中有且仅有一个根节点作为树根&#xff0c;其他结构分散在根节点下形成一个个子树。各个子树互不相交。在实际的编码环节中&#xff0c;我们可以用链表和数组来模拟树结构。 为什么…

【计算机考研408】进程运行的流程

由程序段&#xff08;进程运行的程序的代码&#xff09;、相关数据段、和PCB&#xff08;进程存在的唯一标志&#xff09;三个部分构成了进程实体&#xff0c;也称作进程映像。 注&#xff1a;&#xff08;引入线程后&#xff09;进程只作为cpu外的系统资源的分配单元。 注&a…

DOM算法系列007-判定给定节点是否为空白节点

UID: 20221220141216 aliases: tags: source: cssclass: created: 2022-12-20 空白节点 什么是空白节点&#xff1f; 当一个节点的节点值为空文本值时&#xff0c;这个节点就是空白节点。 节点值&#xff1a; 即节点的 nodeValue 属性值&#xff1a; 实际上&#xff0c;节点值…

程序员必看:一款巨好用的免费简历“神器”(据说有了它,再也不发愁找工作啦!)

先说地址&#xff1a;https://cvmaker.greedyai.com/ 相比于前两年&#xff0c;今年大家的求职热情依然不减&#xff0c;但市场却泼了一盆“冰水”。 无论是从后台收到的留言&#xff0c;还是各种各样的新闻报道&#xff0c;以及今年的各大平台招聘数据来看&#xff0c;总结…

java多线程 下

目录 线程的生命周期 线程的同步 Synchronized的使用方法 同步机制中的锁 同步的范围 单例设计模式之懒汉式(线程安全) 线程的死锁问题 Lock(锁) synchronized 与 Lock 的对比 线程的通信 JDK5.0 新增线程创建方式 新增方式一&#xff1a;实现Callable接口 新增方式二…