练习题(2024/5/13)

1移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

提示:

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

思路:

使用虚拟头结点的方法来简化链表的删除操作。首先,创建一个值为0的虚拟头结点,然后将其指向原始链表的头部。接着,使用一个指针 cur 遍历整个链表,当 cur->next 的值等于目标值 val 时,删除当前节点的下一个节点,并将当前节点指向下下个节点;否则,将 cur 指针向后移动一个节点。最后,返回虚拟头结点的下一个节点作为新的链表头部。

代码:

class Solution {
public:// 删除链表中值为 val 的所有节点ListNode* removeElements(ListNode* head, int val) {// 设置一个虚拟头结点ListNode* dummyHead = new ListNode(0);// 将虚拟头结点指向 head,这样方便后面做删除操作dummyHead->next = head;ListNode* cur = dummyHead;// 遍历链表while (cur->next != NULL) {// 如果当前节点的下一个节点的值等于 val,则删除下一个节点if(cur->next->val == val) {ListNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;} else {cur = cur->next;}}// 更新 head 指针head = dummyHead->next;// 删除虚拟头结点delete dummyHead;return head;}
};

2设计链表

你可以选择使用单链表或者双链表,设计并实现自己的链表。

单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。

如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。

实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

示例:

输入
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2);    // 链表变为 1->2->3
myLinkedList.get(1);              // 返回 2
myLinkedList.deleteAtIndex(1);    // 现在,链表变为 1->3
myLinkedList.get(1);              // 返回 3

提示:

  • 0 <= index, val <= 1000
  • 请不要使用内置的 LinkedList 库。
  • 调用 getaddAtHeadaddAtTailaddAtIndex 和 deleteAtIndex 的次数不超过 2000 。

思路:

这道题的要求有五个:

  • 获取链表第index个节点的数值
  • 在链表的最前面插入一个节点
  • 在链表的最后面插入一个节点
  • 在链表第index个节点前面插入一个节点
  • 删除链表的第index个节点
  1. 定义节点结构体: 开始先定义了一个嵌套的节点结构体LinkedNode,它包含两个成员变量,一个是节点的值val,另一个是指向下一个节点的指针next

  2. 初始化链表: 在MyLinkedList类的构造函数中,创建了一个虚拟头结点_dummyHead,它的val为0,nextnullptr,用来简化链表的操作。同时初始化了链表的大小_size为0。

  3. 获取节点值: get(int index)函数用于获取链表中第index个节点的值。通过判断index是否合法,然后从虚拟头结点开始遍历找到目标节点,并返回其值。

  4. 在头部插入节点: addAtHead(int val)函数用于在链表的头部插入一个新节点。先创建一个新节点,然后将新节点的next指向原头结点,再将虚拟头结点的next指向新节点,最后更新链表大小。

  5. 在尾部插入节点: addAtTail(int val)函数用于在链表的尾部插入一个新节点。从虚拟头结点开始遍历找到最后一个节点,然后将其next指向新节点,最后更新链表大小。

  6. 在指定位置插入节点: addAtIndex(int index, int val)函数用于在指定位置插入一个新节点。首先判断插入位置的合法性,然后从虚拟头结点开始遍历找到目标位置的前一个节点,插入新节点,并更新链表大小。

  7. 删除指定位置的节点: deleteAtIndex(int index)函数用于删除指定位置的节点。同样需要判断位置的合法性,然后找到目标位置的前一个节点,将其next指针跳过待删除节点,删除节点并释放内存,最后更新链表大小。

代码:

class MyLinkedList {
public:// 定义链表节点结构体struct LinkedNode {int val; // 节点的值LinkedNode* next; // 指向下一个节点的指针LinkedNode(int val):val(val), next(nullptr){}
//LinkedNode(int val) : val(val), next(nullptr) {}这行代码创建了一个LinkedNode结构体的构造函数,它接受一个整数参数val,并将val赋值给节点的val成员,同时将next指针初始化为nullptr。};// 初始化链表MyLinkedList() {_dummyHead = new LinkedNode(0); // 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点_size = 0;}// 获取到第index个节点数值,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点int get(int index) {if (index > (_size - 1) || index < 0) { // 判断index是否合法return -1;}LinkedNode* cur = _dummyHead->next; // 从第一个真正的节点开始while(index--) { // 循环找到第index个节点cur = cur->next;}return cur->val; // 返回该节点的值}// 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点void addAtHead(int val) {LinkedNode* newNode = new LinkedNode(val); // 创建一个新节点newNode->next = _dummyHead->next; // 将新节点的next指针指向原来的第一个节点_dummyHead->next = newNode; // 将虚拟头结点指向新节点_size++; // 更新链表长度}// 在链表最后面添加一个节点void addAtTail(int val) {LinkedNode* newNode = new LinkedNode(val); // 创建一个新节点LinkedNode* cur = _dummyHead; // 从虚拟头结点开始遍历while(cur->next != nullptr){ // 找到最后一个节点cur = cur->next;}cur->next = newNode; // 将新节点加在最后一个节点之后_size++; // 更新链表长度}// 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。// 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点// 如果index大于链表的长度,则返回空// 如果index小于0,则在头部插入节点void addAtIndex(int index, int val) {if(index > _size) return; // 如果index大于链表长度,则直接返回if(index < 0) index = 0; // 如果index小于0,则在头部插入节点LinkedNode* newNode = new LinkedNode(val); // 创建一个新节点LinkedNode* cur = _dummyHead; // 从虚拟头结点开始遍历while(index--) { // 找到第index个节点的前一个节点cur = cur->next;}newNode->next = cur->next; // 将新节点的next指针指向当前节点的next指针指向的节点cur->next = newNode; // 将当前节点的next指针指向新节点_size++; // 更新链表长度}// 删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的void deleteAtIndex(int index) {if (index >= _size || index < 0) { // 如果index大于等于链表长度或小于0,则直接返回return;}LinkedNode* cur = _dummyHead; // 从虚拟头结点开始遍历while(index--) { // 找到第index个节点的前一个节点cur = cur ->next;}LinkedNode* tmp = cur->next; // 保存待删除节点cur->next = cur->next->next; // 将待删除节点的前一个节点指向待删除节点的后一个节点delete tmp; // 释放待删除节点的内存tmp=nullptr; // 将指向待删除节点的指针置空,避免成为野指针_size--; // 更新链表长度}private:int _size; // 链表长度LinkedNode* _dummyHead; // 虚拟头结点指针
};

3有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

提示:

  • 1 <= s.length, t.length <= 5 * 104
  • s 和 t 仅包含小写字母

思路:

  1. 记录字母出现次数: 首先,代码使用一个长度为26的整型数组record来记录每个字母出现的次数,数组的索引与字母的ASCII码对应,这样可以将小写字母映射到record数组的相应位置。

  2. 遍历第一个字符串: 然后,代码遍历字符串s,对于每个字符,将其出现的次数记录在record数组中相应的位置。

  3. 遍历第二个字符串: 接着,代码同样遍历字符串t,对于每个字符,将其出现的次数从record数组中相应位置减去。

  4. 检查记录数组: 最后,代码遍历record数组,如果发现有任何一个位置的值不为0,说明两个字符串中有不同数量的某个字母,即它们不是字母异位词,返回false;如果record数组所有位置的值都为0,则说明两个字符串是字母异位词,返回true

代码:

class Solution {
public:// 判断两个字符串是否是字母异位词bool isAnagram(string s, string t) {// 记录每个字母出现的次数的数组,初始值都为0int record[26] = {0};// 遍历字符串s,统计每个字母出现的次数for (int i = 0; i < s.size(); i++) {// 将字母映射到record数组的索引,统计出现次数record[s[i] - 'a']++;}// 遍历字符串t,统计每个字母出现的次数for (int i = 0; i < t.size(); i++) {// 将字母映射到record数组的索引,减去出现次数record[t[i] - 'a']--;}// 遍历record数组,如果有非零值,则说明不是字母异位词for (int i = 0; i < 26; i++) {if (record[i] != 0)return false;}// 如果record数组所有元素都为0,则说明是字母异位词return true;}
};

4两个数组的交集

给定两个数组 nums1 和 nums2 ,返回 它们的 

交集

 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000

思路:

代码:

class Solution {
public:// 求两个数组的交集vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {// 用于存储结果的无序集合unordered_set<int> result_set;// 将 nums1 转化为无序集合,方便进行查找unordered_set<int> nums_set(nums1.begin(), nums1.end());// 遍历 nums2,查找是否存在于 nums1 中,存在则加入结果集合for (int num : nums2) {if (nums_set.find(num) != nums_set.end()) {result_set.insert(num);}}// 将结果集合转化为数组并返回return vector<int>(result_set.begin(), result_set.end());}
};

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何对基本公共服务均等化进行统计监测

党的十九大指出“履行好政府再分配调节职能&#xff0c;加快推进基本公共服务均等化&#xff0c;缩小收入分配差距”&#xff0c;提出到2035年基本公共服务均等化基本实现。国务院相继于2012年和2017年发布了《国家基本公共服务体系“十二五”规划》和《“十三五”推进基本公共…

基于安装包安装数据库时出现的问题分析及总结

数据库在数据初始化后并不会出现错误&#xff0c;这个时候在启动数据库时会出现启动不成功&#xff0c;不知道问题是什么要学会通过查看日志发现问题&#xff0c;日志就在Data文件夹下。 错误类型1 数据库在初始化后数据库启动不起来 原因&#xff1a;可能是配置文件my.ini一些…

深入探索内存映射:mmap和共享内存的工作原理及区别

目录标题 1. 引言 1.1 内存映射的定义1.2 mmap 系统调用概述 2. 内存映射基础 2.1 内存映射的定义2.2 mmap 系统调用概述2.3 mmap 系统调用和直接使用IPC共享内存之间的差异 3. mmap 与文件 I/O 3.1. 传统文件 I/O 的局限性3.2. mmap 的优势 4. 内存映射的工作原理&…

力扣HOT100 - 198. 打家劫舍

解题思路&#xff1a; 动态规划 class Solution {public int rob(int[] nums) {int len nums.length;if (nums null || len 0) return 0;if (len 1) return nums[0];int[] dp new int[len];dp[0] nums[0];dp[1] Math.max(nums[0], nums[1]);for (int i 2; i < len;…

智能AI数字人系统 打造无人直播间 主播形象任意选择!

系统概述 智能AI数字人系统是一种结合人工智能、计算机图形学、语音合成等技术的综合性系统。该系统能够模拟人类的外貌、行为和语言&#xff0c;为用户提供逼真的交互体验。在无人直播间场景下&#xff0c;智能AI数字人系统可以扮演主播角色&#xff0c;与观众进行实时互动&a…

AIConnect 综合算力服务网络:引领智能未来,创造无限可能性!

2022年11月30日&#xff0c;由OpenAI开发的大模型聊天机器人GPT-3发布&#xff0c;首个完全意义上通过图灵测试的人工智能诞生了。这一里程碑事件的启发了人们对AI技术的发展和应用。在短短两年的时间里&#xff0c;各式各样的聊天AI&#xff0c;图片生成AI&#xff0c;视频生成…

Springboot+MybatisPlus如何实现分页和模糊查询

实现分页查询的时候我们需要创建一个config配置类 1、创建MybatisPlusConfig类 Configuration //表明这是一个配置类 ConditionalOnClass(Value{PaginationInterceptor.class} //ConditionalOnClass:当指定的类存在时&#xff0c;才会创建对应的Bean // 这里当PaginationInt…

【Linux】用户组、用户、文件权限(ugo权限),权限掩码,chmod,chown,suid,sgid,sticky,su,sudo

用户组 注意&#xff1a;普通用户只能查看有哪些组&#xff0c;不能创建/修改/删除&#xff0c;会提示&#xff1a;用户名 is not in the sudoers file.This incident will be reported. groupadd 用户组名新建用户组cat /etc/group查看有哪些组&#xff08;普通用户可以操作…

性能测试学习二

瓶颈的精准判断 TPS曲线 tps图 响应时间图 拐点在哪里呢? 这是一个阶梯式增加的场景,拐点在第二个压力阶梯上就出现了,因为响应时间增加了,tps增加的却不多,在第三个阶段时,tps增加的就更少了,响应时间也在不断增加,所以性能瓶颈在加剧,越往后越明显【tps的增长,…

Echarts使用

介绍 ECharts 是一个强大的&#xff0c;基于 JavaScript 的开源数据可视化库&#xff0c;适用于创建多种类型的图表&#xff0c;满足广泛的业务需求。它由百度团队开发并维护&#xff0c;后来捐赠给了 Apache 软件基金会&#xff0c;并已在2021年从孵化项目毕业&#xff0c;成…

C++复习 -- 常用关键字

this 关键字: 概念 在 C 中&#xff0c; this 关键字是一个指向调用对象的指针。它在成员函数内部使用&#xff0c;用于引用调用该函数的对象。使用 this 可以明确指出成员函数正在操作的是哪个对象的数据成员。 case :证明他就是一个指向被调用对象的指针: #include <iost…

Linux内核发送网络数据

前言 我们开始今天对 Linux 内核⽹络发送过程的深度剖析。还是按照我们之前的传统&#xff0c;先从⼀段代码作为切⼊。 上述代码中&#xff0c;调⽤ send 之后内核是怎么样把数据包发送出去的。本⽂基于Linux 3.10&#xff0c;⽹卡驱动采⽤Intel的igb举例。 基础框架 我们看…