算法系列--链表刷题(二)(上)

简介: 算法系列--链表刷题(二)

💕"轻舟已过万重山"💕

作者:Mylvzi

文章主要内容:算法系列–链表刷题(二)

今天为大家带来的是算法系列--链表刷题(二),带来了几道经典的有关链表的面试题(合并K个有序列表)

1.两数相加

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

模拟两数相加:

使用两个指针cur1和cur2来遍历两个链表,通过t记录每次相加的结果,最后创建出新的节点,尾插

注意:

  1. 每次相加时都需要更新t的值,但是不可以直接将t设置为0,因为存在进位的可能,比如t = 9 + 9 = 18,要插入节点的val = 8,还要记录进位1,所以:val = t % 10, t /= 10
  2. 循环的结束要同时满足三个条件,cur1 = null, cur2 = null, t = 0,其中最后t = 0这种情况最容易忘记,导致最后需要进位没进位成,结果相比于正确答案少了一位
    代码:
/**
 * 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 cur1 = l1;
        ListNode cur2 = l2;
        ListNode phead = new ListNode(0);
        ListNode cur = phead;// 用于尾插
        int t = 0;// 用于表示本次相加的结果  处理进位
        // 要注意t最后可能不为0 要进一位
        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;
            }
            ListNode newNode = new ListNode(t % 10);
            t /= 10;
            // 尾插
            cur.next = newNode;
            cur = newNode;
        }
        return phead.next;
    }
}

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

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

思路:

  1. 分别得到下标为奇数的所有节点的组合和下标为偶数的所有节点的组合(下标从1开始)
  2. 按照偶数节点在前,奇数节点在后的顺序合并两个链表
  3. 得到新的链表

代码实现:

/**
 * 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 p1 = new ListNode(0);
        ListNode p2 = new ListNode(0);
        ListNode cur1 = p1;
        ListNode cur2 = p2;
        ListNode cur = head;
        int i = 1;
        // 分别得到奇数和偶数的链表组合
        while(cur != null) {
            ListNode newNode = new ListNode(cur.val);
            if(i % 2 != 0) {
                // 奇数
                cur1.next = newNode;
                cur1 = newNode;
            }else {
                // 偶数
                cur2.next = newNode;
                cur2 = newNode;
            }
            cur = cur.next;
            i++;
        }
        // 合并两个链表
        ListNode p3 = new ListNode(0);
        ListNode t1 = p1.next;
        ListNode t2 = p2.next;
        ListNode cur3 = p3;
        while(t1 != null || t2 != null) {
            if(t2 != null) {
                cur3.next =  t2;
                cur3 = t2;
                t2 = t2.next;
            }
            if(t1 != null) {
                cur3.next =  t1;
                cur3 = t1;
                t1 = t1.next;
            }
        }
        return p3.next;
    }
}

注:本题更加简洁的写法是通过递归实现的,感兴趣的可以去我的算法系列里查看

3.重排链表

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

思路:

  1. 首先获得中间节点,以中间节点为基准,分为两个不同的链表l1和l2
  2. 逆序l2
  3. 合并两个链表

代码:

/**
 * 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) {
        ListNode slow = head, fast = head;
        // 找到中间节点
        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode l1 = head;
        ListNode l2 = slow.next;
        slow.next = null;
        // 逆序第二个节点
        l2 = reverseList(l2);
        ListNode phead = new ListNode(0);
        ListNode cur = phead;
        // 合并两个链表
        while(l1 != null || l2 != null) {
            if(l1 != null) {
                cur.next = l1;
                cur = l1;
                l1 = l1.next;
            }
            if(l2 != null) {
                cur.next = l2;
                cur = l2;
                l2 = l2.next;
            }
        }
        head = phead.next;
    }
    public ListNode reverseList(ListNode head) {
        if(head == null) return null;
        if(head.next == null) return head;
        ListNode pHead = new ListNode(0);
        ListNode cur = head;
        while(cur != null) {
            ListNode curNext = cur.next;
            
            cur.next = pHead.next;
            pHead.next = cur;
            cur = curNext;
        }
        return pHead.next;
    }
}

同样的本题也有更加简洁的递归写法

算法系列--链表刷题(二)(下)https://developer.aliyun.com/article/1480813?spm=a2c6h.13148508.setting.24.361f4f0eyTL4lb


目录
相关文章
|
1月前
|
算法
【优选算法专栏】专题九:链表--------两两交换链表中的节点
【优选算法专栏】专题九:链表--------两两交换链表中的节点
17 0
|
1月前
|
算法
算法系列--递归(一)--与链表有关(上)
算法系列--递归(一)--与链表有关
28 0
|
3天前
|
存储 算法 Java
数据结构与算法 数组和链表
数据结构与算法 数组和链表
9 0
|
25天前
|
存储 算法
双链表——“数据结构与算法”
双链表——“数据结构与算法”
|
1月前
|
算法
算法系列--链表刷题(二)(下)
算法系列--链表刷题(二)(下)
17 0
|
1月前
|
算法
算法系列--递归(一)--与链表有关(下)
算法系列--递归(一)--与链表有关(下)
21 0
|
1月前
|
存储 算法
【优选算法专栏】专题九:链表--------两数之和
【优选算法专栏】专题九:链表--------两数之和
15 0
|
2天前
|
算法 数据安全/隐私保护 计算机视觉
基于二维CS-SCHT变换和LABS方法的水印嵌入和提取算法matlab仿真
该内容包括一个算法的运行展示和详细步骤,使用了MATLAB2022a。算法涉及水印嵌入和提取,利用LAB色彩空间可能用于隐藏水印。水印通过二维CS-SCHT变换、低频系数处理和特定解码策略来提取。代码段展示了水印置乱、图像处理(如噪声、旋转、剪切等攻击)以及水印的逆置乱和提取过程。最后,计算并保存了比特率,用于评估水印的稳健性。
|
3天前
|
存储 算法 数据可视化
基于harris角点和RANSAC算法的图像拼接matlab仿真
本文介绍了使用MATLAB2022a进行图像拼接的流程,涉及Harris角点检测和RANSAC算法。Harris角点检测寻找图像中局部曲率变化显著的点,RANSAC则用于排除噪声和异常点,找到最佳匹配。核心程序包括自定义的Harris角点计算函数,RANSAC参数设置,以及匹配点的可视化和仿射变换矩阵计算,最终生成全景图像。
|
3天前
|
算法 Serverless
m基于遗传优化的LDPC码NMS译码算法最优归一化参数计算和误码率matlab仿真
MATLAB 2022a仿真实现了遗传优化的归一化最小和(NMS)译码算法,应用于低密度奇偶校验(LDPC)码。结果显示了遗传优化的迭代过程和误码率对比。遗传算法通过选择、交叉和变异操作寻找最佳归一化因子,以提升NMS译码性能。核心程序包括迭代优化、目标函数计算及性能绘图。最终,展示了SNR与误码率的关系,并保存了关键数据。
12 1