您的位置:首页 > 理论基础 > 数据结构算法

数据结构------链表

2020-01-12 10:54 148 查看

什么是链表

非连续非顺序的存储结构,以节点直接的指针指向进行遍历

链表的特性

1.无法随机读取元素,只能通过指针遍历,查找的时间复杂度O(n)
2.元素的删除和新增时间复杂度仅为O(1)

元素的插入和删除

存在链表1->2->3->4要在2和3之间插入节点,只需要将2的next指向newNode,将newNode的next指向3即可,如果要删除2节点,只需要将1的next指向3,2的next指向null。
代码实现:

function ListNode(val){
this.val = val;
this.next = null;
}
// 将node插入到指定的indexNode之后
function insertNode(indexNode,node){
let next = indexNode.next;
indexNode.next = node;
node.next = next;
}
// 删除node节点
function deleteNode(head,node){
let temp = head,
pre = null;
while(temp){
if(temp === node){
if(!pre){
pre.next = temp.next;
node.next = null;
}
}
pre = temp;
temp = temp.next;
}
}

leetcode题目

19. 删除链表的倒数第N个节点

题目描述
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:
给定的 n 保证是有效的。

思路:先遍历整个链表排列成一个数组,然后直接删除倒数第n个
我的代码:

/**
* Definition for singly-linked list.
* function ListNode(val) {
*     this.val = val;
*     this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
var nodeList = [head],
next=head.next;
while(next){
nodeList.push(next);
next = next.next;
};
//删除头部
if(nodeList.length === n){
return head.next;
}
if(nodeList[nodeList.length-n-1]){
nodeList[nodeList.length-n-1].next = nodeList[nodeList.length-n].next;
}
nodeList[nodeList.length-n].next = null;
if(nodeList.length === 1){
return null;
}
return head;
};

23.合并k和排序链表

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例:

输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6

思路:
先用bfs宽度遍历每个链条同级的元素按顺序放进一个list中,然后按list的顺序生成新的链表

我的代码:

/**
* Definition for singly-linked list.
* function ListNode(val) {
*     this.val = val;
*     this.next = null;
* }
*/
/**
* @param {ListNode[]} lists
* @return {ListNode}
*/
var mergeKLists = function(lists) {
if(!lists||!lists.length){
return null;
}
// bfs获取所有节点的集合
var newList = [],
head = null,
tempNode;
bfs(lists,newList);
newList.sort((node1,node2)=>node1.val-node2.val);
head = newList[0];
tempNode = head;
for(let i=1;i<newList.length;i++){
tempNode.next = newList[i];
tempNode = newList[i];
}
return head || null;
};
var bfs = function(lists,newList){
if(!lists || !lists.length){
return;
}else{
let next = [];
for(let i=0;i<lists.length;i++){
let node = lists[i];
if(node){
if(node.next){
next.push(node.next);
}
newList.push(new ListNode(node.val));
}
}
bfs(next,newList);
}
}

25. K 个一组翻转链表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5

说明 :
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

思路:
逐个遍历,记住每组第一个元素,当遍历到个数为k时对这一组进行交换,返回当前组的最后一个最新的元素和下一组的第一个元素,如果存在上一组的第一个元素那么就将其和当前组的最后一个元素进行连接。

我的代码:

/**
* Definition for singly-linked list.
* function ListNode(val) {
*     this.val = val;
*     this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var reverseKGroup = function(head, k) {
if(k===1){
return head;
}
if(!canReverse(head,k)){
return head;
}
let node = head,
preNode = node,
realHead = null,
temp;
while(node!==null){
if(!canReverse(node,k)){
preNode.next = node;
return realHead;
}
temp = reverse(node,k);
if(!realHead){
// 真正的头是第一次翻转组的最后一个
realHead = temp[0];
}else{
// 上一组的第一个指向当前组的最后一个
preNode.next = temp[0];
preNode = node;
}
node = temp[1];
}
return realHead;
};

var reverse = function(node,k){
let pre = null,
next,
curr = node,
i=1;
while(i<=k&&curr!==null){
// 节点交换
next = curr.next;
curr.next = pre;
pre = curr;
curr = next;
i++;
}
return [pre,curr];
}
var canReverse = function(node,k){
let num=0,
temp = node;
while(temp&&num<k){
num++;
temp = temp.next;
}
if(num===k){
return true;
}else{
return false;
}
}
  • 点赞
  • 收藏
  • 分享
  • 文章举报
逆行的小白菜 发布了14 篇原创文章 · 获赞 3 · 访问量 269 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: