第四章:如何k个一组反转链表

labuladong如何k个一组反转链表

25. K 个一组翻转链表

利用栈先进后出,反转k个一组的链表

  • stack中存放的是ListNode
    • 虽然存放在stack中,但ListNode之间的指向关系仍然保留

以 1->2->3->4->5 为例,

  • 先在最左边加一个dummy头(-1)便于操作。
  • 注意:大循环 while cur里面的while n>0 and cur 一定要有,确保不够k个Node时n>0,及时跳出(否则cur=cur.next也没有意义了)。
  • 第一次while时,stack中存放 [3,2,1],pre产生的结果是: -1->3->2->1 。此时cur 指向4,pre指向3。pre.next=cur后现在的结果是-1->3->2->1->4->5
  • 第二次while时,stack中存放[5,4],但是由于n!=0,直接break出循环(即pre.next=cur不执行)。此时cur已经指向5后面的None,但是现在已经跳出while循环了,不必理会cur
    • else break这里用else continue也可以,反正此时cur==nullprt,也要跳出while循环
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def reverseKGroup(self,head, k):
        dummy=ListNode(-1)
        dummy.next=head
        pre=dummy
        cur=head
        stack=[]
        while cur:
        # while True:
            n=k
            while n>0 and cur:
                stack.append(cur)
                cur=cur.next
                n-=1
            if n==0:
                while stack:
                    pre.next=stack.pop()
                    pre=pre.next
            else:
                break
            pre.next=cur
        return dummy.next
  • 其他写法
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def reverseKGroup(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        # 在最左边加一个dummy头(-1)便于操作
        dummy = ListNode(-1)
        dummy.next=head
        pre = dummy
        cur = head
        stack = []

        count = 0
        while cur:
            # 把k个节点加到stack中
            while cur and count < k:
                stack.append(cur)
                cur = cur.next
                count += 1

            # 当stack中存了k个节点时,pop出这些节点,并逐个加到pre后面
            if count == k:
                while stack:
                    pre.next = stack.pop()
                    pre = pre.next
                    count -= 1
            else:
                break # 如果不够k个,则跳出while cur循环
            # 不用担心跳出以后后面的节点
            # pre已经在这次的if语句执行前通过pre.next=cur 把后面的节点连在一起了

            pre.next = cur

        return dummy.next
  • 注意C++中栈的操作,在top后要pop
    • s.pop() 删除栈顶元素但不返回其值
    • s.top() 返回栈顶的元素,但不删除该元素
    • s.push() 在栈顶压入新元素
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode *reverseKGroup(ListNode *head, int k) {
        ListNode *dummy = new ListNode(-1);
        dummy->next = head;
        ListNode *pre=dummy;
        ListNode *cur=head;
        stack < ListNode * > stk;
        while (cur!=nullptr){
//            不管够不够k个,都尽量入栈
            for (int i = 0; i < k && (cur!=nullptr); ++i) {
                stk.push(cur);
                cur=cur->next;
            }
//            如果栈中有k个元素,则把这一组进行出栈并拼接
            if (stk.size()==k){
                while(!stk.empty()){
                    pre->next=stk.top();
                    stk.pop();
                    pre=pre->next;
                }
            }else break; // 这里用continue也可以,反正此时cur==nullprt,也要跳出while循环
            pre->next = cur; // 每组操作后,把cur接到pre后面
        }
        return dummy->next;
    }
};

其他写法:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode *reverseKGroup(ListNode *head, int k) {
        ListNode *dummy = new ListNode(-1);
        dummy->next = head;
        ListNode *pre = dummy;
        ListNode *cur = head;
        stack<ListNode *> s;

        int count = 0;
        while (cur != nullptr) {
            while (cur != nullptr && count < k) {
                s.push(cur);
                cur = cur->next;
                count += 1;
            }

            if (count == k) {
                while (!s.empty()) {
                    pre->next = s.top();
                    s.pop();
                    pre = pre->next;
                    count -= 1;
                }
            } else
                break;

            pre->next = cur;
        }

        return dummy->next;
    }
};
  • 补充:如果题目变成:后面不够的也要反转,只要把else break改成: (也就是把后面的stack中的节点pop出,并拼接到pre后即可)
else:
    while stack:
        pre.next = stack.pop()
        pre = pre.next
        count -= 1

   转载规则


《第四章:如何k个一组反转链表》 M 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
第四章:如何寻找最长回文子串 第四章:如何寻找最长回文子串
labuladong 如何寻找最长回文子串 5. 最长回文子串 回文串的长度可能是奇数也可能是偶数,如果是 abba这种情况,没有一个中心字符。所以可以: 找到以 s[i] 为中心的回文串(对奇数回文串),找到以 s[i] 和 s[i+1]
2020-07-13
下一篇 
第四章:如何运用贪心思想玩跳跃游戏 第四章:如何运用贪心思想玩跳跃游戏
labuladong如何运用贪心思想玩跳跃游戏 有关动态规划的问题,大多是让你求最值的,比如最长子序列,最小编辑距离,最长公共子串等等等。 那么贪心算法作为特殊的动态规划也是一样,也一定是让你求个最值。 贪心问题往往可以通过动态规划来解决
2020-07-12
  目录