1,环形链表
题目
给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环,则返回 true 。 否则,返回false
**进阶:**你能用 O(1)(即,常量)内存解决此问题吗?
题解
环形链表判断,有两种方法, hash法, 快慢指针。
-
hash法比较简单, 遍历链表, 使用hash 存储,判断是否存在重复。 重复返回 true 否则false 这中的话 内存就是O(n)
-
快慢指针:我们定义两个指针,一快一慢。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针在位置 head,而快指针在位置 head.next。这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。
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; }
2,合并K个排序链表
题目
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
题解:
合并K个排序链表 ,基于合并两个有序链表的延伸。
合并两个有序链表。
-
首先我们需要一个变量 head来保存合并之后链表的头部,你可以把 head设置为一个虚拟的头(也就是 head 的 val属性不保存任何值)这是为了方便代码的书写,在整个链表合并完之后,返回它的下一位置即可
-
我们需要一个指针 tail 来记录下一个插入位置的前一个位置,以及两个指针 a,b 来记录l1,l2未合并部分的第一位。注意这里的描述,tail不是下一个插入的位置,a 和 b 所指向的元素处于「待合并」的状态,也就是说它们还没有合并入最终的链表。
-
当 a,b 不为空时,取 val 属性小的合并。
-
如果a为空,则把 整个b以及后面的元素全部合并
-
如果b为空,则把 整个a以及后面的元素全部合并
public ListNode merge2Lists(ListNode l1,ListNode l2){ if(l1==null){ return l2; }else if(l2 == null){ return l1; } ListNode head = new ListNode(0); ListNode tail = head,a=l1,b=l2; while (a !=null && b !=null){ if(a.val < b.val){ tail.next = a; a = a.next; }else{ tail.next = b; b=b.next; } tail = tail.next; } tail.next = a==null?b:a; return head.next;}
知道两个有序链表合并后, 顺序合并即可
public ListNode mergeKLists(ListNode[] lists) {
ListNode ans = null;
for (int i = 0; i < lists.length; ++i) {
ans = merge2Lists(ans, lists[i]);
}
return ans;
}
当然遍历 顺序合并相对于 分治合并 慢一些
下边我们看下分治合并
-
将 k 个链表配对并将同一对中的链表合并;
-
第一轮合并以后, k 个链表被合并成了 k/2个链表,平均长度为 2n/k,然后是 k/4个链表, k/8个链表等等; 重复这一过程,直到我们得到了最终的有序链表。
public ListNode mergeKLists(ListNode[] lists) { return mergeKLists(lists,0,lists.length -1); } public ListNode mergeKLists(ListNode[] lists, int l, int r) { if (l == r) { return lists[l]; } if (l > r) { return null; } int mid = (r - l) / 2 + l; return mergeTwoList(mergeKLists(lists, l, mid), mergeKLists(lists, mid + 1, r)); }