【华为机试ACM基础#02】从单向链表中删除指定值的节点、输出单向链表中倒数第k个节点(熟悉链表的输入方式)
从单向链表中删除指定值的节点
输入一个单向链表和一个节点的值,从单向链表中删除等于该值的节点,删除后如果链表中无节点则返回空指针。
链表的值不能重复。
构造过程,例如输入一行数据为:
6 2 1 2 3 2 5 1 4 5 7 2 2
则第一个参数6表示输入总共6个节点,第二个参数2表示头节点值为2,剩下的2个一组表示第2个节点值后面插入第1个节点值,为以下表示:
1 2 表示为
2->1
链表为2->1
3 2表示为
2->3
链表为2->3->1
5 1表示为
1->5
链表为2->3->1->5
4 5表示为
5->4
链表为2->3->1->5->4
7 2表示为
2->7
链表为2->7->3->1->5->4
最后的链表的顺序为 2 7 3 1 5 4
最后一个参数为2,表示要删掉节点为2的值
删除 结点 2
则结果为 7 3 1 5 4
数据范围:链表长度满足 1≤�≤1000 1≤n≤1000 ,节点中的值满足 0≤���≤10000 0≤val≤10000
测试用例保证输入合法
输入描述:
输入一行,有以下4个部分:
1 输入链表结点个数
2 输入头结点的值
3 按照格式插入各个结点
4 输入要删除的结点的值
输出描述:
输出一行
输出删除结点后的序列,每个数后都要加空格
思路
如果这题是在LeetCode用核心代码模式做的话,是一道很常规的题目,只需要遍历单向链表,找到与目标值匹配的节点后删除即可
在ACM模式下,输入输出就成了大问题
为了理顺逻辑,最好将删除功能单独写成一个函数
那么,整体逻辑就是:从输入数据中拿到头节点,遍历输入数据,将链表构建好,然后调用删除函数将指定节点删除,最后再把链表的值打印出来
#include<iostream>
using namespace std;
struct ListNode{
};
ListNode* deleteNode(ListNode* head, int val) {//删除链表中值为val的节点
}
int main(){
}
定义结构体
先定义一个结构体作为链表节点(详见:构造链表)
struct ListNode{
int val;
ListNode* next;
ListNode(int x):val(x), next(nullptr){}
};
删除函数
使用dummy进行删除(注意,这里和设计链表中的删除函数还不太一样,这里需要根据节点值进行删除而不是索引值)
ListNode* deleteNode(ListNode* head, int val) {//删除链表中值为val的节点
if(head == nullptr) return nullptr;//特判:如果头结点为空,返回空指针
if(head->val == val) return head->next;//特判:如果头结点的值等于val,直接返回头结点的下一个节点
ListNode* dummy = new ListNode(0);//创建dummy节点,接在头节点之前
dummy->next = head;
ListNode* cur = dummy;
while(cur->next != nullptr){
if(cur->next->val == val){//处理被删除的节点
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
return dummy->next;
}
主函数
在主函数里,我们需要接受一行输入数据,例如:
6 2 1 2 3 2 5 1 4 5 7 2 2
则第一个参数6表示输入总共6个节点,第二个参数2表示头节点值为2,剩下的2个一组表示第2个节点值后面插入第1个节点值
根据题目描述,我们需要两个两个的从输入数据中取值,过程如下:
取1、2,表示2要接在1后面【链表为2->1】
接下来取2、3,表示3要接在2后面【链表为2->3->1】
然后取5、1,表示5要接在1后面【链表为2->3->1->5】
取4、5,表示5要接在4后面【链表为2->3->1->5->4】...
实际上题目除了要我们从单向链表中删除指定值的节点,还需要我们根据输入数据按照规则来先构建链表
int main(){
//定义几个变量分别接收:链表节点数量(例子中的6)、头节点的值(例子中的2)、待删除节点的值
int n, head_val, val;
cin >> n >> head_val;
ListNode* head = new ListNode(head_val); //创建头结点
for(int i = 0; i < n-1; i++){ //循环插入剩余的n-1个节点
int pre_val, cur_val;//取两个值(如例子中的1、2)
cin >> cur_val >> pre_val; //输入当前节点的值和需要插入的位置的节点的值
ListNode* pre = head;
while(pre != NULL && pre->val != pre_val) //遍历链表,找到需要插入的节点
pre = pre->next;
ListNode* cur = new ListNode(cur_val); //创建当前节点
cur->next = pre->next; //将当前节点插入至链表中
pre->next = cur;
}
}
然后再从输入中获取待删除值,调用删除函数,之后遍历打印链表即可
cin >> val; //输入需要删除的节点的值
head = deleteNode(head, val); //删除节点
while(head != NULL){ //遍历打印链表
cout << head->val << " ";
head = head->next;
}
代码
#include<iostream>
using namespace std;
struct ListNode{
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode* deleteNode(ListNode* head, int val) {//删除链表中值为val的节点
if(head == nullptr) return nullptr;//特判:如果头结点为空,返回空指针
if(head->val == val) return head->next;//特判:如果头结点的值等于val,直接返回头结点的下一个节点
ListNode* dummy = new ListNode(0);//创建dummy节点,接在头节点之前
dummy->next = head;
ListNode* cur = dummy;
while(cur->next != nullptr){
if(cur->next->val == val){//处理被删除的节点
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
return dummy->next;
}
int main(){
int n, head_val, val;
cin >> n >> head_val;
ListNode* head = new ListNode(head_val); //创建头结点
for(int i = 0; i < n-1; i++){ //循环插入剩余的n-1个节点
int cur_val, pre_val;//取两个值(如例子中的1、2)
cin >> cur_val >> pre_val; //输入当前节点的值和需要插入的位置的节点的值
ListNode* pre = head;
while(pre != NULL && pre->val != pre_val) //遍历链表,找到需要插入的节点
pre = pre->next;
ListNode* cur = new ListNode(cur_val); //创建当前节点
cur->next = pre->next; //将当前节点插入至链表中
pre->next = cur;
}
cin >> val; //输入需要删除的节点的值
head = deleteNode(head, val); //删除节点
while(head != NULL){ //遍历打印链表
cout << head->val << " ";
head = head->next;
}
return 0;
}
输入输出总结
其实也没啥好总结的这题,本来以为可以用来当做ACM下链表输入的参考的,结果使用的还是cin
但是观察这题可以发现:ACM下,题目要求的输入有可能不是一次性输入完成的
例如本题,题目举的例子是6 2 1 2 3 2 5 1 4 5 7 2 2,如果一开始没明白题意的话很容易以为输入数据的形式就是这个,导致后续处理很困难
还有就是复习了一下删除指定节点值的操作,练习了链表的构造
输出单向链表中倒数第k个结点(构造链表、输入tips)
输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第1个结点为链表的尾指针。
链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
正常返回倒数第k个结点指针,异常返回空指针.
要求:
(1)正序构建链表;
(2)构建后要忘记链表长度。
数据范围:链表长度满足 1≤�≤1000 1≤n≤1000 , �≤� k≤n ,链表中数据满足 0≤���≤10000 0≤val≤10000
本题有多组样例输入。
输入描述:
输入说明
1 输入链表结点个数
2 输入链表的值
3 输入k的值
输出说明:输出一个整数
输入:
8
1 2 3 4 5 6 7 8
4
输出:5
思路
参考删除链表倒数第N个节点,使用快慢双指针即可找出本题中倒数第K个节点
但是要注意,本题不是要删除该节点,因此要和上述题目作区分
在本题中,快指针只需要比慢指针先走k步就行,不用k+1
剩下的问题还有两个:数据输入、正向链表构造
数据输入
虽然还是用cin来获取用户的输入数据,但是这里有个使用技巧,即cin与while配合使用
形式如下:
int main() {
int nodeNums;//节点个数
while(cin >> nodeNums){
}
return 0;
}
由题意,我们需要先输入链表的节点个数,此时可以将接收的代码写在while里面
这样当用户(这里其实是OJ)输入8,循环开始,我们可以在循环内处理其他逻辑
当本次循环结束,若用户没有输入,则退出循环,程序结束。
OJ会不断输入测试用例直到测试完毕才会停止输入,那时候正好跳出循环,程序结束
链表构造
和上题不同,本题是要求我们按规定的顺序构建链表,不涉及穿插节点,因此适用性更广
int main() {
int nodeNums;//节点个数
while(cin >> nodeNums){
int nodeVal;//接收用户输入的节点值
ListNode* dummy = new ListNode(0);
ListNode* cur = dummy;
for(int i = 1; i <= nodeNums; ++i){//正序构建链表
cin >> nodeVal;
ListNode* node4add = new ListNode(nodeVal);
cur->next = node4add;
cur = cur->next;
}
}
return 0;
}
进入循环后,继续接收用户输入的值作为节点的值
创建dummy和cur指针,在遍历过程中不断接收节点值,用于构造临时节点node4add,该节点被连接到cur后
随着cur的移动,链表构造完毕
后面只需要根据输入的k值,找到对应节点并返回其值即可
注意!!!使用快慢指针时,快指针只需要提前k步
注意!!!使用快慢指针时,快指针只需要提前k步
注意!!!使用快慢指针时,快指针只需要提前k步
代码
#include <iostream>
using namespace std;
struct ListNode{
int val;
ListNode* next;
ListNode(int x): val(x), next(nullptr){}
};
int main() {
int nodeNums;//节点个数
while(cin >> nodeNums){
int nodeVal;
ListNode* dummy = new ListNode(0);
ListNode* cur = dummy;
for(int i = 1; i <= nodeNums; ++i){//正序构建链表
cin >> nodeVal;
ListNode* node4add = new ListNode(nodeVal);
cur->next = node4add;
cur = cur->next;
}
int k;
cin >> k;
//使用双指针寻找倒数第k个节点
ListNode* fast = dummy;
ListNode* slow = dummy;
// k--;//fast指针不用从k+1开始走,因为本题不是要删除倒数第k个节点,而是要返回其值
for(int i = k; i > 0; --i){//fast指针先走k步
if(fast == nullptr) break;
fast = fast->next;
}
while(fast != nullptr){//同时走,直到fast为nullptr
fast = fast->next;
slow = slow->next;
}
cout << slow->val << endl;
}
return 0;
}
【华为机试ACM基础#02】从单向链表中删除指定值的节点、输出单向链表中倒数第k个节点(熟悉链表的输入方式)的更多相关文章
- 华为机试ACM(字符组合问题)
今晚做了华为的机试,3道ACM题,最后一道是实现从M个不同字符中任取N个字符的所有组合. eg: input:ABC 2 output:AB AC BC 第一个输入为字符串,第二个输入为组合的字符个数 ...
- java笔试之从单向链表中删除指定值的节点
输入一个单向链表和一个节点的值,从单向链表中删除等于该值的节点,删除后如果链表中无节点则返回空指针. 链表的值不能重复 构造过程,例如 1 -> 2 3 -> 2 5 -> 1 4 ...
- 2014华为机试西安地区A组试题
2014华为机试西安地区A组试题 题目一.分苹果 M个同样苹果放到N个同样篮子里有多少种放法,同意有篮子不放. 1<=M<=10.1<=N<=10 比如5个苹果三个篮子,3,1 ...
- 2014华为机试西安地区B组试题
2014华为机试西安地区B组试题 题目一.亮着点灯的盏数 一条长廊里依次装有n(1≤n≤65535)盏电灯,从头到尾编号1.2.3.-n-1.n.每盏电灯由一个拉线开关控制.開始,电灯所有关着. 有n ...
- 华为机试001:字符串最后一个单词的长度(华为OJ001)
华为机试 字符串最后一个单词的长度 计算字符串最后一个单词的长度,单词以空格隔开. 提交网址: http://www.nowcoder.com/practice/8c949ea5f36f422594b ...
- 寻找单向链表的倒数第k个节点
题目: 输入一个单向链表,输出这个单向链表的倒数第k个节点 template<class T> class ListNode { public: T Data; ListNode<T ...
- 数据结构——求单向链表的倒数第K个节点
首先,对于链表来说,我们不能像数组一样直接访问,所以我们想到要求倒数第K个节点首先要知道最后一个节点. 然后从最后一个节点往前数K个. 最后得到想要的值. 但是这是不对的,为什么呢?因为题目给出的是单 ...
- 数据结构和算法之单向链表二:获取倒数第K个节点
我们在做算法的时候或多或少都会遇到这样的问题,那就是我们需要获取某一个数据集的倒数或者正数第几个数据.那么今天我们来看一下这个问题,怎么去获取倒数第K个节点.我们拿到这个问题的时候自然而然会想到我们让 ...
- LeetCode 面试题 02.02. 返回倒数第 k 个节点
题目链接:https://leetcode-cn.com/problems/kth-node-from-end-of-list-lcci/ 实现一种算法,找出单向链表中倒数第 k 个节点.返回该节点的 ...
- 面试题 02.02. [链表][双指针]返回倒数第 k 个节点
面试题 02.02. 返回倒数第 k 个节点 方法一:使用外部空间 // 执行用时: 1 ms , 在所有 Java 提交中击败了 16.75% 的用户 // 内存消耗: 36.8 MB , 在所有 ...
随机推荐
- [转帖]台积电3nm成功量产,稳了吗?
https://docs.pingcode.com/info/13836.html?p=13836 2023-01-19 资讯 21 原标题:台积电3纳米成功量产:未来与三星仍将决战鳍式场效晶体管(F ...
- K8S 使用loki 监控 应用日志的搭建办法
1. 背景 这几天一直在用k8s部署分SU的测试环境,开发反馈看日志比较麻烦. 昨天晚上在家里本来想搭建ELK 发现比较重, 又说有一个比较轻量级的 loki 可以实现使用grafana进行监控和查看 ...
- pytest.ini配置文件
pytest.ini文件是pytest框架独有的配置文件,主要作用就是在运行pytest.main时可指定运行顺序,也 就相当于在Terminal输入pytest+参数+路径效果一致,下面介绍几种简单 ...
- Vue中Vue.set()和this.$forceUpdate()的使用
1.给对象添加一个key值 成功的 <template> <div> <p>{{userInfo.name}}</p> <p>{{userI ...
- 每日一库:使用Viper处理Go应用程序的配置
在开发Go应用程序时,处理配置是一个常见的需求.配置可能来自于配置文件.环境变量.命令行参数等等.Viper是一个强大的库,可以帮助我们处理这些配置. 什么是Viper? Viper是一个应用程序配置 ...
- session未过期就丢失的原因以及处理方式
转 https://blog.csdn.net/flamelp/article/details/5316725?utm_medium=distribute.pc_relevant.none-task- ...
- 搭建mongo的replica set
搭建mongo的replica set 前言 安装 构建副本集 加入认证 备份数据 备份数据到本地 数据恢复 搭建mongo的replica set 前言 准备三台机器,相互可以访问的.处理思路,先构 ...
- 【Jmeter】基础介绍-详细
最近做压测时使用到Jmeter,为什么用它,之前也做过部分压测,不是很系统,使用的是Apache Bench,虽然效率高,但是功能比较简单,不太适合本次压测场景,另外Jmeter能更好的利用压测机的多 ...
- NLP国内外大模型汇总列表[文心一言、智谱、百川、星火、通义千问、盘古等等]
NLP国内外大模型汇总列表[文心一言.智谱.百川.星火.通义千问.盘古等等] 中国大模型列表大全,全面收集有明确来源的大模型情况,包括机构.来源信息和分类等,随时更新. Awesome family ...
- 3.5 Windows驱动开发:应用层与内核层内存映射
在上一篇博文<内核通过PEB得到进程参数>中我们通过使用KeStackAttachProcess附加进程的方式得到了该进程的PEB结构信息,本篇文章同样需要使用进程附加功能,但这次我们将实 ...