编程导航算法通关村第二关 | K个一组反转

164 阅读2分钟

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

头插法

将其分成已经反转、正在反转和未反转三个部分。为了方便循环,我们可以先遍历一遍数组,统计一下元素数量len,确定要分几组n=len/k,然后将其反转

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode cur = head;
        int len = 0;
        while(cur != null) {
            len++;
            cur = cur.next;
        }
        int n = len/k;
        ListNode pre = dummy;
        cur = head;
        for(int i=0;i<n;i++) {
            for(int j=0;j<k-1;j++) {
                ListNode next = cur.next;
                cur.next = cur.next.next;
                next.next = pre.next;
                pre.next = next;
            }
            pre = cur;
            cur = cur.next;
        }
        return dummy.next;
    }
}

穿针引线法

首先,因为要分组反转,我们就一组一组的处理,将其分成已经反转、正在反转和未反转三个部分,同时为了好处理头结点,我们新建一个虚拟头结点。

之后我们直接遍历,根据是否为K个找到四个关键位置,并用变量pre、start、end和next标记,如下:

接着我们就可以对上图中颜色部分进行反转了 完成之后,我们要将裁下来的部分再缝到原始链表上,这就需要调整指针指向了,同样注意指针的指向: 最后调整一下几个变量的位置,为下一次做准备:

public ListNode reverseKGroup(ListNode head, int k) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;

    ListNode pre = dummy;
    ListNode end = dummy;

    while (end.next != null) {
        //找到要处理的区间的末尾
        for (int i = 0; i < k && end != null; i++){
            end = end.next;
        } 
        if (end == null){
            break;
        } 
        //将要处理的区间裁剪下来
        ListNode start = pre.next;
        ListNode next = end.next;
        end.next = null;
        //执行反转
        pre.next = reverse(start);
        // 上面pre.next和下面start.next两个指针是为了将反转的区间缝补回去
        start.next = next;
        //调整指针,为下一组做准备
        pre = start;
        end = pre;
    }
    return dummy.next;
}


private ListNode reverse(ListNode head) {
    ListNode pre = null;
    ListNode curr = head;
    while (curr != null) {
        ListNode next = curr.next;
        curr.next = pre;
        pre = curr;
        curr = next;
    }
    return pre;
}