Top101【10-16】

97 阅读3分钟

BM10 两个链表的第一个公共结点

题目

image.png

思路

  1. 求两个链表的长度
  2. 快指针走Math.abs(len1-len2)步
  3. 快慢指针一起走,直到相遇即可返回

代码

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    // 1. 先统计两个链表长度
    if (pHead1 == null || pHead2 == null) {
        return null;
    }

    ListNode cur1 = pHead1;
    int len1 = 0;
    while (cur1 != null) {
        cur1 = cur1.next;
        len1++;
    }

    ListNode cur2 = pHead2;
    int len2 = 0;
    while (cur2 != null) {
        cur2 = cur2.next;
        len2++;
    }

    // 快指针走差距步
    int len = Math.abs(len1 - len2);
    ListNode longNode = pHead1;
    ListNode shortNode = pHead2;
    if (len2 > len1) {
        longNode = pHead2;
        shortNode = pHead1;
    }

    while (len > 0) {
        longNode = longNode.next;
        len--;
    }

    // 一起走
    while (longNode != shortNode) {
        longNode = longNode.next;
        shortNode = shortNode.next;
    }

    return longNode;
}

BM11 链表相加(二)

题目

image.png

思路

  1. 先逆序两个链表
  2. 然后逐个相加,注意进位
  3. 将相加结果逆序

代码

public ListNode ReverseList2 (ListNode head) {
    if(head == null || head.next == null) {
        return head;
    }

    ListNode cur = head;
    ListNode pre = null;
    while (cur != null) {
        ListNode curNext = cur.next;
        cur.next = pre;
        pre = cur;
        cur = curNext;
    }

    return pre;
}

public ListNode addInList (ListNode head1, ListNode head2) {
    if(head1 == null) return head2;
    if(head2 == null) return head1;

    // 1. 逆序两个链表
    head1 = ReverseList2(head1);
    head2 = ReverseList2(head2);

    int next = 0;  // 负责进位的
    ListNode newHead = null;
    ListNode tail = null;

    while (head1 != null && head2 != null) {
        int val = head1.val + head2.val + next;
        if(val > 9) {
            next = 1;
            val %= 10;
        } else {
            next = 0;
        }

        if(newHead == null) {
            newHead = tail = new ListNode(val);
        } else {
            tail.next = new ListNode(val);
            tail = tail.next;
        }
        head1 = head1.next;
        head2 = head2.next;
    }

    while (head2 != null) {
        int val = head2.val + next;
        if(val > 9) {
            next = 1;
            val %= 10;
        } else {
            next = 0;
        }

        tail.next = new ListNode(val);
        tail = tail.next;
        head2 = head2.next;
    }

    while (head1 != null) {
        int val = head1.val + next;
        if(val > 9) {
            next = 1;
            val %= 10;
        } else {
            next = 0;
        }

        tail.next = new ListNode(val);
        tail = tail.next;
        head1 = head1.next;
    }

    if(next == 1) {
        tail.next = new ListNode(1);
        tail = tail.next;
    }
    tail.next = null;

    return newHead;
}

BM12 单链表的排序

题目

image.png

思路

归并排序:先拆解【快慢指针找中间节点,然后拆成两半】,再合并【之前文章写过合并两个有序链表】

注意代码中注释的部分

代码

public ListNode Merge (ListNode pHead1, ListNode pHead2) {
        ListNode dummyNode = new ListNode(-1);
        ListNode head = dummyNode;
        while (pHead1 != null && pHead2 != null) {
            if(pHead1.val > pHead2.val) {
                head.next = pHead2;
                pHead2 = pHead2.next;
            } else {
                head.next = pHead1;
                pHead1 = pHead1.next;
            }
            head = head.next;
        }

        head.next = pHead1 == null ? pHead2 : pHead1;

        return dummyNode.next;
    }

    public ListNode sortInList (ListNode head) {
        if(head == null || head.next == null) return head;

//        下面代码不行:如果是偶数个,找的是靠后面的节点,会造成死递归
//        ListNode slow = head;
//        ListNode fast = head;
//        while (fast != null && fast.next != null) {
//            fast = fast.next.next;
//            slow = slow.next;
//        }

        ListNode slow = head;
        ListNode fast = head.next;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }

        // slow 为中间节点
        // tmp 存储后半部分的头节点
        ListNode tmp = slow.next;
        slow.next = null;

        ListNode left = sortInList(head);
        ListNode right = sortInList(tmp);

        return Merge(left,right);
    }

BM13 判断一个链表是否为回文结构

题目

image.png

思路

  1. 逆序链表,然后判断两个链表是否各个节点都相同
  2. 找中间节点,然后逆序后半部分链表,最后头尾一起走,一直走到 null,则为相同,否则不同

代码

private ListNode getMidNode(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }

    ListNode slow = head;
    ListNode fast = head;
    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
    }

    return slow;
}

private ListNode reverse(ListNode mid) {
    if (mid == null || mid.next == null) {
        return mid;
    }

    ListNode newHead = reverse(mid.next);
    mid.next.next = mid;
    mid.next = null;

    return newHead;
}

public boolean isPail (ListNode head) {
    // 1. 先找中间节点
    ListNode mid = getMidNode(head);

    // 2. 逆序后半部分链表
    ListNode newHead = reverse(mid);
    // 3. 遍历判断
    while (newHead !=  null) {
        if(newHead.val != head.val) return false;

        newHead = newHead.next;
        head = head.next;

    }

    return true;
}

BM14 链表的奇偶重排

题目

image.png

思路

相当于分离出奇偶两个链表,然后进行连接即可

代码

public ListNode oddEvenList (ListNode head) {
    if(head == null || head.next == null || head.next.next == null) return head;

    // 奇数
    ListNode odd = head;
    // 偶数
    ListNode even = head.next;
    // 记录下偶数链表的头结点
    ListNode tmp = even;

    while (even != null && even.next != null) {
        odd.next = even.next;
        odd = odd.next;
        even.next = odd.next;
        even = even.next;
    }

    odd.next = tmp;
    return head;
}

BM15 删除有序链表中重复的元素-I

题目

image.png

思路

直接遍历链表删除即可,发现当前元素与下一个元素相等就走两步,不然就走一步

代码

public ListNode deleteDuplicates (ListNode head) {
    if(head == null || head.next == null) return head;

    ListNode cur = head;
    while (cur.next != null) {
        if(cur.val == cur.next.val) {
            cur.next = cur.next.next;
        } else {
            cur = cur.next;
        }
    }
    return head;
}

BM16 删除有序链表中重复的元素-II

题目

image.png

思路

需要一个虚拟头结点,pre指向虚拟头结点,然后cur用来遍历是否有重复元素,有重复元素就全部跳过,直到发现没有重复的 pre.next = cur;若进入循环发现cur 与 cur.next 不重复,则 pre 与 cur 一起往后走

代码

public ListNode deleteDuplicates (ListNode head) {
    if(head == null || head.next == null) return head;

    ListNode dummyNode = new ListNode(-1);
    dummyNode.next = head;
    ListNode pre = dummyNode;
    ListNode cur = head;

    while (cur != null && cur.next != null) {
        if(cur.val == cur.next.val) {
           int tmp = cur.val;
           while (cur != null && cur.val == tmp) {
               cur = cur.next;
           }
           pre.next = cur;
        } else {
            pre = pre.next;
            cur = cur.next;
        }
    }

    return dummyNode.next;
}