链表相关的题目 这里用来记录链表相关的题目以及思路
相交链表 输入两个链表,找出它们的第一个公共结点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Solution { public ListNode getIntersectionNode (ListNode headA, ListNode headB) { if (headA == null || headB == null ) return null ; ListNode pA = headA, pB = headB; while (pA != pB) { pA = pA == null ? headB : pA.next; pB = pB == null ? headA : pB.next; } return pA; } }
K个一组翻转链表 思路:每k个翻转一次,可以单独进行反转,但注意上一组的尾节点和下一组的头节点要连接起来,所以需要记录上一组尾节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public static ListNode reverseKGroup (ListNode head, int k) { ListNode start = head; ListNode end = teamEnd(start, k); if (end == null ) { return head; } head = end; reverse(start, end); ListNode lastTeamEnd = start; while (lastTeamEnd.next != null ) { start = lastTeamEnd.next; end = teamEnd(start, k); if (end == null ) { return head; } reverse(start, end); lastTeamEnd.next = end; lastTeamEnd = start; } return head; } public static ListNode teamEnd (ListNode s, int k) { while (--k != 0 && s != null ) { s = s.next; } return s; } public static void reverse (ListNode s, ListNode e) { e = e.next; ListNode pre = null , cur = s, next = null ; while (cur != e) { next = cur.next; cur.next = pre; pre = cur; cur = next; } s.next = e; }
随机链表的复制 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
思路:将每个节点复制一份,并把复制的节点放在原节点后面,比如1->2->3->4->5,复制之后变成1->1’->2->2’->3->3’->4->4’->5->5’,然后遍历链表,将复制的节点的random指针指向原节点的random指针指向的节点的下一个节点。最后将链表拆分,返回新链表的头节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public Node copyRandomList (Node head) { Node pre = head; Node next = null ; if (head == null ){ return null ; } while (pre != null ){ next = pre.next; pre.next = new Node (pre.val); pre.next.next = next; pre = next; } pre = head; while (pre!=null ){ next = pre.next.next; pre.next.random = pre.random == null ? null : pre.random.next; pre = next; } Node newHead = head.next; Node newPre = newHead; pre =head; while (pre != null ){ next = pre.next.next; newPre.next = next == null ? null : next.next ; pre.next = next; pre =next; newPre = newPre.next; } return newHead; }
判断回文链表 思路:利用快慢指针,找到中点,然后翻转后半部分链表,比较前后两个链表是否相等。最后恢复链表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public boolean isPalindrome (ListNode head) { if (head == null ) return false ; if (head.next==null ) return true ; ListNode man = head; ListNode kuai = head; while (kuai.next != null && kuai.next.next != null ) { man = man.next; kuai = kuai.next.next; } ListNode reverseHead = reverseList(man); Boolean isPal = true ; ListNode reversePre = reverseHead; ListNode pre = head; while (reversePre!=null && pre!=null ){ if (pre.val!=reversePre.val){ isPal = false ; break ; } reversePre = reversePre.next; pre = pre.next; } reverseList(reverseHead); return isPal; } public ListNode reverseList (ListNode head) { ListNode pre = null ,next=null ; while (head!=null ){ next =head.next; head.next = pre; pre =head; head = next; } return pre; }
链表是否存在环 并求环的入口节点 思路:利用快慢指针,快指针每次移动两步,慢指针每次移动一步,如果快慢指针相遇,则说明链表有环,否则没有环。相遇的时候,快指针回到头节点,慢指针继续移动,但是慢指针和快指针每次都移动一步,再次相遇的时候就是环的入口节点。 a+(nb+c) = 2(a+c) a = nb - c 所以慢指针再走a步,就能到达入口节点。此时快指针也走a步,慢指针和快指针相遇的节点就是入口节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static 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){ fast = head; while (fast!=slow){ fast = fast.next; slow = slow.next; } return slow; } } return null ; }
排序链表 要求:时间复杂度nlog(n),空间复杂度O(1),且稳定 思路:利用非递归版本的归并排序,并且merge是合并两个有序链表。 代码很复杂,看看就好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 public static ListNode sortList (ListNode head) { int n = 0 ; ListNode cur = head; while (cur != null ) { n++; cur = cur.next; } ListNode l1, r1, l2, r2, next, lastTeamEnd; for (int step = 1 ; step < n; step <<= 1 ) { l1 = head; r1 = findEnd(l1, step); l2 = r1.next; r2 = findEnd(l2, step); next = r2.next; r1.next = null ; r2.next = null ; merge(l1, r1, l2, r2); head = start; lastTeamEnd = end; while (next != null ) { l1 = next; r1 = findEnd(l1, step); l2 = r1.next; if (l2 == null ) { lastTeamEnd.next = l1; break ; } r2 = findEnd(l2, step); next = r2.next; r1.next = null ; r2.next = null ; merge(l1, r1, l2, r2); lastTeamEnd.next = start; lastTeamEnd = end; } } return head; } public static ListNode findEnd (ListNode s, int k) { while (s.next != null && --k != 0 ) { s = s.next; } return s; } public static ListNode start;public static ListNode end;public static void merge (ListNode l1, ListNode r1, ListNode l2, ListNode r2) { ListNode pre; if (l1.val <= l2.val) { start = l1; pre = l1; l1 = l1.next; } else { start = l2; pre = l2; l2 = l2.next; } while (l1 != null && l2 != null ) { if (l1.val <= l2.val) { pre.next = l1; pre = l1; l1 = l1.next; } else { pre.next = l2; pre = l2; l2 = l2.next; } } if (l1 != null ) { pre.next = l1; end = r1; } else { pre.next = l2; end = r2; } }