剑指 Offer II 链表
ListNode“变量”是引用 是指向该对象的遥控器 不真的是该对象
021. 删除链表的倒数第 n 个结点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
int m=0;
ListNode dummy=new ListNode(-1);
dummy.next=head;
//while(head!=null)
for(ListNode p=dummy;p!=null;p=p.next)m++;//包含dummy是 实际链表长度+1
ListNode p=dummy;
for(int i=0;i<m-n-1;i++)p=p.next;
p.next=p.next.next;
return dummy.next;
}
}
022链表中环的入口节点 第一次见这种做法:快慢指针扫描
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null||head.next==null)return null;
ListNode first=head;
ListNode second=head;//一次走两步
while(first!=null&&second!=null)
{
first=first.next;
second=second.next;
if(second!=null)second=second.next;
else return null;
if(first==second)
{
first=head;
while(first!=second)
{
first=first.next;
second=second.next;
}
return first;
}
}
return null;
}
}

如上图所示,aa 是起点,bb 是环的入口,cc 是两个指针的第一次相遇点,abab 之间的距离是 xx,bcbc 之间的距离是 yy。
另外感谢@watay147提供的另一种思路,可以用公式来说明:a,b,c,x,ya,b,c,x,y 的含义同上,我们用 zz 表示从 cc 点顺时针走到 bb 的距离。则第一次相遇时 secondsecond 所走的距离是 x+(y+z)∗n+yx+(y+z)∗n+y, nn 表示圈数,同时 secondsecond 走过的距离是 firstfirst 的两倍,也就是 2(x+y)2(x+y),所以我们有 x+(y+z)∗n+y=2(x+y)x+(y+z)∗n+y=2(x+y),所以 x=(n−1)×(y+z)+zx=(n−1)×(y+z)+z。那么我们让 secondsecond 从 cc 点开始走,走 xx 步,会恰好走到 bb 点;让 firstfirst 从 aa 点开始走,走 xx 步,也会走到 bb 点。
时间复杂度分析:firstfirst 总共走了 2x+y2x+y 步,secondsecond 总共走了 2x+2y+x2x+2y+x 步,所以两个指针总共走了 5x+3y5x+3y 步。由于当第一次 firstfirst 走到 bb 点时,secondsecond 最多追一圈即可追上 firstfirst,所以 yy 小于环的长度,所以 x+yx+y 小于等于链表总长度。所以总时间复杂度是 O(n)O(n)。
作者:yxc
链接:https://www.acwing.com/solution/content/241/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
023. 两个链表的第一个重合节点
思路难想 一条走到尾的话从另一条开始走
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p=headA,q=headB;
while(p!=q)
{
p= p==null ? headB:p.next;//p走到头了吗? 有的话从b开头走
q= q==null ? headA:q.next;
}
return p;
}
}
024. 反转链表 这道我做了好多遍还是忘~~~
a b两指针从head开始每次移动一位
public ListNode reverseList(ListNode head) {
if(head==null)return head;
ListNode a=head,b=head.next;
while(b!=null)//当b指向空 a是尾节点
{
ListNode c=b.next;//temp
b.next=a;//我只反a b之间的 方向 最后再让第一个a指向空
a=b;b=c;//把两个指针往后移动一格
}
head.next=null;
return a;
}
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null)return head;
ListNode tail=reverseList(head.next);//会返回一个 以原来尾为头 原来head.next为尾的反转过的链表
head.next.next=head;
head.next=null;
return tail;
}
}
025. 链表中的两数相加
public ListNode rev(ListNode head)
{
ListNode a=head,b=head.next;
while(b!=null)
{
ListNode c=b.next;
b.next=a;
a=b;b=c;
}
head.next=null;
return a;
}
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
l1=rev(l1);l2=rev(l2);
ListNode ans=new ListNode(-1);
int t=0;
while(l1!=null||l2!=null||t!=0)
{
if(l1!=null)
{
t+=l1.val;
l1=l1.next;
}
if(l2!=null){
t+=l2.val;
l2=l2.next;
}
ListNode c=new ListNode(t%10);
t/=10;
c.next=ans.next;
ans.next=c;
}
return ans.next;
}
026. 重排链表
class Solution {
public ListNode rev(ListNode x)
{
ListNode a=x,b=x.next;
while(b!=null)
{
ListNode c=b.next;
b.next=a;
a=b;b=c;
}
x.next=null;
return a;
}
public void reorderList(ListNode head) {
if(head==null||head.next==null)return ;
/*
1.找中点
2.把(n+1)/2后的点反转
3.合并
*/
int n=0;
for(ListNode p=head;p!=null;p=p.next)n++;
ListNode p=head;
for(int i=0;i<(n-1)/2;i++)p=p.next;//n/2次 5-》跳2次 4-》跳1次
ListNode q=p.next;//p q中间两个点
q=rev(q);
p.next=q;
while(head!=null&&q!=null)//前后两个指针走
{
ListNode H=head.next,Q=q.next;
第一段的尾连上第二段头的next
p.next=q.next;
插入
q.next=head.next;
head.next=q;
head=H; q=Q;
}
}
}
027. 回文链表
class Solution {
ListNode rev(ListNode x)
{
if(x.next==null||x==null)return x;
ListNode tail=rev(x.next);
x.next.next=x;
x.next=null;
return tail;
}
public boolean isPalindrome(ListNode head) {
List<Integer>a=new ArrayList();
ListNode p=head;
while(p!=null)
{
//System.out.println(p.val);
a.add(p.val);
p=p.next;
}
// System.out.println(a.get(0));
head=rev(head);
int t=0;
boolean flag=true;
while(head!=null)
{
if(!a.get(t).equals(head.val)) flag=false;
t++;
head=head.next;
}
return flag;
}
}
028. 展平多级双向链表
class Solution {
public Node flatten(Node head) {
if(head==null||(head.next==null&&head.child==null))return head;
Node p;
if(head.child==null){
p=flatten(head.next);//处理好扁平的链表
head.next=p;
p.prev=head;
}
else
{
p=flatten(head.child);
Node q=p;
while(q.next!=null)q=q.next;//找最后一个点
q.next=head.next;
if(head.next!=null) head.next.prev=q;//太细了 wa在这里
head.next=p;
p.prev=head;
head.child=null;
}
return head;
}
}

浙公网安备 33010602011771号