题解 | #最长的括号子串#

链表中的节点每k个一组翻转

http://www.nowcoder.com/practice/b49c3dc907814e9bbfa8437c251b028e

链表中的节点每k个一组翻转
将给出的链表中的节点每k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。
要求空间复杂度 O(1)

示例
输入:{1,2,3,4,5},2
返回值:{2,1,4,3,5}

方法一 模拟法

将一条链表分块分为链表长度/k块链表,如果处不尽则说明后面会有剩下的那一块是不满长度为k的。在最初的时候需要定义两个NodeList表示result(结果)和 now(当前所到达的结果链表的位置)。之后遍历块的长度,对每一个链表块进行翻转,再翻转完后将完成的链表插入到now链表的下一个,再将now链表更新到最前即可。
图片说明

public class Solution {
    /**
     * 
     * @param head ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    public ListNode reverseKGroup (ListNode head, int k) {
        // write code here
        if(k <= 1) return head;
        if(head == null) return head;
        ListNode node = head;
        int len = length(head);
        head = node;
        int sx = len / k;    //分成sx块向下取整(默认向下) 因为处不尽的后面必然凑不满k个
        ListNode result = new ListNode(0);
        ListNode now = result;
        int cnt = 0;
        for(int i = 0; i < sx; i ++){
            ListNode tmp = null;
            for(int j = 0; j < k; j ++){    //将第i块的元素翻转
                ListNode bl = head.next;
                head.next = tmp;
                tmp = head;
                head = bl;
            } 
            now.next = tmp;
            while(now.next != null) now = now.next;    //将now更新到最前的一个点
        }
        now.next = head;
        return result.next;
    }
    public int length(ListNode now){    //获取链表长度
        int cnt = 0;
        if(now != null) cnt = 1;
        while(now.next != null){
            cnt ++; now = now.next;
        }
        return cnt;
    }
}

时间复杂度: O(n) 获取链表长度,翻转链表,和now变量的指位都需要遍历一次链表所以总时间复杂度为O(n).
空间复杂度: O(1) 只使用了若干个变量

方法二 栈

和方法一一样将链表分成每段长度为k的子链表,将每个链表存入栈中,当栈中有k个元素即可一一取出,之后按取出的顺序重组链表就是这一段中翻转的链表,要注意的是处理尾部不满长度为k的链表块时直接取栈底的元素做为最后一段即可。
图片说明

public ListNode reverseKGroup (ListNode head, int k) {
        // write code here
        if(k <= 1 || head == null) return head;
        Deque<ListNode> st = new ArrayDeque<ListNode>();    //模拟栈
        ListNode result = new ListNode(0);
        ListNode now = result;
        int cnt = 0;
        while(true){
            for(int i = 0; i < k; i ++){    //将当前链表前k个存入栈中
                st.push(head);
                head = head.next;
                cnt ++;
                if(head == null) break;
            }
            if(cnt == k){    //如果当前栈中有k个元素则一一取出存入链表
                while(!st.isEmpty()){
                    now.next = st.pop();
                    now = now.next; now.next = null;
                }
            }
            if(head == null) break;   //如果链表取完了跳出循环
            cnt = 0;
        }
        ListNode end = null;
        while(!st.isEmpty()){    //如果栈中还有剩下的就说明是最后的一块直接取栈底即可
            end = st.pop();
        }
        now.next = end;
        return result.next;
    }

时间复杂度 O(n) 遍历了整个链表并且重组链表使用了时间为2n
空间复杂度 O(k) 栈中存入最大有k个ListNode

全部评论
一开始想用模拟法,没有算长度,直接用count存k,然后count--把链表切断一截,使用外置的反转函数处理完再返回头,但这样后续链表的头指针会变得乱七八糟不好操作;按这样从头开始分块处理,反转时head位置会保留,就可以操作了
1 回复 分享
发布于 2021-11-22 16:12
如果K是3,那最后栈中可能剩下一个元素,也可能剩下两块,所以最后那个代码是不是有问题
6 回复 分享
发布于 2021-08-21 20:11
题目要求空间复杂度为O(1),你用了栈,空间复杂度不符合吧
5 回复 分享
发布于 2022-02-11 16:00
栈的思路很惊艳呀
4 回复 分享
发布于 2021-11-21 19:02
最后剩在栈里的一块 小于k的那部分 再用头插法恢复一下它原来的顺序就可以了
1 回复 分享
发布于 2021-10-22 16:42
O(k)??
点赞 回复 分享
发布于 2025-09-01 00:20 江苏
这个时间复杂度超了吧?
点赞 回复 分享
发布于 2023-09-12 15:56 上海
30和31行没看懂。请教
点赞 回复 分享
发布于 2023-08-02 07:17 陕西
orz
点赞 回复 分享
发布于 2021-11-16 23:01
很有帮助,感谢
点赞 回复 分享
发布于 2021-11-16 16:29

相关推荐

哞客37422655...:这就是真实社会,没有花里胡哨的安慰,让你感受到阶级分明,不浪费彼此时间。虽然露骨但是唉
点赞 评论 收藏
分享
评论
64
10
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务