10道链表练习题

目录

1.移除链表元素

2.反转一个单链表

3.链表的中间节点

4.返回倒数第K个节点

5.合并两个有序链表

6.链表分割

7.链表的回文结构

8.相交链表

 9.环形链表1

 10.环形链表2


1.移除链表元素

. - 力扣(LeetCode)

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

 方法1:

创建一个头结点,遍历一遍所给链表,将不等于val的节点增加到新的链表上,返回头结点的下一个节点的引用

class Solution {
    public ListNode removeElements(ListNode head, int val) {
ListNode Nhead=new ListNode(0);
ListNode cur1=head;
ListNode cur2=Nhead;
while(cur1!=null){
    if(cur1.val!=val){
        cur2.next=cur1;
        cur2=cur2.next;
    }
    cur1=cur1.next;
}
cur2.next=null;
return Nhead.next;
    }
}

方法2:

创建一个头结点(哨兵位),让哨兵位的下一个节点指向原头结点的引用,创建一个cur引用指向哨兵位,每次判断cur的下一个节点的值是否为val,如果是就将cur.next指向cur.next.next,否则cur=cur.next

class Solution {
    public ListNode removeElements(ListNode head, int val) {
ListNode Nhead=new ListNode(0);
Nhead.next=head;
ListNode cur=Nhead;
while(cur.next!=null){
    if(cur.next.val==val){
        cur.next=cur.next.next;
    }else{
        cur=cur.next;
    }
}
return Nhead.next;
    }
}

方法3:

使用递归,如果head为null就返回null,否则head的下一个引用再调用removeElements方法,如果head.val==val,就返回head.next,否则返回head。

class Solution {
    public ListNode removeElements(ListNode head, int val) {
if(head==null){
    return null;
}
head.next=removeElements(head.next,val);
if(head.val==val){
    return head.next;
}else{
    return head;
}
    }
}

2.反转一个单链表

. - 力扣(LeetCode)

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

 方法1:

使用三个指针,分别指向连续的三个节点,将中间节点的下一个引用指向上一个节点,将上一个指针指向中间节点,中间指针指向下一个节点,下一个指针指向下一个节点的下一个引用

class Solution {
    public ListNode reverseList(ListNode head) {
if(head==null||head.next==null){
    return head;
}
ListNode cur=head;
ListNode next=head.next;
ListNode prv=null;
while(next!=null){
cur.next=prv;
prv=cur;
cur=next;
next=next.next;
}
cur.next=prv;
return cur;
    }
}

3.链表的中间节点

. - 力扣(LeetCode)

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

方法1:

快慢指针,快慢指针开始均指向头结点,快指针每次走两步,慢指针每次走一步,当快指针为空或者快指针的下一个节点为空时,返回慢指针

class Solution {
    public ListNode middleNode(ListNode head) {
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
    slow=slow.next;
    fast=fast.next.next;
}
return slow;
    }
}

4.返回倒数第K个节点

. - 力扣(LeetCode)

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值

方法1:

先创建一个指针,让他先走k步,再创建一个指针指向头结点,两个指针同时走,当快指针为空时,慢指针指向的节点就为倒数第K个节点

class Solution {
    public int kthToLast(ListNode head, int k) {
ListNode cur=head;
while(k>0){
    cur=cur.next;
    k--;
}
ListNode prv=head;
while(cur!=null){
    cur=cur.next;
    prv=prv.next;
}
return prv.val;
    }
}

5.合并两个有序链表

. - 力扣(LeetCode)

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

方法1:

如果list1或者list2中有一个节点为空,就返回另外一个节点,没有就将小的一个节点的下一个节点使用递归调用mergeTwoLists方法,找到剩下的较小的节点返回

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if(list1==null){
    return list2;
}
if(list2==null){
    return list1;
}
if(list1.val<list2.val){
    list1.next=mergeTwoLists(list1.next,list2);
    return list1;
}else{
    list2.next=mergeTwoLists(list1,list2.next);
return list2;
}

6.链表分割

链表分割_牛客题霸_牛客网

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

方法1:

分别创建两个头结点,一个用来存储小于的,一个用来存储大于的,然后两个链表拼接,返回存储小于的头结点的下一个节点。

注意:当存储大于等于的头节点的下一个节点不为空时,需要将最后一个节点的下一个节点置为空,因为原链表的最后一个节点的值可能是小于目标值的

如果第二个链表除头结点外,没有其他节点,那么直接返回原链表的头结点

public class Partition {
    public ListNode partition(ListNode pHead, int x) {
        if(pHead==null){
            return pHead;
        }
       ListNode NHead1=new ListNode(-1);
       ListNode NHead2=new ListNode(-2);
       ListNode cur1=NHead1;
       ListNode cur2=NHead2;
       ListNode cur=pHead;
while(cur!=null){
    if(cur.val<x){
        cur1.next=cur;
        cur1=cur1.next;
    }else{
        cur2.next=cur;
        cur2=cur2.next;
    }
    cur=cur.next;
}
cur1.next=NHead2.next;
if(NHead2.next!=null){
    cur2.next=null;
}
if(NHead1.next==null){
    return pHead;
}
return NHead1.next;
    }
}

7.链表的回文结构

链表的回文结构_牛客题霸_牛客网

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

方法1:

判断链表是否为空,利用快慢指针找到中间节点,将后面节点的指向反转,创建一个引用指向头结点,与为节点同时开始走,如果两者的值不同,就返回false,当cur1指向的下一个节点是slow指向的节点并且cur1与slow指向的节点值相同时,返回true,当cur1==slow时也返回true

public class PalindromeList {
    public boolean chkPalindrome(ListNode A) {
       ListNode fast=A;
       ListNode slow=A;
       if(A==null){
return true;
       }
while(fast.next!=null&&fast.next.next!=null){
    fast=fast.next.next;
    slow=slow.next;
}
ListNode cur=slow;
slow=slow.next;

while(slow.next!=null){                                                         
    ListNode curN=slow.next;
    slow.next=cur;
    cur=slow;
    slow=curN;
    curN=curN.next;
}
slow.next=cur;
ListNode cur1=A;
while(slow!=cur1){
if(slow.val!=cur1.val){
    return false;
}
if(cur1.next==slow&&cur1.next.val==slow.val){
    return true;
}
cur1=cur1.next;
slow=slow.next;
}
return true;
    }
}

8.相交链表

. - 力扣(LeetCode)

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

 方法1:

两个链表各循环一遍,记录链表长度,让长的链表先走长度的差值,然后同时走,两个指针的指向同一个节点时,那么该节点就是链表相交的节点

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int count1=0;
        int count2=0;
ListNode cur1=headA;
ListNode cur2=headB;
while(cur1!=null){
    cur1=cur1.next;
    count1++;
}
while(cur2!=null){
    cur2=cur2.next;
    count2++;
}
if(count1>count2){
    int tmp=count1-count2;
    cur1=headA;
    cur2=headB;
    while(tmp>0){
        cur1=cur1.next;
        tmp--;
    }
}else{
    int tmp=count2-count1;
cur2=headB;
cur1=headA;
     while(tmp>0){
        cur2=cur2.next;
        tmp--;
    }
}
while(cur1!=cur2&&cur1!=null&&cur2!=null){
    cur1=cur1.next;
    cur2=cur2.next;
}
return cur1;
    }
}

 9.环形链表1

. - 力扣(LeetCode)

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

方法:

利用快慢指针,快指针一次走两步 ,慢指针一次走一步,当快慢指针相遇,说明是环形链表,当快指针走到空,说明不是环形链表

public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
if(fast==slow){
    return true;
}            
        }
        return false;
    }
}

 10.环形链表2

. - 力扣(LeetCode)

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

方法

快慢指针找到第一次相遇的节点,将慢指针指向头结点,快慢指针同时一步一步走,直到相遇,该相遇点就是环入口点

公式:2(L+X)=L+NC+X;

L为未进环的长度,X为在环里走的长度,C为一圈环的长度,N为快指针走的圈数

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
if(slow==fast){
slow=head;
while(true){
    if(slow==fast){
        return slow;
    }
    slow=slow.next;
    fast=fast.next;
}
}
}
return null;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值