优选算法--链表

算法原理

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

常用技巧

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;
    }
}
相关推荐
无极低码34 分钟前
ecGlypher新手安装分步指南(标准化流程)
人工智能·算法·自然语言处理·大模型·rag
软件算法开发1 小时前
基于海象优化算法的LSTM网络模型(WOA-LSTM)的一维时间序列预测matlab仿真
算法·matlab·lstm·一维时间序列预测·woa-lstm·海象优化
罗超驿1 小时前
独立实现双向链表_LinkedList
java·数据结构·链表·linkedlist
superior tigre2 小时前
22 括号生成
算法·深度优先
努力也学不会java3 小时前
【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU
java·数据结构·人工智能·算法·缓存·面试
旖-旎3 小时前
二分查找(x的平方根)(4)
c++·算法·二分查找·力扣·双指针
ECT-OS-JiuHuaShan3 小时前
朱梁万有递归元定理,重构《易经》
算法·重构
智者知已应修善业4 小时前
【51单片机独立按键控制数码管移动反向,2片74CH573/74CH273段和位,按键按下保持原状态】2023-3-25
经验分享·笔记·单片机·嵌入式硬件·算法·51单片机
khddvbe4 小时前
C++并发编程中的死锁避免
开发语言·c++·算法
C羊驼4 小时前
C语言:两天打鱼,三天晒网
c语言·经验分享·笔记·算法·青少年编程