算法系列-链表
前言
链表是一种物理存储单元上非连续、非顺序的存储结构,由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。。
一、链表分类
链表有以下几种
单链表
带头结点的单链表中,头指针head指向头结点,头结点的值域不含任何信息,从头结点的后继结点开始储存信息。头指针head 始终不等于NULL,head->next等于NULL的时候,链表为空。
双链表
双链表就是在单链表结点上增添了一个指针域,指向当前节点的前驱。相比于单链表,双链表能够从终端结点反向走到开始结点
此外还有 循环链表,静态链表 等,感兴趣的请参考访问 链表定义 。本文着重记录单链表。
//链表的实现方式
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
二、链表(牛客题库)
1.反转链表
public ListNode ReverseList(ListNode head) {
if(head==null||head.next==null) {
return head;
}
ListNode next = ReverseList(head.next);
head.next.next = head;
head.next =null;
return next;
}
}
2.链表内指定区间反转
public class Solution {
/**
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
public ListNode reverseBetween (ListNode head, int m, int n) {
// write code here
ListNode dummy =new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
ListNode cur = head;
for(int i=1;i<m;i++) {
pre = cur;
cur =cur.next;
}
for (int i=m;i<n;i++) { //头插法
ListNode temp = cur.next;
cur.next = temp.next;
temp.next = pre.next;
pre.next = temp;
}
return dummy.next;
}
}
}
3.合并k个已排序的链表
//合并k个已排序的链表
public class Solution {
public ListNode mergeKLists(ArrayList<ListNode> lists) {
// 使用优先队列将链表拼接即可
PriorityQueue<ListNode> queue = new PriorityQueue<>((o1,o2) -> o1.val-o2.val);
for(ListNode node:lists) {
if(node!=null) {
queue.add(node);
}
}
ListNode dummy = new ListNode(-1);
ListNode cur = dummy;
while(!queue.isEmpty()) {
ListNode node= queue.poll();
cur.next= node;
cur = node;
if(node.next!=null) {
queue.add(node.next);
}
}
return dummy.next;
}
}
4. 链表中环的入口结点
## 两个链表的第一个公共结点
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode fast=pHead1,slow=pHead2;
if(fast==null || slow==null) return null;
while(fast!=slow) {
slow = slow!=null ? slow.next:pHead1;
fast = fast!=null ? fast.next:pHead2;
}
return slow;
}
}