leetcode: 相交链表

leetcode:160
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表**:**
图片
在节点 c1 开始相交。

示例 1:
图片
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

解法1(使用栈解决)

思路:
用栈作为辅助栈,栈的特性"先进后出",那么我们将两个链表放入栈中,遍历出来的第一个肯定是尾节点。那么如果两个链表相交,则肯定从尾节点往前遍历,到相交节点后面的元素肯定都是一样的,所以我们只要比较两个栈中从尾节点开始比较,如果找到不相等的节点,则前节点就是相交的节点;
时间复杂度分析:
遍历到两个栈中,时间复杂度为O(n),两个栈的比较,则是O(m)(m<n),所以整体时间复杂度为O(n)
空间复杂度分析: 因为用到了辅助栈,所以时间复杂度为O(n)

代码:

/**
 * 使用栈作为辅助栈的解法
 * 用到了辅助栈,时间辅助度为O(m+n)
 *
 * @param headA
 * @param headB
 * @return
 */
public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {

    // 1.判空
    if (headA == null || headB == null) {
        return null;
    }
    // 2.定义两个辅助栈,用来存储两个链表遍历的数据
    Stack<ListNode> stackA = new Stack<ListNode>();
    Stack<ListNode> stackB = new Stack<ListNode>();
    ListNode nodeA = headA;
    ListNode nodeB = headB;
    // 3.遍历链表,存入栈中
    while (nodeA != null) {
        stackA.push(nodeA);
        nodeA = nodeA.next;
    }
    while (nodeB != null) {
        stackB.push(nodeB);
        nodeB = nodeB.next;
    }

    // 遍历栈中元素进行比较,从尾部开始,找到不同的节点处则返回结果
    ListNode pre = null;
    while (!stackA.isEmpty() && !stackB.isEmpty()) {
        if (stackA.peek() != stackB.peek()) {
            return pre;

        } else {
            pre = stackA.peek();
            stackA.pop();
            stackB.pop();
        }

    }
    return pre;

}

解法2(优化)

思路:
我们如果可以得到两个链表的长度,那么如果两个链表长度一致的话,两个链表同时从头节点出发同步前进,则当两个节点一样的时候,则是相遇节点;如果两个链表长度不一样长,把长的链表变成跟 比它短的链表一样的长度,即让长的链表先走k步(k= 长链表A - 短链表B),然后两者再一起同步前进即可。
时间复杂度分析:因为需要找到链表的长度,即要遍历链表,则遍历链表A的长度时间复杂度为O(m)(m<n),链表B的长度时间复杂度为O(n),且一起同步的时间复杂度为O(k)(k<n),整体复杂度为O(n)
空间复杂度分析: 没使用其他空间,则为O(1)

代码:

/**
 * 优化: 先求出链表的长度,然后让长的链表先走对应的步数,然后再同时走,再进行比较
 *
 * @param headA
 * @param headB
 * @return
 */
public static ListNode getIntersectionNode2(ListNode headA, ListNode headB) {

    // 1.判空
    if (headA == null || headB == null)
        return null;
    // 2.数组长度
    int lengthA = 0;
    int lengthB = 0;
    ListNode nodeA = headA;
    ListNode nodeB = headB;
    // 3.求出A/B长度
    while (nodeA != null) {
        lengthA++;
        nodeA = nodeA.next;
    }
    while (nodeB != null) {
        lengthB++;
        nodeB = nodeB.next;
    }
    // 重新赋值
    nodeA = headA;
    nodeB = headB;
    // 4.判断谁的长度比较长,则让它先走
    if (lengthA < lengthB) {
        int distance = lengthB - lengthA;
        for (int i = 0; i < distance; i++) {
            nodeB = nodeB.next;
        }
    }else if(lengthA> lengthB) {
        int distance = lengthA - lengthB;
        for (int i = 0; i < distance; i++) {
            nodeA = nodeA.next;
        }
    }

    // 5. 两者同步前进并比较
    while (nodeA != null && nodeB != null) {
        if (nodeA == nodeB) {
            return nodeA;
        }
        nodeA = nodeA.next;
        nodeB = nodeB.next;
    }

    return null;

}

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值