【Java 优选算法】链表

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗~

如有错误,欢迎指出~



尽量多new节点

2. 两数相加

解法

模拟两数相加即可,利用尾插法, 用 t 代表进位

cur.next = new ListNode(t % 10);

cur = cur.next

t /= 10

代码

复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head = new ListNode(0);
        ListNode prev = head;
        int t = 0;
        while(l1 != null || l2 != null || t != 0 ){
            //加上第一个链表
            if(l1 != null){
                t += l1.val;
                l1 = l1.next;
            }
            //加上第二个链表
            if(l2 != null){
                t += l2.val;
                l2 = l2.next;
            }
            prev.next = new ListNode(t % 10);
            prev = prev.next;
            t /= 10;
        }
        return head.next;
    }
}

24. 两两交换链表中的节点

完成这题只能通过修改指针,不能直接修改值

解法

循环, 迭代(模拟),根据画图模拟过程

处理特殊情况,head==null或者head.next==null时(空链表 或者只有一个节点), 直接返回, 除此之外表示链表至少有两个节点cur和next

定义 头节点newhead= prev ,建立连接prev.next = head,

定义cur = head, next = cur.next, nnext = next;

代码

复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null) return head;
        ListNode newhead = new ListNode(0);
        newhead.next = head;
        ListNode prev = newhead;
        ListNode cur = head;
        ListNode next = cur.next;
        ListNode nnext = next.next;
        while(cur != null && next != null){
            //交换节点
            prev.next = next;
            next.next = cur;
            cur.next = nnext;
            //修改指针
            prev = cur;//注意顺序
            cur = nnext;
            if(cur != null) next = cur.next;//对于偶数情况
            if(next != null) nnext= next.next;//对于奇数
        }
        return newhead.next;
    }
}

143. 重排链表

解法

  1. 找到链表的中间节点: 快慢双指针
  2. 把后面的部分逆序: 头插法
  3. 合并两个链表

这里两种方法都可以使用,但是推荐使用方法1 (方法1可以使两个链表完全独立)

代码

复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public void reorderList(ListNode head) {
        //空链表 || 一个节点 || 两个节点 直接返回
        if(head == null || head.next == null || head.next.next == null) return;
        //找到中间节点
        ListNode slow = head, fast = head;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode head2 = new ListNode(0);
        ListNode cur = slow.next;
        slow.next = null;//把两个链表分离

        //后半部分逆序(将slow后面的节点都逆序)
        while(cur != null){
            ListNode next = cur.next;
            cur.next = head2.next;
            head2.next = cur;
            cur = next;
        }
        //合并两个链表
        ListNode cur1 = head;
        ListNode cur2 = head2.next;


        while(cur1 != null && cur2 != null){//链表1更长

        //合并链表
        ListNode next1 = cur1.next;
        ListNode next2 = cur2.next;

        cur1.next = cur2;
        cur2.next = next1;

        cur1 = next1;
        cur2 = next2;      
        }
    }
}

23. 合并 K 个升序链表

解法

解法1: 暴力解法,每次将第二个链表合并到第一个上面,O(n* k^2)

解法二: 利用优先级队列做优化O(n* k* logk): 创建一个小根堆,将每个链表(题目给的链表都是升序的)的第一个节点放到小根堆里,取出堆顶元素对应的链表,cur节点右移

解法三: 分治-递归O(n* k* logk)

代码

解法二

复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        //创建一个小根堆
        PriorityQueue<ListNode> heap = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);

        //2.把所有头节点放到小根堆里
        for(ListNode head : lists){
            if(head != null){
                heap.offer(head);
            }
        }
        //3.合并链表
        ListNode ret = new ListNode(0);
        ListNode prev = ret;
        while(!heap.isEmpty()){
            ListNode t = heap.poll();
            prev.next = t;
            prev = t;
            if(t.next != null) heap.offer(t.next);
        }
        return ret.next;
    }
}

解法二

复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        return merge(lists, 0, lists.length - 1);
    }

    public ListNode merge(ListNode[] lists, int left, int right) {
        if (left > right) {
            return null;
        }
        if (left == right) {
            return lists[left];
        }
        int mid = (left + right) / 2;
        ListNode l1 = merge(lists, left, mid);
        ListNode l2 = merge(lists, mid + 1, right);
        return mergeTwoList(l1, l2);
    }

    public ListNode mergeTwoList(ListNode l1, ListNode l2) {
        if (l1 == null) {
            return l2;
        }
        if (l2 == null) {
            return l1;
        }
        if (l1.val < l2.val) {
            l1.next = mergeTwoList(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoList(l1, l2.next);
            return l2;
        }
    }
//代码超时了
public ListNode mergeTwoList(ListNode l1, ListNode l2){
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        //合并两个有序链表
        ListNode head = new ListNode(0);
        ListNode cur1 = l1, cur2 = l2, prev = head;
        while(cur1 != null && cur2 != null){
            if(cur1.val < cur2.val){
                prev.next = cur1;
                prev = cur1;
                cur1 = cur1.next;
            }else {
                prev.next = cur2;
                prev = cur2;
                cur2 = cur2.next;
            }
        }
        while(cur1 != null) prev.next = cur1;
        while(cur2 != null) prev.next = cur2;
        return head.next;
    }
}

在分治法的基础上,可以进一步优化合并过程,减少不必要的遍历。例如,在 mergeTwoList 方法中,可以使用递归的方式来合并两个链表,这样可以使代码更加简洁,并且避免一些重复的操作。

25. K 个一组翻转链表

解法

每次用tmp标记要头插的第一个节点,头插k个节点后让prev = tmp,即下一次要头插的位置

代码

复制代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head == null) return head;
        //先求出需要逆序多少组
        ListNode cur = head;
        int n = 0;
        while(cur != null){
            n++;
            cur = cur.next;
        }
        n /= k;
        //重复n次: 长度为k的链表的逆序
        ListNode newHead = new ListNode(0);
        ListNode prev = newHead;
        cur = head;
        for(int i = 0; i < n; i++){
            //每次逆序之前记录第一个节点tmp
            ListNode tmp = cur;
            for(int j = 0; j < k; j++){
                //头插逻辑
                ListNode next = cur.next;
                cur.next = prev.next;
                prev.next = cur;
                cur = next;
            }
            //头插完一轮后,更新prev
            prev = tmp;
        }
        //把后面不需要逆序部分连接上
        prev.next= cur;
        return newHead.next;
    }
}
相关推荐
大小胖虎2 小时前
数据结构——第六章:图
数据结构·笔记··最小生成树·拓扑排序·最短路径
_GR6 小时前
2021年蓝桥杯第十二届C&C++大学B组真题及代码
c语言·数据结构·c++·算法·蓝桥杯
lwewan7 小时前
26考研——图_图的基本概念(6)
数据结构·考研
1haooo9 小时前
API-Arrays
java·数据结构·算法
无职转生真好看10 小时前
vector和list区别
数据结构·c++·list
deming_su12 小时前
第七课:Python基础排序算法与比较排序原理深度解析
数据结构·算法·排序算法
Phoebe鑫12 小时前
数据结构每日一题day1
数据结构
green5+112 小时前
LeetCode206反转链表
数据结构·链表
格格Code12 小时前
数据结构——链式队列
数据结构
刃神太酷啦13 小时前
基础算法篇(2)(蓝桥杯常考点)
数据结构·c++·算法·蓝桥杯·深度优先·蓝桥杯c++组