链表题目合集

23. 合并K个升序链表

给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
第一种方法:维护size=K的小根堆

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        Queue pq = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);
        for (ListNode node: lists) {
            if (node != null) {
                pq.offer(node);
            }
        }

        ListNode dummyHead = new ListNode(0);
        ListNode tail = dummyHead;
        while (!pq.isEmpty()) {
            ListNode minNode = pq.poll();
            tail.next = minNode;
            tail = minNode;
            if (minNode.next != null) {
                pq.offer(minNode.next);
            }
        }

        return dummyHead.next;
    }
}

第二种方法:归并排序,把每个链表当做待排序的元素

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
   public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) return null;
        return merge(lists, 0, lists.length - 1);
    }

    private ListNode merge(ListNode[] lists, int left, int right) {
        if (left == right) return lists[left];
        int mid = left + (right - left) / 2;
        ListNode l1 = merge(lists, left, mid);
        ListNode l2 = merge(lists, mid + 1, right);
        return mergeTwoLists(l1, l2);
    }

    private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1,l2.next);
            return l2;
        }
    }
}

148. 排序链表

截屏2021-12-12 下午6.49.52.png

归并+快慢指针

class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null)
            return head;
        ListNode fast = head.next, slow = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode tmp = slow.next;
        slow.next = null;
        ListNode left = sortList(head);
        ListNode right = sortList(tmp);
        ListNode h = new ListNode(0);
        ListNode res = h;
        while (left != null && right != null) {
            if (left.val < right.val) {
                h.next = left;
                left = left.next;
            } else {
                h.next = right;
                right = right.next;
            }
            h = h.next;
        }
        h.next = left != null ? left : right;
        return res.next;
    }
}

两个单链表是否相交

思路: 直接看两个链表的最后一个节点是否一致

static boolean isIntersect2(ListNode h1, ListNode h2){
        ListNode p1 = h1, p2 = h2;
        if(p1==null || h2==null) return false;
        ListNode last1 = p1;
        while(p1.next != null){
            last1 = p1;
            p1 = p1.next;
        }
        ListNode last2 = p2;
        while (p2.next != null){
            last1 = p2;
            p2 = p2.next;
        }
        if(last1==last2){
            return true;
        }else return false;

    }

两个单链表第一次相交的位置

思路:先让计算链表的长度,让最长的链表A先走 len(A)-len(B)步,然后两个链表一起走,第一个相交点,即为所求的点

static ListNode findFisrtCrossNode(ListNode h1, ListNode h2){
        int lenA = len(h1);
        int lenB = len(h2);
        ListNode p1 = h1, p2 = h2;
        ListNode tmp = null;
        if(lenA > lenB) tmp = p1;
        else tmp = p2;
        for(int i=0; i lenB) p1=tmp;
        else p2 = tmp;
        
        while(p1!=null && p2!=null){
            if(p1==p2) return p1;
            p1 = p1.next;
            p2 = p2.next;
        }
        return null;
    }
static int len(ListNode h){
        int clen = 0;
        ListNode p = h;
        while (p!=null){
            p = p.next;
            ++clen;
        }
        return clen;
    }

单链表是否有环

追逐法:
设置两个指针 fast, slow,将其初始化为链表的头结点;然后两个节点同时向前移动,fast一次移动2步,slow一次移动一步。如果存在环,fast指针和slow指针一定相遇。

static boolean hasCycle(ListNode h){
        ListNode fast=h, slow=h;

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

链表翻转

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* cur = NULL, *pre = head;
        while (pre != NULL) {
            ListNode* t = pre->next;
            pre->next = cur;
            cur = pre;
            pre = t;
        }
        return cur;
    }
};

# 两个链表生成相加链表

https://segmentfault.com/a/1190000040926678
假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。给定两个这种链表,请生成代表两个整数相加值的结果链表。
示例:
输入:[9,3,7],[6,3]
返回值:{1,0,0,0}
分析问题:
由于两个数字相加是从个位数开始,然后再十位数、百位数。对于的链表中,我们需要将两个链表进行右端对齐,然后从右往左进行计算。
要想让两个链表右端对齐,我们有两种实现方式。

  1. 将两个链表进行反转,然后直接求和。
  2. 借助栈这种先进后出的特性,来实现链表的右端对齐。
    我们先来看一下如何使用链表反转来实现。


    截屏2021-12-12 下午7.17.55.png
class Solution(object):
    def reverse(self, head):
        cur = head
        #初始化时,pre为None
        pre = None
        while cur:
            next=cur.next
            cur.next = pre
            pre = cur
            cur = next
        return pre
    def addTwoNumbers(self, l1, l2):
        #将两个链表翻转
        l1 = self.reverse(l1)
        l2 = self.reverse(l2)
        head=ListNode(0)
        pre=head
        #代表是否进位
        carray=0
        while l1 or l2:
           v1=l1.val if l1 else 0
           v2=l2.val if l2 else 0
           sum=v1+v2+carray
           #进位数
           carray=int(sum/10)
           tmp=sum%10
           node=ListNode(tmp)
           pre.next=node
           pre=pre.next
           if l1:
               l1=l1.next
           if l2:
               l2=l2.next
        if carray==1:
            node=ListNode(carray)
            pre.next=node
        
        return self.reverse(head.next)

下面我们来看一下如何使用栈来求解。我们首先将两个链表从头到尾放入两个栈中,然后每次同时出栈,就可以实现链表的右端对齐相加,我们来看一下代码如何实现。


截屏2021-12-12 下午7.17.41.png
def addTwoNumbers(l1, l2):
    #申请两个栈
    stack1=[]
    stack2=[]
    #l1入栈
    while l1:
        stack1.append(l1.val)
        l1 = l1.next
    while l2:
        stack2.append(l2.val)
        l2 = l2.next

    head = None
    carry = 0

    while stack1 and stack2:
        num = stack1.pop() + stack2.pop() + carry
        #求进位数
        carry=int(num/10)
        tmp=num%10
        node = ListNode(tmp)
        node.next = head
        head = node


    s = stack1 if stack1 else stack2
    while s:
        num = s.pop() + carry
        carry = int(num / 10)
        tmp = num % 10
        node = ListNode(tmp)
        node.next = head
        head = node

    if carry==1:
        node = ListNode(carry)
        node.next = head
        head = node
    return head

你可能感兴趣的:(链表题目合集)