Reorder List
Given a linked list and a value x, write a function to reorder this list such that all nodes less than x come before the nodes greater than or equal to x.
可以使用dummy node来减少判断header是否为空的边界条件。
代码:class2/reorder_list.c
ListNode *reorderList(ListNode *head, int x) {
ListNode *newHead = NULL;
ListNode *aDummy = new ListNode(0);
ListNode *aCurr = aDummy;
ListNode *bDummy = new ListNode(0);
ListNode *bCurr = bDummy;
while(head) {
ListNode *next = head->next;
head->next = NULL;
if( head->val < x ) {
aCurr->next = head;
aCurr = head;
} else {
bCurr->next = head;
bCurr = head;
}
head = next;
}
aCurr->next = bDummy->next;
newHead = aDummy->next;
delete aDummy;
delete bDummy;
return newHead;
}
链表的基本技巧
- 链表的插入
- 链表的删除
- 链表逆序(微软特别喜欢考)
- 合并链表
- 找到链表的中间项
Sort List
Sort a linked list in O(n log n) time using contant space complexity.
Hint: merge sort
问题: log n的算法复杂度是怎么得到的。
//里面有两个指针,一个快一个慢,当快的指针到达终点的时候,慢的指针刚好到达终点
public class Solution {
private ListNode findMiddle(ListNode head) {
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
//将两个链表按从小到大排序生成一个新的链表
private ListNode merge(ListNode head1, ListNode head2) {
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while (head1 != null && head2 != null) {
if (head1.val < head2.val) {
tail.next = head1;
head1 = head1.next;
} else {
tail.next = head2;
head2 = head2.next;
}
tail = tail.next;
}
if (head1 != null) {
tail.next = head1;
} else {
tail.next = head2;
}
return dummy.next;
}
public ListNode sortList(ListNode head) {
//先检查head值是否为空
if (head == null || head.next == null) {
return head;
}
ListNode mid = findMiddle(head);
ListNode right = sortList(mid.next);
mid.next = null;//把链表彻底断开成两截
ListNode left = sortList(head);
return merge(left, right);
}
}
Two Pointers
Linked List Cycle I, II
Given a linked list, determine if it has a cycle in it.
如何判断一个单链表中有没有环?
可以开辟一个hashmap,记录每一个访问过的node.但是需要开辟整个linked list的空间。
Follow up: Can you solve it without using extra space
可以先设定一个快指针,每次走两步,慢指针走一步,如果链表中有环,快指针肯定能够和慢指针相遇。
Return the node where the cycle begins, if there is no cycle, return null.找到环的第一个节点
慢者: a+b
快者: a+b+n(c+b)
关系: a+b+c+b = 2(a+b) => a=c
一般而言,如果环特别小,我们就能得到:a=nc+(n-1)b = c + (n-1)(b+c) 这样的结论,可以令c’=c+(n-1)(b+c),则a=c’,算法并没有发生什么改变。
public static ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
}
while (true) {
if (fast == null || fast.next == null) {
return null; //遇到了null,说明不存在环
}
slow = slow.next;
fast = fast.next.next;
if (fast == slow) {
break;//第一次相遇在Z点
}
slow = head; //slow从头开始走
while (slow != fast) { //两者相遇在Y点,则推出
slow = slow.next;
fast = fast.next;
}
return slow;
}
Remove/Find Nth Node From End of List
先让一个指针先跑n步,再让两个指针同时跑 下面的代码是说如何拿到倒数第k个元素
ListNode *findkthtoLast(ListNode *head,int k){
ListNode *runner = head;
ListNode *chaser = head;
if (head == NULL || k < 0)
return NULL;
for(int i = 0; i < k; i++)
runner = runner->next;
if( runner == NULL )
return NULL;
while( runner->next != NULL ) {
chaser = chaser->next;
runner = runner->next;
}
return chaser;
}
Find the Middle of Linked List
代码如下:
ListNode *midpoint( ListNode *head) {
ListNode *chaser = head, *runner = head;
if (head == NULL)
return NULL;
while (runner->next && runner->next->next ) {
chaser = chaser->next;
runner = runner->next->next;
}
return chaser;
}
判断两个单链表是否有交点
如果一个有环一个没有环,则肯定不相交 如果两个都没有环,判断两个列表的尾部是否相等 如果两个都有环,判断一个链表上的Z点是否在另一个链表上
如何找到第一个相交的节点
求出两个链表的长度L1,L2(如果有环,则将Y点当做尾节点来算) 假设L1<L2, 用两个指针分别从两个链表的头部开始走,长度为L2的链表先走(L2-L1),然后两个一起走,直到两者相遇。
Reverse Linked List反转链表
ListNode *reverseLinkedList( ListNode *head ) {
ListNode *prev = NULL;
ListNode *next = head->next;
while(head) {
head->next = prev;
prev = head;
head = next;
next = next->next;
}
return prev;
}
Merge K Sorted Lists
Leetcode题目链接
从2个扩展到k个,对k个东西进行排序要想到堆的概念。
public class Solution {
private Comparator<ListNode> ListNodeComparator = new Comparator<ListNode>() {
public int compare(ListNode left, ListNode right) {
if (left == null) {
return 1;
} else if (right == null) {
return -1;
}
return left.val - right.val;
}
};
public ListNode mergeKLists(ArrayList<ListNode> lists) {
if (lists == null || lists.size() == 0) {
return null;
}
Queue<ListNode> heap = new PriorityQueue<ListNode>(lists.size(), ListNodeComparator);
for (int i = 0; i < lists.size(); i++) {
if (lists.get(i) != null) {
heap.add(lists.get(i));
}
}
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while (!heap.isEmpty()) {
ListNode head = heap.poll();
tail.next = head;
tail = head;
if (head.next != null) {
heap.add(head.next);
}
}
return dummy.next;
}
}
Copy List with Random Pointer
Leetcode题目链接
是linked list里面比较难的题目
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
可以用hashmap来做也可以不用。
首先是是hashmap版本的算法。
public class Solution {
public RandomListNode copyRandomList(RandomListNode head) {
if (head == null) {
return null;
}
HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
RandomListNode dummy = new RandomListNode(0);
RandomListNode pre = dummy, newNode;
while (head != null) {
if (map.containsKey(head)) {
newNode = map.get(head);
} else {
newNode = new RandomListNode(head.label);
map.put(head, newNode);
}
pre.next = newNode;
if (head.random != null) {
if (map.containsKey(head.random)) {
newNode.random = map.get(head.random);
} else {
newNode.random = new RandomListNode(head.random.label);
map.put(head.random, newNode.random);
}
}
pre = newNode;
head = head.next;
}
return dummy.next;
}
}
不使用hashmap的算法。 original指针的结构如下:
- next指针:1->2->3->4->5
- random指针:1->3->5->2->1
算法步骤:
- 复制original list的next指针到copy list,并把original list的next指针指向对应的copy list的节点下。
- 将original_node[i].random.next赋给original_node[i].next.random,完成copy list的random指针的赋值
- 将两个链表的关系断开。
//No HashMap version
public class Solution {
private void copyNext(RandomListNode head) {
while (head != null) {
RandomListNode newNode = new RandomListNode(head.label);
newNode.random = head.random;
newNode.next = head.next;
head.next = newNode;
head = head.next.next;
}
}
private void copyRandom(RandomListNode head) {
while (head != null) {
if (head.next.random != null) {
head.next.random = head.random.next;
}
head = head.next.next;
}
}
private RandomListNode splitList(RandomListNode head) {
RandomListNode newHead = head.next;
while (head != null) {
RandomListNode temp = head.next;
head.next = temp.next;
head = head.next;
if (temp.next != null) {
temp.next = temp.next.next;
}
}
return newHead;
}
public RandomListNode copyRandomList(RandomListNode head) {
if (head == null) {
return null;
}
copyNext(head);
copyRandom(head);
return splitList(head);
}
}