4. 链表


链表题目是有套路的,如下4个方法:
  • 链表逆序 (n个节点进行逆序,实际上循环进行n-1次)
  • 2个指针 (拆分、拼接、合并、求中点)
  • 链表成环
  • 使用额外空间保存

143. Reorder List
Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…

You must do this in-place without altering the nodes' values.

For example,
Given {1,2,3,4}, reorder it to {1,4,2,3}.
该题目几乎使用到了所有的套路
1. 使用2个指针,求出链表中点
2. 将后半段链表逆序
3. 使用3个指针,将2两个链表拼接起来
void reorderList(ListNode* head) {
    ListNode preHead1 = ListNode(INT_MIN);
    preHead1.next = head;
    
    ListNode *preMid = &preHead1, *mid = head;
    while (head && head->next) {
        preMid = mid;
        mid = mid -> next;
        head = head -> next -> next;
    }
    preMid -> next = NULL;
    
    ListNode preHead2 = ListNode(INT_MIN);
    preHead2.next = mid;
    ListNode *pre = &preHead2, *cur = pre->next, *nex = NULL;
    while (cur && (nex = cur->next)) {
        cur->next = nex->next;
        nex->next = pre->next;
        pre->next = nex;
    }
    
    ListNode *left = preHead1.next, *right = preHead2.next, *pt = &preHead1;
    while (left && right) {
        pt->next = left;
        left = left->next;
        pt = pt->next;
        
        pt->next = right;
        right = right->next;
        pt = pt->next;
    }
    head = preHead1.next;
}

92. Reverse Linked List II
Reverse a linked list from position m to n. Do it in-place and in one-pass.

For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,

return 1->4->3->2->5->NULL.

Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.
对链表中一段区域进行逆序。思路很清楚:找出该段的的前一个节点,对该段长度的节点进行逆序,并将pre节点和后面的连接起来。
ListNode* reverseBetween(ListNode* head, int m, int n) {
    ListNode preHead = ListNode(INT_MIN);
    preHead.next = head;
    ListNode *pre = &preHead;
    for (int i = 1; i <= m - 1; ++i)
        pre = pre -> next;
    
    ListNode *cur = pre->next, *nex = cur->next;
    for (int i = 0; i < n - m; ++i) {
        cur->next = nex->next;
        nex->next = pre->next;
        pre->next = nex;
        nex = cur->next;
    }
    
    return preHead.next;
}

25. Reverse Nodes in k-Group
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.

You may not alter the values in the nodes, only nodes itself may be changed.

Only constant memory is allowed.

For example,
Given this linked list: 1->2->3->4->5

For k = 2, you should return: 2->1->4->3->5

For k = 3, you should return: 3->2->1->4->5
每k个节点为一组,内部逆序
求出链表长度,当链表长度 >= k时才进行循环,每k个节点进行逆序并和之前拼接
left记录上组最后一个,pt记录本组第一个,right记录本组的遍历
ListNode* reverseKGroup(ListNode* head, int k) {
    if(head==NULL||k==1) return head;
    ListNode preHead = ListNode(INT_MIN);
    preHead.next = head;
    
    int count=0;
    ListNode *pre = &preHead, *cur = &preHead, *nex = NULL;
    while(cur = cur->next) 
        count++;
    while(count>=k) {
        cur = pre->next;
        nex = cur->next;
        for(int i=1;i<k;++i) {
            cur->next=nex->next;
            nex->next=pre->next;
            pre->next=nex;
            nex=cur->next;
        }
        pre = cur;
        count -= k;
    }
    return preHead.next;
}

141. Linked List Cycle
Given a linked list, determine if it has a cycle in it.

Follow up:
Can you solve it without using extra space?
经典的求链表是否有环的问题,使用快慢指针解决,如果会相遇则有环。
bool hasCycle(ListNode *head) {
    if (!head) return false;
    ListNode *slow = head, *fast = head;
    while (slow && fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) return true;
    }
    return false;
}

142. Linked List Cycle II
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Note: Do not modify the linked list.

Follow up:
Can you solve it without using extra space?
如果不考虑空间复杂度,可以使用set保存已经访问过的节点。
空间复杂度为O(1)的方法是,快慢指针相遇的地方离入口的距离和从头出发的距离是一样的。具体原因
ListNode *detectCycle(ListNode *head) {
    if (!head) return NULL;
    ListNode *slow = head, *fast = head, *entry = head;
    while (slow && fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) {
            while (entry != slow) {
                slow = slow->next;
                entry = entry->next;
            }
            return entry;
        }
    }
    return NULL;
}

19. Remove Nth Node From End of List
Given a linked list, remove the nth node from the end of list and return its head.

For example,

   Given linked list: 1->2->3->4->5, and n = 2.

   After removing the second node from the end, the linked list becomes 1->2->3->5.
Note:
Given n will always be valid.
Try to do this in one pass.
去除倒数第k个节点。使用2个指针,指针的距离为k+1。
ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode preHead = ListNode(INT_MIN);
    preHead.next = head;
    
    ListNode *left = &preHead, *right = head;
    int count = 0;
    while (right) {
        if (count >= n) left = left->next;
        right = right->next;
        ++count;
    }
    
    if (left->next) left->next = left->next->next;
    return preHead.next;
}

83. Remove Duplicates from Sorted List
Given a sorted linked list, delete all duplicates such that each element appear only once.

For example,
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.
有序链表去重。使用2个指针,当right的指针指向的值大于left指针指向的值,则left指针的下一个指向该right指针指向的节点,并移动left指针。
ListNode* deleteDuplicates(ListNode* head) {
    if (!head) return head;
    ListNode preHead = ListNode(INT_MIN);
    preHead.next = head;
    ListNode *left = head, *right = head;
    while (right) {
        if (right->val > left->val) {
            left->next = right;
            left = left->next;
        }
        right = right->next;
    }
    left->next = NULL;
    return preHead.next;
}

82. Remove Duplicates from Sorted List II
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.
1. left负责加入不重复节点,right负责遍历数组
2. right每次遇到新元素便遍历到该值的最后一个节点
ListNode* deleteDuplicates(ListNode* head) {
    if (!head) return head;
    ListNode preHead = ListNode(INT_MIN);
    preHead.next = head;
    ListNode *left = &preHead, *right = head;
    
    while (right) {
        bool duplicated = false;
        while (right && right->next && right->val == right->next->val) {
            right = right->next;
            duplicated = true;
        }
        if (!duplicated) {
            left->next = right;
            left = left->next;
        }
        right = right->next;
    }
    left->next = NULL;
    return preHead.next;
}

86. Partition List
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
将链表拆分成2部分,最后连接起来
1. 新建两个dump节点leftHead、rightHead
2. left、right两个指针负责为两个新链表添加节点
3. head负责遍历原始链表
ListNode* partition(ListNode* head, int x) {
    ListNode leftHead = ListNode(INT_MIN);
    ListNode rightHead = ListNode(INT_MIN);
    ListNode *left = &leftHead, *right = &rightHead;
    while (head) {
        if (head->val < x) {
            left->next = head;
            left = left->next;
        } else {
            right->next = head;
            right = right->next;
        }
        head = head->next;
    }
    left->next = rightHead.next;
    right->next = NULL;
    return leftHead.next;
}

23. Merge k Sorted Lists
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
这道题目可以使用在每个链表中当前节点中选取val最小的,然后拼接起来。或者递归地两两合并,利用分治的思想。时间复杂度分别是O(kn)、O(nlogk)。然而实际使用分治的方法要快很多。
ListNode *mergeTwoLists(ListNode* l1, ListNode* l2) {
    if (NULL == l1) return l2;
    else if (NULL == l2) return l1;
    if (l1->val <= l2->val) {
        l1->next = mergeTwoLists(l1->next, l2);
        return l1;
    }
    else {
        l2->next = mergeTwoLists(l1, l2->next);
        return l2;
    }
}
ListNode *mergeKLists(vector<ListNode *> &lists) {
    if (lists.empty()) return NULL;
    int len = lists.size();
    while (len > 1) {
        for (int i = 0; i < len / 2; ++i) {
            lists[i] = mergeTwoLists(lists[i], lists[len - 1 - i]);
        }
        len = (len + 1) / 2;
    }
    
    return lists.front();
}

61. Rotate List
Given a list, rotate the list to the right by k places, where k is non-negative.

For example:
Given 1->2->3->4->5->NULL and k = 2,
return 4->5->1->2->3->NULL.
1. 遍历链表,求出链表长度,并将链表首尾相连
2. 遍历到len - (k%len)的位置,将链表断开
ListNode* rotateRight(ListNode* head, int k) {
    if (!head) return head;
    int len = 1;
    ListNode *newH = head, *tail = head;
    while (tail -> next) {
        len++;
        tail = tail -> next;
    }
    tail -> next = head;
    if (k %= len) {
        for (int i = 0; i < len - k; ++i) tail = tail->next;
    }
    
    newH = tail->next;
    tail->next = NULL;
    
    return newH;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容