链表面试题

目录

前言:

1. 删除链表中等于给定值 val 的所有节点。 

2. 反转一个单链表。 

3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

4. 输入一个链表,输出该链表中倒数第k个结点。

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

6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。

7. 链表的回文结构。

8. 输入两个链表,找出它们的第一个公共结点。


前言:

在些数据结构算法题,画图分析无疑是一把利刃。

在脑海里数据结构中单链表的结构可以理解为下图

a8eb3dc320074db5a6f76c67c5ada565.png

1. 删除链表中等于给定值 val 的所有节点。 

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/remove-linked-list-elements/description/

题目描述:

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

测试样例:

20770b2a58d043a3aa7e883dbbcffecf.png

代码实现:

思路:

a1c6561bc0384af7a0fabd5300e13d0e.png


class Solution {
    public ListNode removeElements(ListNode head, int val) {
    // 头结点为空的情况
        if(head == null) {
            return null;
        } 
    // 定义一个结点遍历整条链表,头结点最后考虑
    // 定义一个前驱,方便删除操作
        ListNode cur = head.next;
        ListNode prev = head;
    //  遍历到cur为空,整条链表可以遍历完
        while(cur != null ) {
            if(cur.val==val) {
                prev.next = cur.next;
                cur = cur.next;
            }else{
                prev = cur;
                cur = cur.next;
            }
        }
        // 头结点和头结点后一个 都要删除的情况 到这一步都在这不存在(所以判断头结点放到最后),
        //  画图便知
        if(head.val==val) {
            head = head.next;   
    }
    return head;
}
}

2. 反转一个单链表。 

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/description/

题目描述:

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

测试样例:

71b4bdeb1d98474d8baa69cdd6cb9e66.png

5b669e46c086411684e4a855a87d6f41.png

代码实现:

思路:从第二个节点开始,头插法实现逆转

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

    }
}

3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/middle-of-the-linked-list/description/

题目描述:

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

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

测试样例:

d931ea2387a44868adb5b9343797bafa.png

思路:同样的路程下,fast的速度是slow的两倍,当fast到达终点时,slow到达中间

代码实现:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode middleNode(ListNode head) {
    if(head==null) {
        return null;
    }
    ListNode slow = head;
    ListNode fast = head;
    while(fast!=null&&fast.next!=null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow;
    
    }
}

4. 输入一个链表,输出该链表中倒数第k个结点。

题目链接:

链表中倒数第k个结点_牛客题霸_牛客网输入一个链表,输出该链表中倒数第k个结点。。题目来自【牛客题霸】icon-default.png?t=N7T8https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&&tqId=11167&rp=2&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

题目描述:

输入一个链表,输出该链表中倒数第k个结点。

测试样例:

d3fff35dc6074427905eaac3bc06f2dc.png

思路:1.让fast先走k-1步

           2.fast和slow同时走,因为fast先走了k-1步,所以fast和slow永远相差k步

           3.当fast到终点时,slow和fast相差k步,所以slow就为倒数第k个结点。

代码实现:

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/

public class Solution {

    public ListNode FindKthToTail(ListNode head,int k) {
        //如果k是负数或者很大,为非法情况
        //   if(k<=0||k>size())
        //    但是这里size() 已经遍历了一次
        //    所以在for循环后面 判断  如果fast为空了 直接return
       if(k <=0 || head == null ) {
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        for(int i = 0;i < k-1; i++) {
            fast = fast.next;
            if(fast == null) {
                return null;
            }
        }
        while(fast.next!= null ){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

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

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/merge-two-sorted-lists/description/

题目描述:

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

思路:

d619d8004d084830a1e0eccdfb9df915.jpeg

代码实现:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {

       ListNode newHead = new ListNode();
       ListNode tHead = newHead;
       ListNode head1 = list1;
       ListNode head2 = list2; 
       while(head1!=null&&head2!=null) {
           if(head1.val<head2.val) {
               tHead.next = head1;
               head1=head1.next;
           }else{
               tHead.next = head2;
               head2 = head2.next;
           }
           tHead = tHead.next;
       }
       if(head1!=null) {
           tHead.next = head1;
       }     
       if(head2!=null) {
           tHead.next = head2;
       }
       return newHead.next;
    }
}

6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。

题目链接:

链表分割_牛客题霸_牛客网现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的。题目来自【牛客题霸】icon-default.png?t=N7T8https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8&&tqId=11004&rp=2&ru=/activity/oj&qru=/ta/cracking-the-coding-interview/question-ranking

题目描述:

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

思路:这里x取20

37171e9af8f742a48790b400c7005abb.png

通过遍历整条链表,将数据分为两组,一直是在20之前的,一组在之后的

f712b6ca78244976bd7336ba23d2173b.png

特殊情况:

4693963157e54034951ac6deca06143c.png

代码实现:

import java.util.*;

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Partition {
    public ListNode partition(ListNode pHead, int x) {
        // write code here
        ListNode bs = null;
        ListNode be = null;
        ListNode as = null;
        ListNode ae = null;

        ListNode cur = pHead;

        while(cur!=null) {
            if(cur.val<x) {
                //第一次插入
                if(bs==null) {
                    bs = be = cur;
                }else{
                    be.next = cur;
                    be = be.next;
                }
            }else{
                //第一次插入
                if(as==null) {
                    as = ae =cur;
                }else{
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        //前面一段没有数据的情况
        if(bs==null) {
            return as;
        }
        be.next = as;
        // 原链表最后一个数字不是最大的情况,容易造成死循环
           if(ae!=null) {
            ae.next = null;
        }
     
        return bs;
        
    }
}

7. 链表的回文结构。

题目链接:

链表的回文结构_牛客题霸_牛客网对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为。题目来自【牛客题霸】icon-default.png?t=N7T8https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId=49&&tqId=29370&rp=1&ru=/activity/oj&qru=/ta/2016test/question-ranking

题目描述:

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

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

测试样例:

0c9a7245ea4e4cfaa669bac6f3ceb6c1.png

思路:

为上面第三题和第五题的组合

1.找到链表的中间节点

2.翻转中间节点以后的链表

3.从前  从后 同时往前遍历 判断是否回文

4d2b9d9499b04097b726e1bf552fbfeb.png

代码实现:

import java.util.*;

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class PalindromeList {
    public boolean chkPalindrome(ListNode A) {
        // write code here
        ListNode slow = A;
        ListNode fast = A;
        //找到中间节点
        while(fast!=null&&fast.next!=null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        //逆转后半段节点
        
        ListNode cur = slow.next;
        while(cur!=null) {
            ListNode curNext = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curNext;
        }
        //同时向中间靠拢
        ListNode Ahead = A;
        while(A!=slow) {
            if(A.val!=slow.val) {
                return false;
            }
            if(A.next == slow) {
                return true;
            }
            A = A.next;
            slow = slow.next;
        }
        return true;
    }
}

8. 输入两个链表,找出它们的第一个公共结点。

题目链接:

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=N7T8https://leetcode.cn/problems/intersection-of-two-linked-lists/description/

题目描述:

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

测试样例:

9f8c52ec7ce3426eae09158bd1fb7357.png

c6627c071dc949d588fd1f0112faa5cd.png

35ed0b4a878e49de95ff98922faca113.png

思路:

1.相交只能是Y字形

2.两个链表长度不一样主要体现在它们相交前

3.可以让最长的链表引用先走他们的差值步

88b33926674e4bc98685b05542bbf3b1.png

代码实现:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA = 0;
        int lenB = 0;
        int len = 0;
        // 假定最长的是A
        ListNode pL = headA;
        ListNode pS = headB;
        //长度 
        while(pL!=null) {
            lenA++;
            pL = pL.next;
        }
        while(pS!=null) {
            lenB++;
            pS = pS.next;
        }
        len = lenA-lenB;
        pL = headA;
        pS = headB;
        //修正指向  和  len的差值
        if(len<0) {
            pL = headB;
            pS = headA;
            len = lenB - lenA;
        }
        //保证 pl指向最长的 ps指向最短的 len 是一个正数
        if(pL==null||pS==null) {
            return null;
        }
        //2.让最长的列表走差值步
         for(int i = 0;i < len ;i++) {
             pL = pL.next;
         }
         //3.相遇的点
         while(pL!=pS) {
             pL = pL.next;
             pS = pS.next;
         }
         return pL;
        
    }
}

  • 16
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值