数据结构:链表OJ面试题

文章目录

    • 1.移除链表元素
        • 解题思路(双指针)
    • 2. 翻转链表
        • 解题思路(双指针)
    • 3. 链表的中间节点
        • 解题思路(快慢指针)
    • 4. 链表中倒数第k个节点
        • 解题思路(双指针)
    • 5. 合并两个有序链表
        • 解题思路
    • 6. 链表分割
        • 解题思路
    • 7.链表的回文结构
        • 解题思路
    • 8.相交链表
        • 解题思路
    • 9.环形链表I(经典)
        • 解题思路(快慢指针)
    • 10.环形量表II(经典)
        • 解题思路(快慢指针)

1.移除链表元素

OJ题目链接

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

数据结构:链表OJ面试题_第1张图片

解题思路(双指针)

  • 创建 ListNode cur = head.next 节点。

  • 创建 ListNode prev = head 节点,一直指向 cur 前一个节点。

​ (若要删除 cur 必须知道 cur 前一个节点,因此定义 prev节点)

  • 使 cur 和 prev 节点同时向后遍历,遇到 cur.val == val 再进行删除操作。

数据结构:链表OJ面试题_第2张图片

代码实现如下:

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

2. 翻转链表

OJ题目链接

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

数据结构:链表OJ面试题_第3张图片

解题思路(双指针)

  • 定义两个指针: head 和 cur ;head在前 cur 在后。
  • 每次让 cur 的 next 指向 head,实现一次局部反转。
  • 局部反转完成之后,head和 cur 同时往前移动一个位置。

数据结构:链表OJ面试题_第4张图片

代码实现如下:

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

3. 链表的中间节点

OJ题目链接

给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

数据结构:链表OJ面试题_第5张图片

解题思路(快慢指针)

使用两个指针变量 fast 和 slow,刚开始都位于链表的头结点,slow 一次只走 1 步, fast 一次只走 2 步,一个在前,一个在后,同时走。当 fast.next == null 或 fast == null 时,慢指针就来到了链表的中间位置。

数据结构:链表OJ面试题_第6张图片

代码实现如下:

class Solution {
    public ListNode middleNode(ListNode head) {
        if(head == null) {
            return null;
        }
        if(head.next == null) {
            return head;
        }

        ListNode slow = head;
        ListNode fast = head;

        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
}

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

OJ题目链接

描述

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

示例1

输入:1,{1,2,3,4,5}
返回值:{5}

解题思路(双指针)

  • fast 指针先跑,当 fast 指针跑了k-1个节点后,slow 指针开始跑

  • 当 fast 指针跑到最后时,slow 所指指针就是倒数第k个节点

代码实现如下:

public class Solution {
    public ListNode FindKthToTail(ListNode head, int k) {
        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. 合并两个有序链表

OJ题目链接

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

数据结构:链表OJ面试题_第7张图片

解题思路

建立一个新链表,用来存放通过拼接给定的两个链表的所有节点组成的。先确定头结点为 newHead 。

接着用循环比较两个链表 list1 和 list2 的头结点 val 值的大小,小的存在newHead后面。

数据结构:链表OJ面试题_第8张图片

代码实现如下:

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode newHead = new ListNode();
        ListNode tmpH = newHead;

        while(list1 != null && list2 != null){
            if(list1.val < list2.val) {
                tmpH.next = list1;
                tmpH = list1;
                list1 = list1.next;
            }else {
                tmpH.next = list2;
                tmpH = list2;
                list2 = list2.next;
            }
        }
        if(list1 != null){
            tmpH.next = list1;
        }
        if(list2 != null){
            tmpH.next = list2;
        }
        return newHead.next;
    }
}

6. 链表分割

OJ题目链接

描述

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

解题思路

先令cur=head,把链表分成两段,bs为小于目标值的,as为大于等于目标值的

让cur遍历链表并判断节点放入哪一段里,直到cur==null;

若cur.val=x,一样的方法

循环结束后把as尾插到be,返回bs

数据结构:链表OJ面试题_第9张图片

代码实现如下:

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 = cur;
                    be = cur;
                }else{
                    be.next = cur;
                    be = cur;
                }
            }else{
                if(as == null){
                    as = cur;
                    ae = cur;
                }else{
                    ae.next = cur;
                    ae = cur;
                }
            }
            cur = cur.next;
        }
        if(bs == null){
            return as;
        }
        be.next = as;
        if(as != null){
            ae.next = null; 
        }
        return bs;
        }
}

7.链表的回文结构

OJ题目链接

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

测试样例:

1->2->2->1
返回:true

解题思路

  1. 先找到中间节点。(可以参考上文 3.链表的中间节点)
  2. 后半段进行翻转。(参考上文 2.翻转链表)
  3. 前半段与后半段进行比较是否相同。 (循环比较)

数据结构:链表OJ面试题_第10张图片

代码实现如下:

	public class PalindromeList {
    public boolean chkPalindrome(ListNode A) {
        // write code here
        //1.找到中间节点
        ListNode fast = A;
        ListNode slow = A;

        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        //2.后半段进行翻转
        ListNode cur = slow.next;
        while(cur != null){
            ListNode curNext = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curNext;
        }
        //3.进行比较
        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.相交链表

OJ题目链接

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

图示两个链表在节点 c1 开始相交:

数据结构:链表OJ面试题_第11张图片

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构

解题思路

先用计数器遍历两个单链表,得到两个链表的长度,由于不确定 A 与 B 哪个长,因此要进行判断。

求完长度后作差,然后使较长的链表向后走 |A - B|个节点。

以上操作完成后,使两个链表同时向后走,直至 A == B。

代码实现如下:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null){
            return null;
        }

        ListNode pLong = headA;
        ListNode pShort = headB;

        int len1 = 0;
        int len2 = 0;

        while(pLong != null){
            len1++;
            pLong = pLong.next;
        }

        while(pShort != null){
            len2++;
            pShort = pShort.next;
        }

        pLong = headA;
        pShort = headB;

        int len0 = len1 - len2;
        if(len0 < 0){
            pLong = headB;
            pShort = headA;
            len0 = len2 - len1;
        }
        while(len0 != 0){
            len0--;
            pLong = pLong.next;
        }

        while(pLong != pShort){
            pLong = pLong.next;
            pShort = pShort.next;
        }
        return pLong;
    }
}

9.环形链表I(经典)

OJ题目链接

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

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

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

数据结构:链表OJ面试题_第12张图片

解题思路(快慢指针)

设置两个指针 fast 和 slow,fast一次走两个节点 ,slow一次走一个节点。若果链表内存在环则 fast 和 slow 早晚会相遇。

则这道题只需要让两个指针不断往后走,直到 fast 和 slow相遇,说明存在环,反之不存在环。

代码实现如下:

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;
            slow = slow.next;
            if(fast == slow){
                return true;
            }
        }
        return false;
    }
}

10.环形量表II(经典)

ps:这道题很经典,面试的时候若果出现链表题 ,考这道题的几率也非常非常较大

OJ题目链接

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

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

不允许修改 链表。

数据结构:链表OJ面试题_第13张图片

解题思路(快慢指针)

:happy:这道题用到一点点初中数学

  1. 先找到相遇点(参照上文环形链表I)。
  2. fast指针回到起始点。
  3. 使 fast 和 slow 不断向后走,直到相遇,得到入口点。

数据结构:链表OJ面试题_第14张图片

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 = head;
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }
}

你可能感兴趣的:(数据结构Java实现,链表,数据结构,leetcode)