优选算法--链表

算法原理

链表常用的技巧和操作总结

常用技巧

1.画图,画图更加形象直观,便于我们理解

2.引入虚拟"头结点"(便于处理边界情况,方便对链表操作)

3.不要吝啬空间,大胆定义变量

比如在下图所示的情况,如果想将cur添加到prev后面,如果不定义变量的话会比较复杂,但如果我们定义一个变量指向prev.next,那么情况就变得简单了,我们就不需要考虑步骤的先后顺序

4.快慢双指针

定义快慢双指针,可以用来判断环,找链表中环入口,找倒数第n个结点(具体的题可以见链表的博客)

常用操作

1.创建一个新节点

2.头插法 在逆序链表中很好用

3.尾插法 定义一个tail

题目解析

1.两数相加

https://leetcode.cn/problems/add-two-numbers/description/

题目描述

给两个非空的链表,表示两个非空的整数,他们的每位数都是逆序存储的,并且每个节点只存一个数字,将两数相加,并以相同的形式返回和的链表

算法原理

解法:模拟两数相加的过程

比如:一个链表 2->4->3 一个链表是5->6->3

我们先定义一个newHead来指向头结点,这样便于返回

然后用变量t来标识进位

同时也要注意边界

代码实现

java 复制代码
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head=new ListNode();
        ListNode cur1=l1,cur2=l2;
        int t=0;
        ListNode cur=head;
        while(cur1!=null||cur2!=null||t!=0){
            if(cur1!=null){
                t+=cur1.val;
                cur1=cur1.next;
            }
            if(cur2!=null){
                t+=cur2.val;
                cur2=cur2.next;
            }
            cur.next=new ListNode(t%10);
            cur=cur.next;
            t/=10;
        }
        return head.next;
    }
}

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

https://leetcode.cn/problems/swap-nodes-in-pairs/description/

题目描述

给你一个链表,两两交换相邻的节点,并返回交换后的头节点(注意,只能交换节点,而不能只交换节点的值)

eg: 一个链表 1->2->3->4 交换后2->1->4->3

算法原理

解法一:递归

解法二:循环,迭代(模拟)

如果链表为空/链表只有一个节点,直接返回

代码实现

java 复制代码
class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head==null||head.next==null) return head;
        ListNode newHead=new ListNode();
        newHead.next=head;
        ListNode prev=newHead;
        ListNode cur=prev.next;
        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;
    }
}

3.重排链表

https://leetcode.cn/problems/reorder-list/description/

题目描述

给定一个链表的头结点head,单链表表示为L0->L1->...Ln,重排链表后,链表为L0->Ln->L1->Ln-1->...

(注意不能只是改变链表中的值,要进行节点交换)

算法原理

1.找到链表的中间节点(要用到快慢双指针)

2.把后面的部分逆序(双指针,头插)

3.合并两个链表(双指针)

代码实现

java 复制代码
class Solution {
    public void reorderList(ListNode head) {
        if(head==null||head.next==null||head.next.next==null) return;
        //1.找到链表的中间节点
        ListNode slow=head,fast=head;
        while(fast!=null&&fast.next!=null){
            slow=slow.next;
            fast=fast.next.next;
        }
        // 2.将slow后面的部分逆序(头插)
        ListNode nH=new ListNode(0);
        ListNode cur=slow.next;
        slow.next=null;
        while(cur!=null){
            ListNode next=cur.next;
            cur.next=nH.next;
            nH.next=cur;
            cur=next;
        }
        //3.合并两个链表
        ListNode cur1=head,cur2=nH.next;
        ListNode ret=new ListNode(0);
        ListNode prev=ret;
        while(cur1!=null){
           prev.next=cur1;
           prev=cur1;
           cur1=cur1.next;
           if(cur2!=null){
            prev.next=cur2;
            prev=cur2;
            cur2=cur2.next;
           }
        }
        return ;
    }
}

4.合并k个升序链表

https://leetcode.cn/problems/merge-k-sorted-lists/description/

题目描述

给一个链表数组,每个链表都按照升序排列,请将所有链表合并到一个升序链表中,返回合并后的链表

例如

算法原理

解法一:暴力解法(以合并两个有序链表为基,两两合并,再合并) 时间复杂度0(nK^2)

解法二:利用优先级队列做优化 将所有链表放入优先级队列(可以以ListNode作为泛型参数 ,自己提供比较方法,小跟堆) 然后定义一个头节点,不断从优先级队列出元素接在头结点后面

解法三:分治-递归

代码实现

java 复制代码
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        PriorityQueue<ListNode> heap=new PriorityQueue<>((v1,v2)-> v1.val-v2.val);
        for(ListNode head:lists){
            if(head!=null){
                heap.offer(head);
            }
        }
        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;
    }
}
java 复制代码
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];
        }
        //1.先平分数组
        int mid=(left+right)/2;
        //2.递归左右两边
        ListNode l1=merge(lists,left,mid);
        ListNode l2=merge(lists,mid+1,right);
        //3.合并两个有序链表
        return mergeTwo(l1,l2);
    }
    public ListNode mergeTwo(ListNode l1,ListNode l2){
        if(l1==null){
            return l2;
        }
        if(l2==null){
            return l1;
        }
        ListNode head=new ListNode(0);
        ListNode cur=head;
        ListNode cur1=l1,cur2=l2;
        while(cur1!=null&&cur2!=null){
            if(cur1.val<cur2.val){
                cur.next=cur1;
                cur=cur1;
                cur1=cur1.next;
            }else{
               cur.next=cur2;
               cur=cur2;
               cur2=cur2.next;
            }
        }
        if(cur1!=null){
            cur.next=cur1;
        }
        if(cur2!=null){
            cur.next=cur2;
        }
        return head.next;
    }
}

5.k个一组翻转链表

https://leetcode.cn/problems/reverse-nodes-in-k-group/description/

题目描述

给链表的头结点head,每k个结点一组进行翻转,请返回修改后的链表(注意,要进行节点的交换)

算法原理

解法:模拟

1.首先要求出要逆序多少组 :n(要先遍历一遍链表)

2.重复n次长度为k的链表的逆序即可(注意头插)

代码实现

java 复制代码
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        //1.先求出要逆序多少组
        ListNode cur=head;
        int n=0;
        while(cur!=null){
            cur=cur.next;
            n++;
        }
        n/=k;
        //2.重复n次
        ListNode nH=new ListNode(0);
        ListNode prev=nH;
        cur=head;
        for(int i=0;i<n;i++){
            ListNode tmp=cur;
            for(int j=0;j<k;j++){
                ListNode next=cur.next;
                cur.next=prev.next;
                prev.next=cur;
                cur=next;
            }
            prev=tmp;
        }
        prev.next=cur;
        return nH.next;
    }
}
相关推荐
csdn_aspnet1 天前
MATLAB 高效算法实战:数据分析与算法优化的效率秘诀
算法·matlab·数据分析
漫随流水1 天前
leetcode算法(637.二叉树的层平均值)
数据结构·算法·leetcode·二叉树
漫随流水1 天前
leetcode算法(102.二叉树的层序遍历)
数据结构·算法·leetcode·二叉树
源代码•宸1 天前
Leetcode—1339. 分裂二叉树的最大乘积【中等】
开发语言·后端·算法·leetcode·golang·dfs
leoufung1 天前
LeetCode动态规划经典题:Unique Paths 网格路径计数详解
算法·leetcode·动态规划
李泽辉_1 天前
深度学习算法学习(四):深度学习-最简单实现一个自行构造的找规律(机器学习)任务
深度学习·学习·算法
hz_zhangrl1 天前
CCF-GESP 等级考试 2025年12月认证C++六级真题解析
c++·算法·青少年编程·程序设计·gesp·c++六级·gesp2025年12月
小沈同学呀1 天前
基于时间片划分的提醒算法设计与实现
服务器·数据库·算法
千金裘换酒1 天前
LeetCode 两数之和 Java
java·算法·leetcode