【LeetCode-面试经典150题-day13】

目录

141.环形链表

2.两数相加

21.合并两个有序链表

138.复制带随机指针的链表

92.反转链表Ⅱ


141.环形链表

题意:

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。
【输入样例】

head=3,2,0,-4, pos=1

【输出样例】true
解题思路:哈希表

  1. 用哈希表存储所有已经访问果的节点;

2.每到一个节点时,如果该节点已经存在于哈希表中,则说明该链表是环形链表;

3.如果节点不在哈希表中则加入,重复这一过程,直到遍历完整个链表即可。

java 复制代码
public class Solution {
    public boolean hasCycle(ListNode head) {
        Set<ListNode> isSeen = new HashSet<ListNode>();
        while(head != null){
            if(!isSeen.add(head)){
                return true;
            }
            head = head.next;
        }
        return false;
    }
}

时间: 击败了21.65%

内存: 击败了98.04%

2.两数相加

题意:

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
【输入样例】

l1=1,2,4, l2=3,8,1

【输出样例】4,0,6
解题思路:遍历就完了

  1. 同时遍历两个链表,如果有一个链表已经遍历完毕了,则进行补0操作;

  2. 如果两数相加溢出,需要进位处理;

java 复制代码
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head = null,tail = null;
        int carry = 0;//进位值
        while(l1 != null || l2 != null){
            //只要一个还有值,就需要遍历
            int n1 = (l1 != null ? l1.val : 0);
            int n2 = (l2 != null ? l2.val : 0);
            int sum = n1+n2+carry;//进位几位也要加上
            if(head == null){
                //链表还未空,定义head
                head = tail = new ListNode(sum % 10);
            }else{
                tail.next = new ListNode(sum % 10);
                tail = tail.next;
            }
            carry = sum / 10;//计算下一步的进位
            if(l1 != null){
                l1 = l1.next;
            }
            if(l2 != null){
                l2 = l2.next;
            }
        }
        if(carry > 0){
            tail.next = new ListNode(carry);//最后剩下的进位要加上
        }
        return head;
    }
}

时间: 击败了100.00%

内存: 击败了67.03%

21.合并两个有序链表

题意:

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
【输入样例】

l1=1,2,4, l2=1,3,4

【输出样例】1,1,2,3,4,4
解题思路:遍历就完了

  1. 同时遍历两个链表,并进行判断;

  2. 当有一个链表遍历完毕时,将剩下链表直接填入;

java 复制代码
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode dummyHead = new ListNode(0);
        ListNode cur = dummyHead;
        while(list1 != null && list2 != null){
            if(list1.val <=list2.val){
                cur.next = list1;
                cur = cur.next;
                list1 = list1.next;
            }else{
                cur.next = list2;
                cur = cur.next;
                list2 = list2.next;
            }
        }
        if(list1 == null){
            cur.next = list2;
        }else{
            cur.next = list1;
        }

        return dummyHead.next;
    }
}

时间: 击败了100.00%

内存: 击败了31.92%

138.复制带随机指针的链表

题意:

给你一个长度为 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 作为传入参数。
【输入样例】\[7,null,13,0,11,4,10,2]

【输出样例】\[7,null,13,0,11,4,10,2]
解题思路:迭代+节点拆分

  1. 将原链表中每一个节点拆分为两个相连的节点,例如对于链表A->B->C,拆成A->A'->B->B'->C->C';其中,A'是A的拷贝节点;

  2. 找到A,B,C对应的随机指针指向的节点,在A'B'C'中进行模仿寻找,如A的随机指针指向C,A'的随机指针就指向C';

  3. 拆分ABC和A'B'C',注意最后一个拷贝节点的后继节点为空。

java 复制代码
/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/

class Solution {
    public Node copyRandomList(Node head) {
        if(head == null){
            return null;
        }
        for(Node node = head; node != null; node = node.next.next){
            Node nodeCpoy = new Node(node.val);//复制值
            nodeCpoy.next = node.next;//插入节点的操作
            node.next = nodeCpoy;
        }
        for(Node node = head; node != null; node = node.next.next){
            Node nodeCpoy = node.next;
            //复制随机指针指向
            //当前节点有随机指针,则赋值
            nodeCpoy.random = (node.random != null)? node.random.next:null;
        }
        Node headNew = head.next;
        for (Node node = head; node != null; node = node.next) {
            Node nodeNew = node.next;
            node.next = node.next.next;
            nodeNew.next = (nodeNew.next != null) ? nodeNew.next.next : null;
        }
        return headNew;
    }
}

时间: 击败了100.00%

内存: 击败了78.03%

92.反转链表Ⅱ

题意:

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
【输入样例】head=1,2,3,4,5, left=2, right=4

【输出样例】1,4,3,2,5
解题思路:一次遍历,头插法

在反转的区间里,每遍历到一个节点,让这个新节点来到反转部分的起始位置。

如样例所示:1->2->3->4->5

第一步:让3到2前面,得1->3>2>4>5

第二步:让4到3前面,得1->4>3>2>5

  1. 使用三个遍历pre,cur, next实现反转过程;cur变量指向待反转区域的第一个节点left

,next变量指向cur的下一个节点,pre指向待反转区域的第一个节点left的前一个节点;

  1. 先将cur的下一个节点记录为next,执行操作①:将cur的下一个节点指向next的下一个节点;②把next的下一个节点指向pre的下一个节点;③把pre的下一个节点指向next;

以样例为例,cur指向2,next指向3,pre指向1

①2->3->4 变成 2->4

②1->2->3 变成 3->2

③1->2->3 变成 1->3

联结①②③,链表变为1->3->2->4->5

  1. 重复,直到结束
java 复制代码
/**
 * 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 reverseBetween(ListNode head, int left, int right) {
        ListNode reverseNode = new ListNode(-1);
        reverseNode.next = head;//初始化为-1.因为left有可能就是head
        ListNode pre = reverseNode;
        for(int i = 0;i < left-1; i++){
            pre = pre.next;
        }
        ListNode cur = pre.next;
        ListNode next;
        for(int i=0; i< right - left; i++){
            next = cur.next;
            cur.next = next.next;
            next.next = pre.next;
            pre.next = next;
        }
        return reverseNode.next;
    }
}

时间: 击败了100.00%

内存: 击败了93.95%

相关推荐
倒头就睡的小比特4 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
晨米酱4 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
猎头南楼4 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光4 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark4 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her14 天前
并查集-听课笔记
笔记·算法·并查集
码流子4 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
彧azz4 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
another heaven4 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法