今日第二个题,互相监督互相学习哦~,上题:
题目描述
输入一个链表,反转链表后,输出新链表的表头。
分析:链表这个东西我感觉真的是一个字——绕,绕的你脑壳疼,左绕右绕就别想出来了~~~
题目所给的是单链表,想了一下反转后的样子:最后一个结点指向倒数第二个,倒数第二个指向倒数第三个,......,第二个指向第一个,第一个指向null; 知道了反转后各个结点指向哪之后,就需要开始调整每个结点的next指针。
这就需要把结点挨个从链表上摘下来,做调整; 这个调整过程需要两个指针辅助:pre记录其前一个结点位置,好让该结点的next指针指向前一个结点,但是在指向前一个结点前需要用一个指针p记录后一个结点地址,避免结点丢失。
举个栗子:
以head结点为例步骤如下:
1.反转后head是指向null,所以未反转的时候其前一个结点应该是null,初始化pre指针为null;
2.用p指针记录head的下一个结点head.next;
3.从链表上摘下head,即让head.next指向pre;
4.此时已完成head结点的摘取及与前一个节点的连接,则我们需要操作下一个结点:故需移动pre和 head,让pre指向head,head指向下一个节点。
重复这四个操作直到head走完原链表,指向null时,循环结束,返回pre。
最后有附图和说明。
代码:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head==null)return null;
ListNode pre=null;
ListNode p;
while(head!=null){
p=head.next;
head.next=pre;
pre=head;
head=p;
}
return pre;
}
}
牛客运行通过
运行时间:16ms
运行内存:9664Kb
这是通过迭代的方法实现的,一般迭代其实可以转化为递归,所以接下来用递归的方法实现,其实都一样。
方法二:
代码:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head==null||head.next==null)return head;
ListNode pre=ReverseList(head.next);
head.next.next=head;
head.next=null;
return pre;
}
}
牛客运行通过
运行时间:17ms
运行内存:9548Kb
这两种方法最好都要掌握,因为不知道面试官会问你哪个?哪个晓得~~~
再来一题,直接放在一起吧。
k个一组反转链表,不足k不反转。
题目描述
将给出的链表中的节点每k个一组翻转,返回翻转后的链表
如果链表中的节点数不是k的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。
只允许使用常数级的空间
例如:
给定的链表是1->2->3->4->5
对于 k = 2, 你应该返回 2->1->4->3->5
对于 k = 3, y你应该返回 3->2->1->4->5
这可以说是上一道题的扩展,但是又比上一题难挺多的,因为不仅需要进行反转,还需要k一组才反转,后面的还不反转,神奇吧,不知道谁想出来的。
分析:
既然是要分成小组再判断,则每个小组需要设置两个指针pre头和tail尾,来限定这个小分组。
然后在利用上一题的反转实现。但是这里需要保存每一个小组的头和尾,因为还和前一个或者后一个小组有联系。
代码:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
public static ListNode reverseKGroup(ListNode head, int k) {
if(head == null || head.next == null || k < 2) return head;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy, cur = head, temp;
int len = 0;
while (head != null) {
len ++ ;
head = head.next;
}
for (int i = 0; i < len / k; i ++ ) {
for (int j = 1; j < k; j ++ ) {
temp = cur.next;
cur.next = temp.next;
temp.next = pre.next;
pre.next = temp;
}
pre = cur;
cur = cur.next;
}
return dummy.next;
}
}
牛客运行通过
运行时间:222ms
运行内存:14388Kb
因为涉及到了两层循环,先求链表的长度从而得到要反转的次数,然后再进行k个一组反转。
还有利用两个指针的,就是我在分析中所提到的;
代码:
public class Solution {
public static ListNode reverseKGroup(ListNode head, int k) {
if(head == null || head.next == null || k < 2) return head;
ListNode dummy = new ListNode(0);
dummy.next = head;
head=dummy;
ListNode p=head,q=p;
ListNode cur=null;
while(q!=null){
for(int i=0;i<k&&q!=null;i++){
q=q.next;
}
if(q==null)break;
cur=p.next;
for(int i=0;i<k-1;i++){
ListNode temp=cur.next; //记录要改变节点的下一个节点,防止断链
cur.next=temp.next; //将当前指针指向的下一个节点指向所要交换节点的下一个节点,为了每次k组结束,上一个组和下一个组还有联系。
temp.next=p.next; //将第二个节点的指针指向第一个,完成两个节点的交换。
p.next=temp; //记得将头结点的指向进行改变。
}
p=cur; //cur已经指向下一个了,所以直接就是cur赋值;
q=p;
}
return head.next;
}
}
牛客运行通过
运行时间:220ms
运行内存:14576Kb
链表的题真滴真滴是在是太难了~~~~
欢迎各位互相交流指正哦~~