数据结构——链表基础(三)

本期我们就主要单链表利用双指针解决经典问题的技巧进行分析讲解

表解体经典思路解法——双指针的应用

本期我们讲解的链表面试题使用的技巧都是一样,主要通过利用两个指针来解决问题。上期我们讲解的链表环的问题其中快慢指针方法也用到了这种技巧

经典面试题:链表相交的问题

给定两个单链表,判断是否有相交,相交的话找到最开始的交点

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //进行非空判断
        if (headA == null || headB == null) {
            return null;
        }
        //分别记录每个链表的长度
        int lenA = 1;
        int lenB = 1;
        ListNode tempA = headA;
        ListNode tempB = headB;
        while (tempA.next != null) {
            lenA++;
            tempA = tempA.next;
        }
        while (tempB.next != null) {
            lenB++;
            tempB = tempB.next;
        }
        //看两个链表是否相交
        if (!tempA.equals(tempB)) {
            return null;
        }
        //利用双指针的技巧,遍历找到焦点
        int reduseCount = lenA - lenB;
        tempA = headA;
        tempB = headB;
        if (reduseCount > 0) {
            for (int i = 0; i < reduseCount; i++) {
                tempA = tempA.next;
            }
        } else {
            reduseCount = Math.abs(reduseCount);
            for (int i = 0; i < reduseCount; i++) {
                tempB = tempB.next;
            }
        }
        while (tempB != null && tempA != null) {
            if (tempB.equals(tempA)) {
                return tempB;
            }
            tempA = tempA.next;
            tempB = tempB.next;
        }
        return null;
    }

思路:主要利用双指针的技巧,先将比较长的那个链表截取后部分,然后使得两个链表长度相同,此时从起点同时向后走会同时到达终点,其中必定同时到达第一个相交处。两个指针分别向后走,然后分别比较,如果指向相同节点,那么说明找到了相交处,然后返回。

经典面试题:链表删除倒数某个节点

删除链表的倒数第K个节点

**思考:**看到题目首先我们想到的是一定是遍历两便链表,第一遍首先知道链表的长度,然后算出何时可以从头到倒数第K个节点,然后直接在第二遍遍历时候取出来。但是有没有一种方法只遍历一遍就可以得到结果呢?这里我们使用双指针方式来解决。我们直接上代码:

  public ListNode removekthFromEnd(ListNode head, int k) {
        if (head == null) {
            return null;
        }
        ListNode first = head;
        ListNode sec = head;
        for (int i = 0; i < k; i++) {
            first = first.next;
        }
        while (first != null && first.next != null) {
            first = first.next;
            sec = sec.next;
        }
        sec.next = sec.next.next;
        return head;
    }

思路:这是一个双指针法思路来解决的典型例题。首先让指针first指向头节点,然后让其向后移动k步,然后指针sec指向头结点和first同时以相同的速度向后移动。first的next指针为NULL同时sec就指向了要删除节点的前一个节点,接着让sec指向的next指针指向要删除节点的下一个节点就可以将对应的节点删除。

经典面试题:查找链表中的中间节点

我们直接上代码:

public ListNode SearchMid(ListNode head) {
        ListNode p = this.head, q = this.head;
        while (p != null && p.next != null && p.next.next != null) {
            p = p.next.next;
            q = q.next;
        }
        return q;
}

思路:这个题目和上期我们解决的含有环的链表类似,用到了快慢指针,让快指针的速度是慢指针的速度的两倍,那么当快指针到达了终点,那么慢指针就正好到达中间的位置。

经典面试题:回文链表

判断一个链表是否是回文链表

 public  boolean isPalindrome(ListNode head) {
        ListNode reverseNode = null;
        ListNode nomalNode;
        if (head.next.next == null) {
            reverseNode = head;
            nomalNode = head.next;
            reverseNode.next = null;
        } else {
            ListNode slow = head;
            ListNode fast = head;
            ListNode tempSlow;
            ListNode tempFast;

            while (fast.next != null && fast.next.next != null) {
                tempSlow = slow.next;
                tempFast = fast.next.next;

                slow.next = reverseNode;
                reverseNode = slow;

                slow = tempSlow;
                fast = tempFast;
            }

            tempSlow = slow.next;
            slow.next = reverseNode;
            reverseNode = slow;

            //考虑链表是奇数长度链表
            if (fast.next == null) {
                reverseNode = reverseNode.next;
            }

            nomalNode = tempSlow;
        }
        //遍历后半截找不同
        while (nomalNode != null && reverseNode != null) {
            if (nomalNode.val != reverseNode.val) {
                return false;
            }
            nomalNode = nomalNode.next;
            reverseNode = reverseNode.next;
        }
        return true;

思路:首先我们通过快慢指针找中间值,同时顺便反转前半截链表,然后遍历后半截找不同。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值