LeetCode:160. Intersection of Two Linked Lists

题目是:

Write a program to find the node at which the intersection of two
singly linked lists begins.

也就是两个链表是从哪一节点开始相交的。

这题不难,但是很有意思,有些解法会让你感到“哦,还能这样!”

1.解法一
分别遍历两条链表,将元素分别放到两个堆栈。然后比较堆栈顶的两个元素,如果相同,则都弹出;如果不同,说明之前弹出的元素是要求的。这个方法是最简单暴力的:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        stack<ListNode*> s1, s2;
        while(headA) {
            s1.push(headA);
            headA = headA->next;
        }
        while(headB) {
            s2.push(headB);
            headB = headB->next;
        }
        ListNode* p = nullptr;
        while (!s1.empty() && !s2.empty() && s1.top() == s2.top()) {
            p = s1.top();
            s1.pop();
            s2.pop();
        }
        return p;
    }
};

2.解法二
这次我们分别遍历两条链表,求出两条链表的长度。看哪一条长,比如说L1比L2长2,那么我们先从L1的头节点前进两个节点,然后L1从这个节点出发,L2从头节点出发,每次前进一个。如果它们相交,那么必然会同时到达那个交点:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        auto len1 = Length(headA);
        auto len2 = Length(headB);
        if (len1 == 0 || len2 == 0)
            return NULL;
        if (len1 > len2)
            headA = moveForward(headA, len1-len2);
        if (len1 < len2)
            headB = moveForward(headB, len2-len1);
        while(headA && headB && headA->val != headB->val) {
            headA = headA->next;
            headB = headB->next;
        }
        return headA;
    }
private:
    int Length(ListNode *head) {
        int len = 0;
        while(head) {
            ++len;
            head = head->next;
        }
        return len;
    }
    ListNode *moveForward(ListNode *head, int k) {
        assert(k > 0);
        while(k-- > 0)
            head = head->next;
        return head;
    }
};

3.解法三
这是最有意思的一个解法。
我们考虑一下解法二,我们是先求出链表的长度。但实际上我们关心那个长度的值吗?我们不关心,我们只是想要确保两个指针同时到达相交点罢了。
考虑这样一种方法:我们同时开始遍历两个链表。一旦一个链表到达尾部,那么我们就把指针指向另一个链表的开始节点,继续遍历。这样的话,如果有相交点,那么会同时到达;如果没有相交点,那会同时到达链表尾端。
代码:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if (!headA || !headB)
            return NULL;
        auto p1 = headA, p2 = headB;
        while (p1 != p2) {
            p1 = p1? p1->next : headB;
            p2 = p2? p2->next : headA;            
        }
        return p1;
    }
};

是不是很有意思?
本质上和方法二是同一种思想,都是为了消除链表间的长度差,只不过这里更巧妙一点而已。

到此为止,做过的链表题目的较为常用的方法有:
1.一快一慢两个指针
2.一个先将长度差走完,然后一起走(这里的方法二)
3.一个链表走完再从另一个链表开始走(这里的方法三)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值