跟着labuladong算法小抄进行刷题:
1、概述
这三个部分共有四道题,在力扣的题号分别是206、92、25、234。
这四道题都用到了部分链表的反转,下面是一个节点的反转思路:
(假设pre初始值是null的情况,也即从链表的表头开始反转,其他情况小作修改即可)
使用到了三个指针,分别是cur、pre、next这三个指针分别代指了当前需要反转的节点、该节点的前一节点、后一节点。
2、题目206
以题目206来说,这个题目就是遍历从链表头节点开始,每一个节点都进行反转。
3、题目92
题目92中,需要反转固定位置的链表片段,则可以借鉴快慢指针的思路,定义两个指针,差距即为right-left-1,当慢指针移动到left节点时,就开始反转节点,直到反转到right节点为止。设置快慢指针有助于反转部分的链表的前后连接。
##4、 题目25
题目25,K个一组进行反转,难点在于使用递归的思想,代码其实比较好理解,参考了labuladong的解答:
(这个题目使用迭代的思想也可以,此处不再多叙述)
//反转部分链表节点
//设定特定长度
//将不同长度连起来
public ListNode reverseKGroup(ListNode head, int k) {
//获得长度k
if(head==null) return null;
ListNode a=head;
ListNode b=head;
//判断长度是不是够
for(int i=0;i<k;i++)
{
if(b==null)
{
return head;
}
b=b.next;
}
//经过for循环获得剩余长度不小于k个
//首先得到交换后的链表的头节点,然后进行连接
ListNode newHead=reverse(a,b);
//注意 由于b进行移动的时候是从0开始的,所以相当于是移动了k下,是一个左开右闭的区间
a.next=reverseKGroup(b,k);
return newHead;
}
public ListNode reverse(ListNode a,ListNode b)
{
//将链表的头节点和尾结点传递到函数中
//进行反转
ListNode pre=null;
ListNode cur=a,next=a;
while(cur!=b)
{
next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
5、题目234
题目234,由于它前面全是链表反转的题目,所以这个题我也打算使用链表反转的思想来做。@TOC
(这个思路时间复杂度不是最优)
利用回文的定义,将前半部分进行反转,然后再和后半部分对比。
public boolean isPalindrome(ListNode head) {
//首先获得长度
ListNode p=head;
int len=0;
while(p!=null)
{
len++;
p=p.next;
}
//回文有两种 奇数回文和偶数回文
if(len%2==0)
{
//说明是偶数回文
p=head;
//首先获得后半部分的链表
for(int j=0;j<len/2;j++)
{
p=p.next;
}
ListNode newH=reverse(head,len/2);
//此处如果是使用p==newH来判断 结果是不对的???为啥
while(p!=null)
{
if(p.val!=newH.val) return false;
p=p.next;
newH=newH.next;
}
return true;
}
else
{
//说明是奇数回文
p=head;
//首先获得后半部分的链表
for(int j=0;j<=len/2;j++)
{
p=p.next;
}
ListNode newH=reverse(head,len/2);
while(p!=null)
{
if(p.val!=newH.val) return false;
p=p.next;
newH=newH.next;
}
return true;
}
}
public ListNode reverse(ListNode a,int k){
ListNode cur=a;
ListNode pre=null;
ListNode next=a;
for(int i=0;i<k;i++)
{
next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}