这是我参与「第四届青训营 」笔记创作活动的第3天
今天在牛客网刷算法,碰到一题,反转链表,当时直接懵了,因为数据结构的基础不牢固,而前端面试经常问到一些重要算法或是数据结构,为此整理了一下,在这里做个记录,方便以后查看。
1.题目长这样
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。 数据范围: 0≤n≤1000 要求:空间复杂度 O(1) ,时间复杂度 O(n) 。 如当输入链表{1,2,3}时,经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。
2.解决方法
那既然学的是前端,就用js来实现一下吧,顺便练习一下js的一些方法。 考虑到js是动态语言,没有指针,那么链表的数据域和指针域将通过构造函数来模拟。当然解决这道题的话不需要构造函数模拟整个链表的创建过程,只需要给出核心代码即可。
思路大概是这样,如果要反转链表,那么先假设这个链表只有三个数据,中间的那个记为current,他的前一个节点记作pre,后一个节点记作next,反转时只需要将current的指针域指向pre,然后交换pre,current和current,next两个节点对应的数据域即可;因此代码如下:
function ReverseList(pHead){
//如果链表为空,直接返回空表
if(!pHead) return null;
//假定当前节点为头节点
let cur=pHead;
let pre=null;
//当pre不为null时,反转完成;
while(pre){
let next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
js实现链表
既然做了这题,那就顺便把链表的一些方法也实现一遍吧。
首先构造两个类,一个用来创建节点,一个是链表的完整实现,将创建的节点组合成链表。代码如下:
class Node{
constructor(data){
this.data=data;
this.head=null;
}
}
class List{
constructor(){
this.len=0;
this.head=null;
}
}
整体结构大概是这样,剩下的就是在List类中添加增删改查的一些方法:
- 首先是添加节点的操作,需要指出的是,添加时需要指明位置,即在链表的什么位置添加,因此insert方法接受两个参数,一个是插入的位置的索引,另一个是插入的元素,代码如下:
insert(index,node){
if(index<0||index>this.len)throw new Error('插入位置不合法');
let ele=new Node(node);
if(index==0){
node.next=this.head;
this.head=node;
}else{
//调用getpos方法返回当前节点的前一个节点
let pre=this.getpos(index-1);
node.next=pre.next;
pre.next=node;
}
this.len++;
}
getpos(index){
if(index<0||index>=this.len)throw new Error('查找的元素不存在!');
for(let i=0;i<index;i++){
let cur=this.head;
cur.next=cur;
}
return cur;
}
2.删除操作,代码如下:
delnode(index){
if(index<0||index>this.len)throw new Error('指定元素不存在,删除失败!');
let cur=this.head;
if(index==0){
this.head=cur.next;
}else{
let pre=this.getpos(index-1);
cur=pre.next;
pre.next=cur.next;
}
this.len--;
}
3.查找元素,代码如下:
search(ele){
let cur=this.head;
for(let i=0;i<this.len;i++){
if(cur===ele){
return i;
}
return new Error('查找的元素不存在!')
}
}
ok,先记录到这里吧。