1.求链表长度
public int getLength(ListNode head){
int length = 0;
ListNode tmpNode = head;
while(tmpNode!=null){
length++;
tmpNode = tmpNode.next;
}
return length;
}
2.链表翻转(遍历法 递归法)
public ListNode reverseLinkedList(ListNode head){
ListNode preNode = null;
ListNode curNode = head;
ListNode nextNode = null;
while(curNode !=null){
nextNode = curNode.next;
curNode.next = preNode;
preNode = curNode;
curNode = nextNode;
}
return preNode;
}
public ListNode reverseLinkedList(ListNode head){
if(head.next == null) return head;
ListNode last = reverseList(head.next);
head.next.next = head;
head.next = null;
return last;
}
3.求倒数第K个节点
public ListNode getKthFromEnd(ListNode head, int k) {
if(head == null) return head;
ListNode first = head;
ListNode second = head;
ListNode cur = head;
for (int i = 0; i < k ; i++) {
first = first.next;
}
while(first != null){
first = first.next;
second = second.next;
}
return second;
}
4.求链表中间结点
public ListNode middleNode(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast.next !=null && fast.next.next !=null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
5.链表划分
public class Solution {
public ListNode partition(ListNode head, int x) {
if(head == null) return null;
ListNode leftDummy = new ListNode(0);
ListNode rightDummy = new ListNode(0);
ListNode left = leftDummy, right = rightDummy;
while (head != null) {
if (head.val < x) {
left.next = head;
left = head;
} else {
right.next = head;
right = head;
}
head = head.next;
}
right.next = null;
left.next = rightDummy.next;
return leftDummy.next;
}
}
6.快排实现单链表排序
class Solution {
public ListNode sortList(ListNode head) {
return quickSort(head, null);
}
public ListNode quickSort(ListNode head, ListNode end){
if(head == end || head.next == end ) return head;
ListNode left = head, right = head, p = head.next;
while(p != end){
ListNode next = p.next;
if(p.val < head.val){
p.next = left;
left = p;
}else{
right.next = p;
right = p;
}
p = next;
}
right.next = end;
ListNode node = quickSort(left,head);
head.next = quickSort(head.next,end);
return node;
}
}
7.归并实现单链表排序
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode midNode = middleNode(head);
ListNode rightHead = midNode.next;
midNode.next = null;
ListNode left = sortList(head);
ListNode right = sortList(rightHead);
return mergeTwoLists(left, right);
}
private ListNode middleNode(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode slow = head;
ListNode fast = head.next.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode sentry = new ListNode(-1);
ListNode curr = sentry;
while(l1 != null && l2 != null) {
if(l1.val < l2.val) {
curr.next = l1;
l1 = l1.next;
} else {
curr.next = l2;
l2 = l2.next;
}
curr = curr.next;
}
curr.next = l1 != null ? l1 : l2;
return sentry.next;
}
8.合并两个有序单链表
public ListNode mergeLinkedList(ListNode l1,ListNode l2){
ListNode node = new ListNode();
ListNode tempNode = node;
while(l1 !=null && l2 !=null){
if(l1.val <= l2.val){
tempNode.next=l1;
l1 = l1.next;
}else{
tempNode.next =l2;
l2 = l2.next;
}
tempNode = tempNode.next;
}
tempNode.next = l1 == null ? l2 : l1;
return node.next;
}
9.复杂链表复制
public Node copyRandomList(Node head) {
if(head == null) return null;
Node cur = head;
Map<Node, Node> map = new HashMap<>();
while(cur != null) {
map.put(cur, new Node(cur.val));
cur = cur.next;
}
cur = head;
while(cur != null) {
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
return map.get(head);
}
10.判断链表是否有环
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null) return false;
ListNode fast= head ,slow = head;
while(true){
if(fast == null || fast.next == null) return false;
fast = fast.next.next;
slow = slow.next;
if(fast == slow) return true;
}
}
11.求环形链表入环的第一个节点
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;
while (true) {
if (fast == null || fast.next == null) return null;
fast = fast.next.next;
slow = slow.next;
if (fast == slow) break;
}
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
12.判断两个无环单链表是否相交
- 方法一 最直接的方法是判断 A 链表的每个节点是否在 B 链表中,但是这种方法的时间复杂度为 O(Length(A) * Length(B))。
- 方法二 转化为环的问题。把 B 链表接在 A 链表后面,如果得到的链表有环,则说明两个链表相交。可以之前讨论过的快慢指针来判断是否有环,但是这里还有更简单的方法。如果 B 链表和 A 链表相交,把 B 链表接在 A 链表后面时,B 链表的所有节点都在环内,所以此时只需要遍历 B 链表,看是否会回到起点就可以判断是否相交。这个方法需要先遍历一次 A 链表,找到尾节点,然后还要遍历一次 B 链表,判断是否形成环,时间复杂度为 O(Length(A) + Length(B))。
- 方法三 除了转化为环的问题,还可以利用“如果两个链表相交于某一节点,那么之后的节点都是共有的”这个特点,如果两个链表相交,那么最后一个节点一定是共有的。所以可以得出另外一种解法,先遍历 A 链表,记住尾节点,然后遍历 B 链表,比较两个链表的尾节点,如果相同则相交,不同则不相交。时间复杂度为 O(Length(A) + Length(B)),空间复杂度为 O(1),思路比解法 2 更简单。
public boolean isIntersect(ListNode headA, ListNode headB) {
if (null == headA || null == headB) {
return false;
}
if (headA == headB) {
return true;
}
while (null != headA.next) {
headA = headA.next;
}
while (null != headB.next) {
headB = headB.next;
}
return headA == headB;
}
13.求两个无环单链表的第一个相交点
- 方法一 如果两个链表存在公共结点,那么它们从公共结点开始一直到链表的结尾都是一样的,因此我们只需要从链表的结尾开始,往前搜索,找到最后一个相同的结点即可。但是题目给出的单向链表,我们只能从前向后搜索,这时,我们就可以借助栈来完成。先把两个链表依次装到两个栈中,然后比较两个栈的栈顶结点是否相同,如果相同则出栈,如果不同,那最后相同的结点就是我们要的返回值。
- 方法二 先找出2个链表的长度,然后让长的先走两个链表的长度差,然后再一起走,直到找到第一个公共结点。
- 方法三 由于2个链表都没有环,我们可以把第二个链表接在第一个链表后面,这样就把问题转化为求环的入口节点问题。
- 方法四 两个指针p1和p2分别指向链表A和链表B,它们同时向前走,当走到尾节点时,转向另一个链表,比如p1走到链表 A 的尾节点时,下一步就走到链表B,p2走到链表 B 的尾节点时,下一步就走到链表 A,当p1==p2 时,就是链表的相交点
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (null == headA || null == headB) {
return null;
}
if (headA == headB) {
return headA;
}
ListNode p1 = headA;
ListNode p2 = headB;
while (p1 != p2) {
p1 = (null == p1) ? headB : p1.next;
p2 = (null == p2) ? headA : p2.next;
}
return p1;
}