关于链表常用的算法总结
介绍
单链表
每一个节点由两部分组成,一个是数据一个是指针(存放指向下一个节点的指针),最后一个节点的指针指向null
public class ListNode {
int val;
ListNode next;
public ListNode() {
}
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
双链表
双链表:每一个节点有两个指针,一个指向下一个节点,一个指向上一个节点。
public class ListNode {
int val;
ListNode next;
ListNode prev;
public ListNode() {
}
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next,ListNode prev) {
this.val = val;
this.next = next;
this.prev = prev;
}
}
循环链表
循环链表,就是链表首尾相连。
循环链表可以用来解决约瑟夫环问题。
Josephu 问题为:设编号为 1,2,… n 的 n 个人围坐一圈,约定编号为 k(1<=k<=n)的人从 1 开始报数,数到 m 的那个人出列,它的下一位又从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
链表的存储方式
链表是通过指针链接在内存中各个节点,所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
Leetcode
707. 设计链表 - 力扣(LeetCode) (leetcode-cn.com)
class MyLinkedList {
int size;
ListNode head,tail;
public MyLinkedList() {
size = 0;
head = new ListNode(0);
tail = new ListNode(0);
head.next = tail;
tail.prev = head;
}
public int get(int index) {
if(index > size-1|| index<0)return -1;
ListNode cur = head;
if((size/2) > index){
for(int i = 0; i <=index;i++)
cur = cur.next;
}else{
cur = tail;
for(int i = size-1;i>=index;i--)
cur = cur.prev;
}
return cur.val;
}
public void addAtHead(int val) {
ListNode newnode = new ListNode(val);
ListNode cur = head;
newnode.next = cur.next;
cur.next = newnode;
newnode.prev = cur;
newnode.next.prev = newnode;
size++;
}
public void addAtTail(int val) {
ListNode newnode = new ListNode(val);
ListNode cur = tail;
cur.prev.next = newnode;
newnode.next = cur;
newnode.prev = cur.prev;
cur.prev = newnode;
size++;
}
public void addAtIndex(int index, int val) {
if(index > size) return;
if(index < 0) index = 1;
ListNode newnode = new ListNode(val);
ListNode cur = head;
for(int i =0;i<index;i++){
cur=cur.next;
}
newnode.next = cur.next;
cur.next = newnode;
newnode.prev = cur;
cur.next.next.prev = newnode;
size++;
}
public void deleteAtIndex(int index) {
if(index <0|| index>size-1) return;
ListNode cur = head;
for(int i =0;i<index;i++){
cur = cur.next;
}
cur.next.next.prev = cur;
cur.next = cur.next.next;
size--;
}
}
public class ListNode {
int val;
ListNode next;
ListNode prev;
ListNode(int val) { this.val = val; }
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.get(index);
* obj.addAtHead(val);
* obj.addAtTail(val);
* obj.addAtIndex(index,val);
* obj.deleteAtIndex(index);
*/
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
size = 0;
head = new ListNode(0);
}
public int get(int index) {
if(index < 0 || index>=size) return -1;
ListNode cur = head;
for(int i = 0; i<=index;i++){
cur = cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0,val);
}
public void addAtTail(int val) {
addAtIndex(size,val);
}
public void addAtIndex(int index, int val) {
if(index > size) return;
if(index < 0) index = 0;
size ++;
ListNode pre = head;
for(int i =0;i<index;i++){
pre = pre.next;//找到前一个节点的位置
}
ListNode toadd = new ListNode(val);
toadd.next = pre.next;
pre.next = toadd;
}
public void deleteAtIndex(int index) {
if(index < 0|| index>=size) return;
size--;
ListNode pre = head;
for(int i = 0; i<index;i++){
pre = pre.next;
}
pre.next = pre.next.next;
}
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.get(index);
* obj.addAtHead(val);
* obj.addAtTail(val);
* obj.addAtIndex(index,val);
* obj.deleteAtIndex(index);
*/
203. 移除链表元素 - 力扣(LeetCode) (leetcode-cn.com)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
while(head != null && head.val == val) head = head.next;
if(head == null) return head;
ListNode cur = head;
while(cur.next != null){
if(cur.next.val == val){
cur.next = cur.next.next;
}else{
cur = cur.next;
}
}
return head;
}
}
206. 反转链表 - 力扣(LeetCode) (leetcode-cn.com)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null,head);
}
private ListNode reverse(ListNode prev,ListNode cur){
while(cur !=null){
ListNode temp = cur.next;
cur.next = prev;
prev = cur;
cur = temp;
}
return prev;
}
}
24. 两两交换链表中的节点 - 力扣(LeetCode) (leetcode-cn.com)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode prev = dummyNode;
while (prev.next != null && prev.next.next != null) {
ListNode temp = head.next.next; // 缓存 next
prev.next = head.next; // 将 prev 的 next 改为 head 的 next
head.next.next = head; // 将 head.next(prev.next) 的next,指向 head
head.next = temp; // 将head 的 next 接上缓存的temp
prev = head; // 步进1位
head = head.next; // 步进1位
}
return dummyNode.next;
}
}
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode) (leetcode-cn.com)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode slow = dummy;
ListNode fast = dummy;
while(n-->0) fast = fast.next;
ListNode prev = null;
while(fast != null){
prev = slow;
fast = fast.next;
slow = slow.next;
}
prev.next = slow.next;
return dummy.next;
}
}
面试题 02.07. 链表相交 - 力扣(LeetCode) (leetcode-cn.com)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0, lenB = 0;
while (curA != null) { // 求链表A的长度
lenA++;
curA = curA.next;
}
while (curB != null) { // 求链表B的长度
lenB++;
curB = curB.next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
//1. swap (lenA, lenB);
int tmpLen = lenA;
lenA = lenB;
lenB = tmpLen;
//2. swap (curA, curB);
curA = headB;
curB = headA;
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap-- > 0) {
curA = curA.next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != null) {
if (curA == curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
环形链表 - 提交记录 - 力扣(LeetCode) (leetcode-cn.com)
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null)return false;
ListNode slow = head;
ListNode fast = head.next;
while(slow!= fast){
if(fast == null || fast.next == null) return false;
slow = slow.next;
fast = fast.next.next;
}
return true;
}
}
142. 环形链表 II - 力扣(LeetCode) (leetcode-cn.com)
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
ListNode index1 = fast;
ListNode index2 = head;
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}