1. 环形链表(经典中的经典),返回入环节点,那么我们应该怎么做呢,首先判断链表有没有环,然后是不是空,用经典的快慢指针,快的指针一次走两步,慢的指针走一步,
问题一:先想一下,为什么fast的速度设置为2,slow的速度为1
假如两个有环,他们俩个一定会相遇,因为在环中,fast相当于比slow永远多走一步,也就是说,fast相当于在环里面一直走,slow一直保持原有的位置没有动,所以一定会相遇,所以fast的速度为2在环中会一定和slow相遇
问题二后面的代码是什么意思(不明白看我的图)
fast的速度一直是slow的二倍,所以肯定路程也是二倍(保姆级教学
)
L是头到环入口的距离,环入口到相遇点的距离是X,M是相遇点到环的入口的距离
力扣142
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast=head;
ListNode slow =head;
ListNode cur =head;
if(head==null){ //判断是否为空
return null;
}
while(fast!=null&&fast.next!=null){//如果没有环,那么一定会有空的时候
fast=fast.next.next;
slow=slow.next;
if(slow==fast){ //把它放后面很细节,是为了不让fast和slow等于头退出
break;
}
}
if(fast==null||fast.next==null){ //判断是否有环
return null;
}
while(slow!=cur){ //找环的入口点
cur=cur.next;
slow=slow.next;
}
return cur;
2.链表相交 很简单思路,把A,B链表走一遍,知道长度差,然后谁长,让谁先走,然后看相不相交
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode cur=headA;
ListNode curv=headB;
int la=0; //a表长度
int lb=0; //b表长度
if(headB==null&&headA==null){
return null;
}
if(headA==null&&headB!=null||headB==null&&headA!=null){
return null;
}
while(cur!=null){ //计算A与B的长度
la++;
cur=cur.next;
}
while(curv!=null){
lb++;
curv=curv.next;
}
cur=headA; //还原两个指针,让他们两个再次指向头
curv=headB;
if(lb>la){
while(lb-la>0&&curv!=null){ //b长先走
curv=curv.next;
lb--;
}
}
else{
while(la-lb>0&&cur!=null){
cur=cur.next; //a长a先走
la--;
}
}
while(cur!=null){ //很重要一个点,相交是点相同,不是点值相同
if(cur==curv){ //不要去写.val==.val是不对的
return cur;
}
cur=cur.next;
curv=curv.next;
}
return null;
}
}
3.双向链表。要求会写,这是类的必须,其他类中的方法放到下面,内部类是必须要的,然后下面是链表具备的头和尾指针方便插入和删除,(需要分到两个部分写),
下面的各种函数你也都可以用phead就是像c语言那种传一个头之类的。
public class ListNode {
public class LinkedNode{
int val;
LinkedNode next = null;
LinkedNode prev=null;
LinkedNode(int val) {
this.val = val;
}
}
public LinkedNode head; //链表的头
public LinkedNode tail; //链表的尾巴
3.(1)头插
// 2、无头双向链表实现
//头插法
public void addFirst(int data){
LinkedNode p=new LinkedNode(data); 申请一个节点
if(head==null){ //之前的节点为空的话,就头和尾都在开始的节点
head=p;
tail=p;
}
p.prev=null; //头节点的前面是NULL
head.prev=p; //头连接P节点
p.next=head;
head=p; //P成为新的头
tail.next=null; //尾节点下一个还是null
}
(2)尾插
public void addLast(int data){
LinkedNode p=new LinkedNode(data); //还是生成个节点
if(head==null){
head=p; //头和尾都是空
tail=p;
}
while(tail.next!=null){
tail=tail.next; //尾巴遍历到最后
}
tail.next=p; //tail的下一个连像尾巴节点p
p.prev=tail; //p的前一个节点是尾巴
tail=p; //尾巴指向p
}
(3)任意位置插入,第一个数据节点为0号下标,插入节点
public boolean addIndex(int index,int data) {
if(index<0||index>size()){ //插入序列不合理
return false;
}
LinkedNode cur=head;
LinkedNode p=new LinkedNode(data);
int n=1;
if(index==1){ //插入第一个就是头插
addFirst(data);
}
while(n<index){
n++; //找到要插入节点的前面
cur=cur.next;
}
if(cur.next.next!=null) {
p.next=cur.next; //插入中间节点
p.prev=cur; //P的前驱后继
cur.next.prev=p;
cur.next=p; //前驱节点的下一个连接他
}
else {
addLast(data); //最后一个就是尾插
}
return true;
}
(4)看关键字key在不在链表中(简单的遍历)
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
LinkedNode cur=head;
while(cur!=null){
if(cur.val==key){
return true;
}
cur=cur.next;
}
return false;
}
(5)//删除第一次出现关键字为key的节点
//删除第一次出现关键字为key的节点
public void remove(int key){
LinkedNode cur=head;
while(cur!=null){
if(cur.next.val==key){
break;
}
}
cur.next.prev=null; //key值的前一个点,的前指针为空
cur.next.next.prev=cur; //key的后一个节点连key前面的节点
cur.next=cur.next.next; //key值的前一个点下一个连接key值的下一个
}
(6)删除所有值为key的节点(删除全部和上面的删除一个意思一样)
public void removeAllKey(int key){
LinkedNode cur=head;
while(cur!=null){
if(cur.next.val==key){
cur.next.prev=null;
cur.next.next.prev=cur;
cur.next=cur.next.next;
}
}
}
(7)链表长度和展示(简单不解析了)
//得到单链表的长度
public int size(){
LinkedNode cur=head;
int n=0;
while(cur!=null){
cur=cur.next;
n++;
}
return n;
}
public void display(){
LinkedNode cur=head;
while(cur!=null){
System.out.println(cur.val);
cur=cur.next;
}
}