20210429力扣第25题:k个一组翻转链表

1.题目

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

来源:力扣(LeetCode)
       链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group
        著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

进阶:

  • 你可以设计一个只使用常数额外空间的算法来解决此问题吗?

  • 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]
输入:head = [1], k = 1
输出:[1]

2.想法

这道题开始的时候感觉是有点困难,但是根据前一道题和同学商量的思想,有了想法,可以把这些看成一个List,List中有reverse方法。

  • 把这个链表中的所有元素存入一个List中
  • 根据划分的k,将list重新分割,装入新的list1,在分割过程中,分割后就使用reverse。
  • 这些分割的小list1再装入一个list2中
  • 新建一个节点,遍历list2 遍历list1
  • 把其中的值都放入节点的next中,一直next下去,就完成翻转了。

2.1代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        //1.使用一个list 把这些数值都存入list中
        if(k==1) return head;
        if(head==null) return null;
        ListNode pre = new ListNode();
        pre.next = head;
        
        List<List<Integer>> lists=new ArrayList<List<Integer>>();
        List<Integer> li = new ArrayList<Integer>();
        
        while(head!=null)
        {
            li.add(head.val);
            head = head.next;
        }

        
        
        //2.根据k  把 一个list 存入k个元素.
        //i和 k的关系 这一块 要写好嗄
     
        for(int i = 0;i<li.size();i++)
        {
             List<Integer> li1 = new ArrayList<>();
             if((i+1)%k==0)
             {
                 for(int j = (i+1)-k;j<i+1;j++)
                 {
                     li1.add(li.get(j));
                 }
                 Collections.reverse(li1);
                 lists.add(li1);
             }
        }

        //最后几个元素
        List<Integer> li2 = new ArrayList<>();
        for(int i = (li.size()/k)*k;i<li.size();i++)
        {
            li2.add(li.get(i));
        }
         //Collections.reverse(li2);
         lists.add(li2);


        

        ListNode n = new ListNode();
        ListNode nn = n;
        for(List<Integer> lis:lists)
        {
            for(Integer in:lis)
            {
                nn.next = new ListNode(in);
                nn=nn.next;
            }
        }
        return n.next;





    }
}

这样虽然运行出来了,但是运行的时间复杂度和空间复杂度都比较高。接下来,看一下其他人的回答。

2.2其他想法

看到想法很多,找一个看得懂的来说,就是先计算链表的长度,再将链表化成k等份,在每个k等份中循环进行两两交换。

这个代码自己没写,这是评论中的代码:

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

这个代码需要画图看得出来,我自己也有点小疑问:

就是在内层for循环中,他的curr没有向下next,怎么可以一直循环呢,我只画图使用了k=2时候的情况,但是k=3就要循环2次,我不知道这个是怎么循环的,当跳出循环的时候,之后的我没有问题。

3.总结

这道题自己写的时候使用了笨方法,知道怎么做就可以了,但是时间复杂度和空间复杂度都是相当高的了,就看了别人方法,这种类似的题都需要画图辅助才比较好,要仔细看这些链表的点指向哪里,我都没有静下心来仔细看,后还有就是我遇到那种有时链表赋值,忽然就搞不清了,有next倒还行,比如:

head= pre.next;


和


pre.next = head;

这两个我能分清一个,但是另一个就有时候转不过弯来。搜了下,找了个(有关head->next = p;和p=head->next;之间的区别

说下自己的理解:

head.next = pre :就是pre是head的后驱 head是pre的前驱,图的第二种情况

head=pre.next:head的后驱和pre的后驱指向同一个点。

可以这么说,还得多看这样的题才好,还有知识点Collections.reverse(),这个coeelctions是有s的。

-----------------------------------

20210722更新

看知乎上说这是道面试题,就重新翻看了下,果然又有些忘了,哎,所以重新看了下题解。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    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);

          start.next = next;
          pre =start;
          end = pre;

      }
          return dummy.next;


    }

    public 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;

    }
}

先得明白逻辑才行 ,一个pre,start,end,其中需要一个reverse方法,这些需要自己画图去看懂这个意思。先弄明白意思,再去编程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值