【数据结构】链表面试题

目录

1.反转链表

2.链表的中间节点

3.链表中倒数第k个节点

4.合并两个有序链表 

5.链表分割

6.判断回文链表

7.递归逆序打印链表

8.相交链表

9.环形链表Ⅰ

10.环形链表Ⅱ


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; 
     }
}

1.反转链表

反转链表  要求:时间复杂度O(n),空间复杂度O(1)

class Solution {
        public ListNode reverseList(ListNode head) {
            if (head == null) { //一个节点都没有
                return null;
            }
            if (head.next == null) { //只有一个节点
                return head;
            }
            ListNode cur = head.next;
            head.next = null;
            while (cur != null) {
                ListNode curNext = cur.next;
                cur.next = head;
                head = cur;
                cur = curNext;
            }
            return head;
        }
    }

2.链表的中间节点

链表的中间节点

class Solution {
    public ListNode middleNode(ListNode head) {
        if (head == null) { //一个节点都没有
            return null;
        }
        if (head.next == null) { //只有一个节点
            return head;
        }
        //快慢指针
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) { //注意这里两个条件顺序不能变!!
            fast = fast.next.next; //fast一次走两步
            slow = slow.next; //slow一次走一步
        }
        return slow;
    }
}

3.链表中倒数第k个节点

链表中倒数第k个节点

public class Solution {
   public ListNode FindKthToTail(ListNode head,int k) {
        if (k <= 0 || head == null) { //判断k和链表的有效性
            return null;
        }
        //快慢指针
        ListNode fast = head;
        ListNode slow = head;
       for (int i = 0;i < k-1;i++) { //先让fast走k-1步
                fast = fast.next;
                if (fast == null) { //相当于直接越界
                    return null;
                }
            }
        while (fast.next != null) { //再让fast和slow一起走
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

4.合并两个有序链表 

合并两个有序链表

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode newHead = new ListNode();//定义一个新头作为合并链表的起点
        ListNode tmpH = newHead;//tmpH指向每一个合并后链表的元素
        while (list1 != null && list2 != null) {
            if (list2.val < list1.val) { //list2的val小于list1的val时
                tmpH.next = list2; //当前tmpH的next存入该节点的地址
                tmpH = tmpH.next; //tmpH向后走一步
                list2 = list2.next; //list2向后走一步
            }else { //同上
                tmpH.next = list1;
                tmpH = tmpH.next;
                list1 = list1.next;
            }
        }
        //list1为空时,说明list1已遍历完,此时list2剩余元素直接接入list1后即可
        if (list1 == null) {
            tmpH.next = list2;
        }
        //同上
        if (list2 == null) {
            tmpH.next = list1;
        }
        //注意返回的是newHead.next而不是newHead
        return newHead.next;
    }
}

5.链表分割

链表分割

public class Partition {
    public ListNode partition(ListNode pHead, int x) {

        ListNode bs = null;//before start
        ListNode be = null;//before end
        ListNode as = null;//after start
        ListNode ae = null;//after end

        ListNode cur = pHead ;//cur初识化为头节点

        while (cur != null) { //遍历链表
            if (cur.val < x) { //小于x放在前面
                if (bs == null) { //第一次存放
                    bs = cur;
                    be = cur;
                }else {
                    be.next = cur;
                    be = be.next;
                }
            }else { //大于x放在后面
                if (as == null) { //第一次存放
                    as = cur;
                    ae = cur;
                }else {
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next; //cur向后走一步
        }

        if (bs == null) { //说明没有元素小于x
            return as; //返回后面的头节点
        }
        if (as != null) { //当后面存放了元素时
            ae.next = null; //注意要手动将尾节点置空
        }

        be.next = as; //将前后连起来
        return bs; //返回前面头节点
    }
}

6.判断回文链表

判断回文链表

public class PalindromeList {
    public boolean chkPalindrome(ListNode head) {
        if (head == null) {
            return true;
        }
        //找到中点节点
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        //翻转后半部分
        ListNode cur = slow.next;
        while (cur != null) {
            ListNode curNext = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curNext;
        }
        //一前一后依次比较
        while (head != slow){
            if (head.val != slow.val) {
                return false;
            }
            if (head.next == slow) { //此处是偶数情况
                return true;
            }
            head = head.next;
            slow = slow.next;
        }
        return true;
    }
}

7.递归逆序打印链表

递归在C语言中写了不少了,图也没啥好画的,直接上代码~~

public class Test {
    /*void printList(ListNode head){
        if(null != head){
            printList(head.next);
            System.out.print(head.val + " ");
        }
    }*/
     public static void printList(ListNode head) {
        if (head == null) {
            return;
        }
        if (head.next == null) {
            System.out.print(head.val+" ");
            return;
        }
         printList(head.next);
         System.out.print(head.val+" ");
    }
}

8.相交链表

相交链表

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ListNode plong = headA;//假设A长B短
        ListNode pshort = headB;
        //1.分别求两个链表的长度
        int len1 = 0;
        int len2 = 0;
        while (plong != null) {
            len1++;
            plong = plong.next;
        }
        while (pshort != null) {
            len2++;
            pshort = pshort.next;
        }
        plong = headA;
        pshort = headB;
        //2.求两个链表的差值
        int len = len1 - len2;
        if (len < 0) { //说明A短B长
            plong = headB;
            pshort = headA;
            len = len2 - len1;
        }
        //到这里确保plong指向长链表,len大于0 
        //3.哪个链表长先走len步
        while (len != 0) {
            plong = plong.next;
            len--;
        }
        //4.一起走,直到相遇
        while (plong != pshort) {
            plong = plong.next;
            pshort = pshort.next;
        }
        return plong;
    }
}

9.环形链表Ⅰ

环形链表Ⅰ

public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null) {
            return false;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next; //fast每次走2步
            slow = slow.next; //slow每次走1步
            if (fast == slow) { //相遇说明一定有环
                return true;
            }
        }
        return false;
    }
}

10.环形链表Ⅱ

环形链表Ⅱ

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null) {
            return null;
        }
        //找相遇点
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                break;
            }
        }
        //判断是否有环
        if (fast == null || fast.next == null) {
            return null;
        }
        //fast在起始点,slow在相遇点
        fast = head;
        //一起走直到相遇就是入口点
        while (fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值