LeeCode刷题简记(五)

链表

Solution148排序链表、Solution86分隔链表、Solution23合并K个升序链表、Solution160相交链表、Solution234回文链表、Solution328奇偶链表、Solution237删除链表中的特定元素、Solution24两两交换链表中的节点、Solution61旋转链表、Solution138复制带随机指针的链表、Solution24两两交换链表中的节点、

Solution148排序链表

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

使用归并排序 

class Solution {
    public ListNode sortList(ListNode head) {
        return mergeSort(head);
    }

    // 归并排序
    private ListNode mergeSort(ListNode head){
        // 如果没有结点/只有一个结点,无需排序,直接返回
        if (head==null||head.next==null) return head;
        // 快慢指针找出中位点
        ListNode slowp=head,fastp=head.next.next,l,r;
        while (fastp!=null&&fastp.next!=null){
            slowp=slowp.next;
            fastp=fastp.next.next;
        }
        // 对右半部分进行归并排序
        r=mergeSort(slowp.next);
        // 链表判断结束的标志:末尾节点.next==null
        slowp.next=null;
        // 对左半部分进行归并排序
        l=mergeSort(head);
        return mergeList(l,r);
    }
    // 合并链表
    private ListNode mergeList(ListNode l,ListNode r){
        // 临时头节点
        ListNode tmpHead=new ListNode(-1);
        ListNode p=tmpHead;
        while (l!=null&&r!=null){
            if (l.val<r.val){
                p.next=l;
                l=l.next;
            }else {
                p.next=r;
                r=r.next;
            }
            p=p.next;
        }
        p.next=l==null?r:l;
        return tmpHead.next;
    }
}

Solution86分隔链表

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

 虚拟头结点,pq各自带领一片分区,最后连接起来

public class S86分隔链表 {
    public ListNode partition(ListNode head, int x) {
        ListNode dummyHead1 = new ListNode(0);
        ListNode dummyHead2 = new ListNode(0);
        ListNode p = dummyHead1;
        ListNode q = dummyHead2;
        while (head != null) {
            if (head.val < x) {
                p.next = head;
                head = head.next;
                p = p.next;
                p.next = null;
            } else {
                q.next = head;
                head = head.next;
                q = q.next;
                q.next = null;
            }
        }
        p.next = dummyHead2.next;
        return dummyHead1.next;
    }
}

Solution24两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

  1. 找终止条件:本题终止条件很明显,当递归到链表为空或者链表只剩一个元素的时候,没得交换了,自然就终止了。
  2. 找返回值:返回给上一层递归的值应该是已经交换完成后的子链表。
  3. 单次的过程:因为递归是重复做一样的事情,所以从宏观上考虑,只用考虑某一步是怎么完成的。我们假设待交换的俩节点分别为head和next,next的应该接受上一级返回的子链表(参考第2步)。就相当于是一个含三个节点的链表交换前两个节点
public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        // 获取当前节点的下一个节点
        ListNode next = head.next;
        head.next = swapPairs(next.next);
        next.next = head;
        return next;
    }

Solution138复制带随机指针的链表

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。

在这里可以用hashmap映射,也可以在原表上复制一个兄弟表出来,组合在拆开

public class S复杂链表的复制 {
    public static Node copyListWithRand(Node head) {
        if (head == null) {
            return null;
        }
        Node cur = head;
        Node next = null;
        //建兄弟节点 1 -> 1' -> 2
        while (cur != null) {
            next = cur.next;
            cur.next = new Node(cur.val);
            cur.next.next = next;
            cur = next;
        }
        cur = head;
        Node curCopy = null;
        //连接随机节点
        while (cur != null) {
            next = cur.next.next;
            curCopy = cur.next;
            curCopy.random = cur.random != null ? cur.random.next : null;
            cur = next;
        }
        Node res = head.next;
        cur = head;
        //切断
        while (cur != null) {
            next = cur.next.next;
            curCopy = cur.next;
            cur.next = next;
            curCopy.next = next != null ? next.next : null;
            cur = next;
        }
        return res;
    }
}

Solution23.合并K个升序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

 直接合并再排序

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0){
            return null;
        }
        ArrayList<Integer> nums = new ArrayList<>();
        for (ListNode head : lists) {
            ListNode p = head;
            while (p != null) {
                nums.add(p.val);
                p = p.next;
            }
        }
        Collections.sort(nums);
        ListNode head = new ListNode(-1);
        ListNode p = head;
        for (Integer num : nums) {
            ListNode node = new ListNode(num);
            p.next = node;
            p = p.next;
        }
        return head.next;
    }
}

Solution160相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交:

public class S160相交链表 {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null ){
            return null;
        }
        ListNode p1 = headA;
        ListNode p2 = headB;
        while (p1 != p2){
            p1 = p1 == null ? headB : p1.next;//如果p1是空就从b开始走,不是空就下一个
            p2 = p2 == null ? headA : p2.next;
        }
        return p1;
    }
}

Solution234回文链表

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

快慢指针把链表分成相等两部分,互相遍历找相等,注意fast指向什么表明链表长度奇偶。

public class S234回文链表 {
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null){
            return true;
        }
        ListNode slow = head,fast = head;
        ListNode p = null,pre = null;
        while (fast != null && fast.next != null){
            p = slow;
            slow = slow.next;
            fast = fast.next.next;
            p.next = pre;
            pre = p;
        }
        if (fast != null){
            slow = slow.next;
            //如果fast不指向空代表是奇数个数,让slow指向头结点的下一条;
        }
        //一一对应判断只要有不一样的就错
        while (p != null && slow != null){
            if (p.val != slow.val){
                return false;
            }
            p = p.next;
            slow = slow.next;
        }
        return true;
    }
}

Solution328奇偶链表

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

 就是改变链表顺序再把两个连起来。

public class S328奇偶链表 {
    public ListNode oddEvenList(ListNode head) {
        if (head == null || head.next == null){
            return head;
        }
        ListNode ji = head;
        ListNode ou = head.next;
        ListNode ouhead = ou;
        while (ou != null && ou.next != null){
            ji.next = ji.next.next;
            ou.next = ou.next.next;
            ji = ji.next;
            ou = ou.next;
        }
        ji.next = ouhead;
        return head;
    }
}

Solution237删除链表中的特定元素

请编写一个函数,用于 删除单链表中某个特定节点 。在设计函数时需要注意,你无法访问链表的头节点 head ,只能直接访问 要被删除的节点 。

题目数据保证需要删除的节点 不是末尾节点 。

题目给的node就是要删除的节点,链表中删除节点只需要断掉它跟前后的联系,找到人替换自己,再把那个人干掉

class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val;    //变成下个倒霉蛋
        node.next = node.next.next;  //把倒霉蛋干掉。
    }
}

Solution24两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

迭代法

Solution61旋转链表

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if (head == null || head.next == null || k == 0 ){
            return head;
        }
        int count = 1;//统计总个数
        ListNode temp = head;
        while (temp.next != null) {
            count++;
            temp = temp.next;
        }
        k %= count;
        //排除k为0时,然后连接首尾,找到k点续到头部
        temp.next = head;
        for (int i = 0 ;i < count - k ; i++) {
            temp = temp.next;
        }
        ListNode newHead = temp.next;
        temp.next = null;
        return newHead;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值