[Leetcode刷题]——链表
一、找出两个链表的交点
160.相交链表(easy)2021-01-05
编写一个程序,找到两个单链表相交的起始节点
如下面的两个链表,在c1 处相交:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode l1 = headA;
ListNode l2 = headB;
while(l1 != l2){
l1 = (l1 == null) ? headB : l1.next;
l2 = (l2 == null) ? headA : l2.next;
}
return l1;
}
}
解法:如果两个链表有相交,设第一个链表长度为 a+c, 第二个链表长度为b+c。
让两个链表指针从头开始遍历,第一个链表遍历a+c后接着从头开始遍历第二个链表的b,第二个链表遍历b+c后从头开始遍历第二个链表的a。
最后两个指针会同时到达相交的地方。
注意,条件判断时判断的是(l1 == null)而不是 (l1.next == null) 。其目的是为了如果两个链表没有相交,那么在遍历两个链表后连个指针均指向了链表最后的null,而非陷入死循环。
此解法的复杂度为O(n)。
二、反转链表
206.反转链表(easy)2021-01-06
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
我的原始解法,错误示范:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode newHead = head;
newHead.next = null;
ListNode traverseNode = head;
while(traverseNode.next != null){
traverseNode = traverseNode.next;
ListNode temp = traverseNode;
temp.next = newHead;
newHead = temp;
}
return newHead;
}
}


错误分析:上述代码理论推导似乎可行,但是编译器运行不通过。
debug后发现,第2-5行,将head结点赋值给newhead结点,然后将newhead结点的next指针改为null,发现原始的head结点的next指针自动也变成了null。
在idea中可以看到,虽然head的值赋值给newHead 和traverseNode, 但是并没有开辟新空间,所以这里不能当一般变量处理。
标准解法:
1.递归,yyds
public static ListNode reverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode next = head.next;
ListNode newHead = reverseList(next);
next.next = head;
head.next = null;
return newHead;
}
2.头插法
public ListNode reverseList(ListNode head) {
ListNode newHead = new ListNode(-1);
while (head != null) {
ListNode next = head.next;
head.next = newHead.next;
newHead.next = head;
head = next;
}
return newHead.next;
}
三、合并两个有序链表
21、合并两个有序链表(easy) 2021-01-07
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
我的代码:
常规思路,需要注意的是在进行循环后的第二个if 语句时,又重新判断了( l1 != null )。 如果不加判断条件有可能为null就直接写l1.val会产生NullPointerException异常。
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode newHead = new ListNode(-1);
ListNode temp = newHead;
while(l1 != null && l2 != null){
if(l1.val < l2.val){
temp.next = l1;
temp = l1;
l1 = l1.next;
}
if(l1 != null && l2.val <= l1.val){
temp.next = l2;
temp = l2;
l2 = l2.next;
}
}
if(l1 == null){
temp.next = l2;
}
if(l2 == null){
temp.next = l1;
}
return newHead.next;
}
}
递归的写法,真简洁:
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
四、从有序链表中删除重复结点
83、删除排序链表中的重复元素 (easy) 2021-01-08
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:输入: 1->1->2->3->3
输出: 1->2->3
我的解法:需要注意的一点是在没有判断结点是否为空的情况下之直接就使用.val 调用结点的数值会报NullPointerException异常
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode tempNode = head;
while(tempNode != null){
if(tempNode.next != null && tempNode.val == tempNode.next.val){
tempNode.next = tempNode.next.next;
}else{
tempNode = tempNode.next;
}
}
return head;
}
}
递归的解法,妙呀,三行就搞定!唯一不足的就是内存消耗较多。
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null || head.next == null) return head;
head.next = deleteDuplicates(head.next);
return head.val == head.next.val ? head.next : head;
}
}
五、删除链表的倒数第N个结点
19、给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。(medium) 2021-01-09
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
我的解法,遍历两次,内存击败29.8%,还是太菜
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode tempNode = head;
int len = 1;
while(tempNode.next != null){
len++;
tempNode = tempNode.next;
}
tempNode = head;
if(n == len){
return head.next;
}else{
while(tempNode != null && tempNode.next != null){
if(len == n + 1){
tempNode.next = tempNode.next.next;
}
len--;
tempNode = tempNode.next;
}
return head;
} }
}遍历一次的原理,设置两个指针,让一个指针先走n长度,然后两个指针一起走,当快的指针走到链表结尾时,慢的指针就在倒数第n个位置
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode fast = head;
while (n-- > 0) {
fast = fast.next;
}
if (fast == null) return head.next;
ListNode slow = head;
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return head;
}
}
六、两两交换链表中的相邻结点
24、给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。(medium) 2021-01-10
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
解法:力扣里的链表的头节点都是第一个结点,在这个题中,设置第一个结点的前一个结点为头结点,在判断后两个结点是否为空,然后进行交换即可。
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode preHeadNode = new ListNode(-1);
preHeadNode.next = head;
ListNode traverseNode = preHeadNode;
while(traverseNode.next != null && traverseNode.next.next != null){
ListNode n1 = traverseNode.next;
ListNode n2 = traverseNode.next.next;
traverseNode.next = n2;
ListNode temp = n2.next;
n2.next = n1;
n1.next = temp;
traverseNode = n1;
}
return preHeadNode.next;
}
}
递归的写法,需要系统的学习递归,链表和树的大多数题目太适合递归了。
参考博客https://lyl0724.github.io/2020/01/25/1/
递归三部曲:1.找终止条件 2.找返回值 3.单次过程
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode next = head.next;
head.next = swapPairs(next.next);
next.next = head;
return next;
}
}

[Leetcode刷题]——链表的更多相关文章
- C#LeetCode刷题-链表
链表篇 # 题名 刷题 通过率 难度 2 两数相加 29.0% 中等 19 删除链表的倒数第N个节点 29.4% 中等 21 合并两个有序链表 C#LeetCode刷题之#21-合并两个有序链 ...
- LeetCode刷题 链表专题
链表专题 链表题目的一般做法 单链表的结构类型 删除节点 方法一 方法二 增加节点 LeedCode实战 LC19.删除链表的倒数第N个结点 解法思路 LC24.两两交换链表中的节点 解法思路 LC6 ...
- LeetCode刷题总结-链表
LeetCode刷题总结-链表 一.链表 链表分为单向链表.单向循环链表和双向链表,一下以单向链表为例实现单向链表的节点实现和单链表的基本操作. 单向链表 单向链表也叫单链表,是链表中最简单的 ...
- LeetCode刷题专栏第一篇--思维导图&时间安排
昨天是元宵节,过完元宵节相当于这个年正式过完了.不知道大家有没有投入继续投入紧张的学习工作中.年前我想开一个Leetcode刷题专栏,于是发了一个投票想了解大家的需求征集意见.投票于2019年2月1日 ...
- LeetCode刷题总结之双指针法
Leetcode刷题总结 目前已经刷了50道题,从零开始刷题学到了很多精妙的解法和深刻的思想,因此想按方法对写过的题做一个总结 双指针法 双指针法有时也叫快慢指针,在数组里是用两个整型值代表下标,在链 ...
- LeetCode刷题总结-数组篇(上)
数组是算法中最常用的一种数据结构,也是面试中最常考的考点.在LeetCode题库中,标记为数组类型的习题到目前为止,已累计到了202题.然而,这202道习题并不是每道题只标记为数组一个考点,大部分习题 ...
- LeetCode刷题总结-树篇(下)
本文讲解有关树的习题中子树问题和新概念定义问题,也是有关树习题的最后一篇总结.前两篇请参考: LeetCode刷题总结-树篇(上) LeetCode刷题总结-树篇(中) 本文共收录9道题,7道中等题, ...
- LeetCode刷题笔记和想法(C++)
主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...
- C#LeetCode刷题-设计
设计篇 # 题名 刷题 通过率 难度 146 LRU缓存机制 33.1% 困难 155 最小栈 C#LeetCode刷题之#155-最小栈(Min Stack) 44.9% 简单 173 二叉搜索 ...
随机推荐
- 半夜删你代码队 Day4冲刺
一.每日站立式会议 1.站立式会议 成员 昨日完成工作 今日计划工作 遇到的困难 陈惠霖 做了新规划 开始双人合作 无 侯晓龙 写了第一个例子 开始双人合作 无 周楚池 准备合作 开始双人合作 无 胡 ...
- AcWing 332. 股票交易
大型补档计划 题目链接 \(f[i][j]\) 表示前 \(i\) 天,手里有 \(j\) 个股票挣得最多钱 买股票.枚举 \(u < i - W\) \(f[i][j] = max(f[u][ ...
- linux文件实时同步
参考博客:https://www.cnblogs.com/MacoLee/p/5633650.html 一.文件同步很简单 服务端:被动的接收传输过来的数据 客户端:主动提供数据给服务端 安装思路:服 ...
- 写一个为await自动加上catch的loader逐渐了解AST以及babel
为什么要写这个loader 我们在日常开发中经常用到async await去请求接口,解决异步.可async await语法的缺点就是若await后的Promise抛出错误不能捕获,整段代码区就会卡住 ...
- 时间转成x时x分x秒的封装(简易版)
function createTime(t) { let timer; if (t <= 0 || !t || t < 60 || typeof(t)!=='number') timer ...
- 【操作系统】页面置换算法(最佳置换算法)(C语言实现)
[操作系统]页面置换算法(最佳置换算法)(C语言实现) (编码水平较菜,写博客也只是为了个人知识的总结和督促自己学习,如果有错误,希望可以指出) 1.页面置换算法: 在地址映射过程中,若在页面中发现所 ...
- JavaSE14-集合·其一
1.Collection集合 1.1 集合体系结构 集合 (接口)Collection:单列 (接口)List:可重复 (实现类)ArrayList (实现类)LinkedList (接口)Set:不 ...
- 深入浅出java的Map
HashMap的组成 首先了解数组和链表两个数据结构 1.数组 寻址容易,插入和删除元素困难 数组由于是紧凑连续存储,可以随机访问,通过索引快速找到对应元素,而且相对节约存储空间. 但正因为连续存储, ...
- Java8中执行js脚本
代码中除了callJSFunctionFromFile函数,其他均转载于文章JDK1.8中如何用ScriptEngine动态执行JS import jdk.nashorn.api.scripting. ...
- CMake将生成的可执行文件保存到其他目录
在运行一些程序的时候,我们一般会把数据文件放在其他位置.而当在修改程序时,需要不断的修改代码,编译,执行.每次编译之后,都得将可执行文件复制到数据文件的目录. 这一问题有两种解决方法,一是直接在数据目 ...
