目录
一、二进制链表转整数
1.1 迭代
创建一个节点cur去遍历链表,实现每个节点的值二进制转整数
1.2 代码展示
/**
* 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 int getDecimalValue(ListNode head) {
ListNode cur = head;
int ret = 0;
while (cur != null) {
ret = cur.val + ret * 2;
cur = cur.next;
}
return ret;
}
}
二、从尾到头打印链表
2.1 辅助栈法
解题思路:
链表特点:只能从前至后访问每个节点
算法流程:
- 入栈:遍历,将各节点入栈,使用addLast()
- 出栈:将各节点值出栈,存储于数组并返回
2.2 代码展示
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int[] reversePrint(ListNode head) {
ListNode cur = head;
LinkedList<Integer> mid = new LinkedList<>();
while (cur != null) {
mid.addLast(cur.val);
cur = cur.next;
}
int[] ret = new int[mid.size()];
for (int i = 0; i < ret.length; i++) {
ret[i] = mid.removeLast();
}
return ret;
}
}
三、两两交换链表中的节点
3.1 迭代
创建tmp节点,每次需要交换tmp后面的两个节点。
如果tmp的后面没有节点,或者只有一个节点,则没有更多的节点需要交换,因此结束交换。否则,获得tmp后面的两个节点node1和node2,通过更新节点的指针关系实现两两交换节点。
tmp.next = node2;
node1.next = node2.next;
node2.next = node1;
完成上述操作之后两两节点交换之后,令tmp=node1,对链表中的其余节点进行两两交换。最后返回新的链表的头节点即可。
3.2 代码展示
/**
* 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) {
if (head == null) return null;
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode tmp = dummyHead;
while (tmp.next != null && tmp.next.next != null) {
ListNode node1 = tmp.next;
ListNode node2 = tmp.next.next;
tmp.next = node2;
node1.next = node2.next;
node2.next = node1;
tmp = node1;
}
return dummyHead.next;
}
}
四、相交链表
4.1 双指针
只有当链表headA和headB都不为空时,链表才可能相交。
首先判断链表headA和headB是否为空,如果其中至少有一个链表为空,则两个链表一定不相交,返回null。
创建两个指针pl和ps,分别指向两个链表的头节点,然后将两个指针依次遍历两个链表的每个节点。
pl指的是长的链表的节点,ps表示短的链表的节点,所有我们需要设计一个方法来实现将pl永远指向长链表,ps指向短链表。
同时我们可以得到长链表和短链表的差值步,我们让ps走差值步,然后同时走,直到相遇。
4.2 代码展示
/**
* 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) {
if (headA == null || headB == null) {
return null;
}
ListNode pl = headA;
ListNode ps = headB;
int lenA = 0;
int lenB = 0;
while (pl != null) {
lenA++;
pl = pl.next;
}
pl = headA;
while (ps != null) {
lenB++;
ps = ps.next;
}
ps = headB;
int len = lenA - lenB;//差值步
if (len < 0) {
pl = headB;
ps = headA;
len = lenB - lenA;
}
//1. pl 永远指向了最长的链表 ps 永远指向了最短的链表
//2. 求到了差值len步
//3. 走差值步
//同时走,直到相遇
while (len != 0) {
pl = pl.next;
len--;
}
while (pl != ps) {
pl = pl.next;
ps = ps.next;
}
return pl;
}
}
五、环形链表
5.1 环形链表 I
5.1.1 快慢指针
我们定义两个指针,一快一慢。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针在位置 head,而快指针在位置 head。这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。
5.1.2 代码展示
/**
* 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 ) return false;
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
return true;
}
}
return false;
}
}
5.2 环形链表 II
5.2.1 快慢指针
我们使用两个指针,一快一慢,慢指针每次只移动一步,而快指针每次移动两步。
如果链表中存在环,则fast最终会追上slow相遇。
我们设链表中环外的长度为a,slow进入环后,又走了b步与fast相遇,此时fast已经走完了环的n圈,因此它走过的总距离为a+n(b+c)+b=a+(n+1)nc.
任意时刻,fast走过的步数时slow的2倍,因此有
我们可以发现,从相遇点到入环点的距离加上n-1圈的环长,恰好等于从链表头部进入环点的距离。
因此,但发现slow与fast相遇时,相遇点就是入环点。
5.2.2 代码展示
/**
* 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) {
if (head == null) return null;
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast == null || fast.next == null) {
return null;
}
fast = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
}