面试算法TOP101——多链表操作

152 阅读3分钟

0.两个链表的第一个公共节点

描述

输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

数据范围: n ≤ 1000 要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)\

例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:

可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。

输入描述

输入分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。 后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。

返回值描述

返回传入的pHead1和pHead2的第一个公共结点,后台会打印以该节点为头节点的链表。

示例1

输入:{1,2,3},{4,5},{6,7}
返回值:{6,7}
说明:第一个参数{1,2,3}代表是第一个链表非公共部分,第二个参数{4,5}代表是第二个链表非公共部分,最后的{6,7}表示的是2个链表的公共部分
这3个参数最后在后台会组装成为2个两个无环的单链表,且是有公共节点的          

示例2

输入:{1},{2,3},{}
返回值:{}
说明:2个链表没有公共节点 ,返回null,后台打印{}   

解题思路1

双指针法,使用两个指针,依次遍历链表,当任一个指针走到链表末尾时,将该指针移动到另一个链表头节点位置继续移动,直到两个指针相遇,相遇节点即为公共链表起始节点。
设head1长度为n,head2长度为m,n < m,所以head1先遍历完,此时head2要遍历完得比head1多走m-n步,刚好相当于head1和head2在距离公共节点起始位置相同距离处移动,所以当两个指针相等时,当前位置即为公共链表起始节点。
可以把链表末尾节点指向null的当做公共节点,所以当两个链表没有公共节点时,返回null。

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    ListNode cur1 = pHead1;
    ListNode cur2 = pHead2;

    while (cur1 != cur2) {
        cur1 = cur1 == null ? pHead2 : cur1.next;
        cur2 = cur2 == null ? pHead1 : cur2.next;
    }

    return cur1;
}

时间复杂度O(N+M)
空间复杂度O(1)

解题思路2

使用一个集合来存储其中一个链表遍历的节点,然后遍历另一个链表,当另一个链表遍历的节点在集合中存在时,即为第一个公共节点。

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    ListNode cur1 = pHead1;
    ListNode cur2 = pHead2;

    Stack<ListNode> stack = new Stack<>();

    while (cur1 != null) {
        stack.push(cur1);
        cur1 = cur1.next;
    }

    while (cur2 != null) {
        if (stack.contains(cur2)) {
            return cur2;
        }
        cur2 = cur2.next;
    }

    return cur2;
}

时间复杂度O(N+M)
空间复杂度O(N+M)

解题思路3

先得到两个链表的长度,然后先让长链表先移动两个链表长度差,使得两个链表从距离第一个公共节点相同位置出同时移动,直到两个指针相等。

public int getListLength(ListNode head) {
    int len = 0;
    ListNode p = head;

    while (p != null) {
        p = p.next;
        len++;
    }

    return len;
}
    
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    int len1 = getListLength(pHead1);
    int len2 = getListLength(pHead2);

    ListNode p1 = pHead1;
    ListNode p2 = pHead2;

    if (len1 < len2) {
        for (int i = 0; i < len2-len1; i++) {
            p2 = p2.next;
        }

        while (p1 != p2) {
            p1 = p1.next;
            p2 = p2.next;
        }
    } else {
        for (int i = 0; i < len1-len2; i++) {
            p1 = p1.next;
        }

        while (p1 != p2) {
            p1 = p1.next;
            p2 = p2.next;
        }
    }

    return p1;
}

时间复杂度O(N+M)
空间复杂度O(1)

1.链表相加

描述

假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。

给定两个这种链表,请生成代表两个整数相加值的结果链表。

数据范围:0 ≤ n,m ≤ 1000000,链表任意值 0 ≤ val ≤ 9
要求:空间复杂度 O(n),时间复杂度 O(n)

例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。

示例1

输入:
[9,3,7],[6,3]
返回值:{1,0,0,0}

示例2

输入:\[0],\[6,3]
返回值:{6,3}
## 备注:
1 ≤ n,m ≤ 106
0 ≤ ai,bi ≤ 9

解题思路

先获取两个链表的长度,将longList指针指向长链表,shortList指针指向短链表,根据两个链表的长度差,先将长链表移动到和短链表一样长度的节点位置处,然后使用递归依次按位相加,第i个节点的值为长链表节点value加短链表节点value再加下一步的节点值,值保存在长链表节点处,如果当前节点值大于或等于10,则返回1,同时值减去10,否则返回0,处理完两个链表加法部分后,还要处理结果链长表的进位,对长链表依次进行和加法递归相同的操作,直到到达两个链表加法处理结果的第一个节点处为止。

public int getListLength(ListNode head) {
    int len = 0;
    ListNode p = head;

    while (p != null) {
        p = p.next;
        len++;
    }

    return len;
}

public int listAdd(ListNode head1, ListNode head2) {
    if (head1 == null || head2 == null) {
        return 0;
    }
    head1.val = head1.val + head2.val + listAdd(head1.next, head2.next);
    if (head1.val >= 10) {
        head1.val = head1.val - 10;
        return 1;
    }
    return 0;
}

public int singleListAdd(ListNode head, int k) {
    if (k < 0 || head == null) {
        return 0;
    }
    head.val = head.val + singleListAdd(head.next, k--);
    if (head.val >= 10) {
        head.val = head.val - 10;
        return 1;
    }
    return 0;
}

public ListNode addInList (ListNode head1, ListNode head2) {
    int len1 = getListLength(head1);
    int len2 = getListLength(head2);

    ListNode longList = len1 >= len2 ? head1 : head2;
    ListNode shortList = len1 < len2 ? head1 : head2;

    ListNode res = new ListNode(0);
    res.next = len1 >= len2 ? head1 : head2;

    int n = len1 > len2 ? len1-len2 : len2-len1;

    ListNode pre = res;

    for (int i = 0; i < n; i++) {
        pre = pre.next;
        longList = longList.next;
    }
    pre.val += listAdd(longList, shortList);
    singleListAdd(res, n);

    return res.val == 0 ? res.next : res;
}

时间复杂度O(N+M)
空间复杂度O(1)