一、找出两个链表的交点

160.相交链表(easy)2021-01-05

编写一个程序,找到两个单链表相交的起始节点    

如下面的两个链表,在c1 处相交:

  1. public class Solution {
  2. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  3. ListNode l1 = headA;
  4. ListNode l2 = headB;
  5. while(l1 != l2){
  6. l1 = (l1 == null) ? headB : l1.next;
  7. l2 = (l2 == null) ? headA : l2.next;
  8. }
  9. return l1;
  10. }
  11. }

解法:如果两个链表有相交,设第一个链表长度为 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

  进阶:
  你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

  我的原始解法,错误示范:

  1. class Solution {
  2. public ListNode reverseList(ListNode head) {
  3. ListNode newHead = head;
  4. newHead.next = null;
  5. ListNode traverseNode = head;
  6. while(traverseNode.next != null){
  7. traverseNode = traverseNode.next;
  8. ListNode temp = traverseNode;
  9. temp.next = newHead;
  10. newHead = temp;
  11. }
  12. return newHead;
  13. }
  14. }

 

错误分析:上述代码理论推导似乎可行,但是编译器运行不通过。

     debug后发现,第2-5行,将head结点赋值给newhead结点,然后将newhead结点的next指针改为null,发现原始的head结点的next指针自动也变成了null。

            在idea中可以看到,虽然head的值赋值给newHead 和traverseNode, 但是并没有开辟新空间,所以这里不能当一般变量处理。

标准解法:

1.递归,yyds

  1. public static ListNode reverseList(ListNode head) {
  2. if(head == null || head.next == null){
  3. return head;
  4. }
  5. ListNode next = head.next;
  6. ListNode newHead = reverseList(next);
  7. next.next = head;
  8. head.next = null;
  9. return newHead;
  10. }

2.头插法

  1. public ListNode reverseList(ListNode head) {
  2. ListNode newHead = new ListNode(-1);
  3. while (head != null) {
  4. ListNode next = head.next;
  5. head.next = newHead.next;
  6. newHead.next = head;
  7. head = next;
  8. }
  9. return newHead.next;
  10. }

 三、合并两个有序链表

21、合并两个有序链表(easy) 2021-01-07

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

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

我的代码:

常规思路,需要注意的是在进行循环后的第二个if 语句时,又重新判断了( l1 != null )。 如果不加判断条件有可能为null就直接写l1.val会产生NullPointerException异常。

  1. class Solution {
  2. public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
  3. ListNode newHead = new ListNode(-1);
  4. ListNode temp = newHead;
  5. while(l1 != null && l2 != null){
  6. if(l1.val < l2.val){
  7. temp.next = l1;
  8. temp = l1;
  9. l1 = l1.next;
  10. }
  11. if(l1 != null && l2.val <= l1.val){
  12. temp.next = l2;
  13. temp = l2;
  14. l2 = l2.next;
  15. }
  16. }
  17. if(l1 == null){
  18. temp.next = l2;
  19. }
  20. if(l2 == null){
  21. temp.next = l1;
  22. }
  23. return newHead.next;
  24. }
  25. }

递归的写法,真简洁:

  1. class Solution {
  2. public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
  3. if (l1 == null) return l2;
  4. if (l2 == null) return l1;
  5. if (l1.val < l2.val) {
  6. l1.next = mergeTwoLists(l1.next, l2);
  7. return l1;
  8. } else {
  9. l2.next = mergeTwoLists(l1, l2.next);
  10. return l2;
  11. }
  12. }
  13. }

四、从有序链表中删除重复结点

83、删除排序链表中的重复元素   (easy)  2021-01-08

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例 1:

输入: 1->1->2
输出: 1->2
示例 2:

输入: 1->1->2->3->3
输出: 1->2->3

我的解法:需要注意的一点是在没有判断结点是否为空的情况下之直接就使用.val 调用结点的数值会报NullPointerException异常

  1. class Solution {
  2. public ListNode deleteDuplicates(ListNode head) {
  3. ListNode tempNode = head;
  4. while(tempNode != null){
  5. if(tempNode.next != null && tempNode.val == tempNode.next.val){
  6. tempNode.next = tempNode.next.next;
  7. }else{
  8. tempNode = tempNode.next;
  9. }
  10. }
  11. return head;
  12. }
  13. }

递归的解法,妙呀,三行就搞定!唯一不足的就是内存消耗较多。

  1. class Solution {
  2. public ListNode deleteDuplicates(ListNode head) {
  3. if (head == null || head.next == null) return head;
  4. head.next = deleteDuplicates(head.next);
  5. return head.val == head.next.val ? head.next : head;
  6. }
  7. }

 五、删除链表的倒数第N个结点

19、给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。(medium) 2021-01-09

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?

我的解法,遍历两次,内存击败29.8%,还是太菜

  1. class Solution {
  2. public ListNode removeNthFromEnd(ListNode head, int n) {
  3. ListNode tempNode = head;
  4. int len = 1;
  5. while(tempNode.next != null){
  6. len++;
  7. tempNode = tempNode.next;
  8. }
  9. tempNode = head;
  10. if(n == len){
  11. return head.next;
  12. }else{
  13. while(tempNode != null && tempNode.next != null){
  14. if(len == n + 1){
  15. tempNode.next = tempNode.next.next;
  16. }
  17. len--;
  18. tempNode = tempNode.next;
  19. }
  20. return head;
  21. }
  22.  
  23. }
  24. }

遍历一次的原理,设置两个指针,让一个指针先走n长度,然后两个指针一起走,当快的指针走到链表结尾时,慢的指针就在倒数第n个位置

  1. class Solution {
  2. public ListNode removeNthFromEnd(ListNode head, int n) {
  3. ListNode fast = head;
  4. while (n-- > 0) {
  5. fast = fast.next;
  6. }
  7. if (fast == null) return head.next;
  8. ListNode slow = head;
  9. while (fast.next != null) {
  10. fast = fast.next;
  11. slow = slow.next;
  12. }
  13. slow.next = slow.next.next;
  14. return head;
  15. }
  16. }

六、两两交换链表中的相邻结点

24、给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。(medium) 2021-01-10

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]

解法:力扣里的链表的头节点都是第一个结点,在这个题中,设置第一个结点的前一个结点为头结点,在判断后两个结点是否为空,然后进行交换即可。

  1. class Solution {
  2. public ListNode swapPairs(ListNode head) {
  3. ListNode preHeadNode = new ListNode(-1);
  4. preHeadNode.next = head;
  5. ListNode traverseNode = preHeadNode;
  6. while(traverseNode.next != null && traverseNode.next.next != null){
  7. ListNode n1 = traverseNode.next;
  8. ListNode n2 = traverseNode.next.next;
  9. traverseNode.next = n2;
  10. ListNode temp = n2.next;
  11. n2.next = n1;
  12. n1.next = temp;
  13. traverseNode = n1;
  14. }
  15. return preHeadNode.next;
  16. }
  17. }

  递归的写法,需要系统的学习递归,链表和树的大多数题目太适合递归了。

  参考博客https://lyl0724.github.io/2020/01/25/1/

  递归三部曲:1.找终止条件 2.找返回值 3.单次过程

  1. class Solution {
  2. public ListNode swapPairs(ListNode head) {
  3. if(head == null || head.next == null){
  4. return head;
  5. }
  6. ListNode next = head.next;
  7. head.next = swapPairs(next.next);
  8. next.next = head;
  9. return next;
  10. }
  11. }

[Leetcode刷题]——链表的更多相关文章

  1. C#LeetCode刷题-链表

    链表篇 # 题名 刷题 通过率 难度 2 两数相加   29.0% 中等 19 删除链表的倒数第N个节点   29.4% 中等 21 合并两个有序链表 C#LeetCode刷题之#21-合并两个有序链 ...

  2. LeetCode刷题 链表专题

    链表专题 链表题目的一般做法 单链表的结构类型 删除节点 方法一 方法二 增加节点 LeedCode实战 LC19.删除链表的倒数第N个结点 解法思路 LC24.两两交换链表中的节点 解法思路 LC6 ...

  3. LeetCode刷题总结-链表

    LeetCode刷题总结-链表 一.链表     链表分为单向链表.单向循环链表和双向链表,一下以单向链表为例实现单向链表的节点实现和单链表的基本操作. 单向链表 单向链表也叫单链表,是链表中最简单的 ...

  4. LeetCode刷题专栏第一篇--思维导图&时间安排

    昨天是元宵节,过完元宵节相当于这个年正式过完了.不知道大家有没有投入继续投入紧张的学习工作中.年前我想开一个Leetcode刷题专栏,于是发了一个投票想了解大家的需求征集意见.投票于2019年2月1日 ...

  5. LeetCode刷题总结之双指针法

    Leetcode刷题总结 目前已经刷了50道题,从零开始刷题学到了很多精妙的解法和深刻的思想,因此想按方法对写过的题做一个总结 双指针法 双指针法有时也叫快慢指针,在数组里是用两个整型值代表下标,在链 ...

  6. LeetCode刷题总结-数组篇(上)

    数组是算法中最常用的一种数据结构,也是面试中最常考的考点.在LeetCode题库中,标记为数组类型的习题到目前为止,已累计到了202题.然而,这202道习题并不是每道题只标记为数组一个考点,大部分习题 ...

  7. LeetCode刷题总结-树篇(下)

    本文讲解有关树的习题中子树问题和新概念定义问题,也是有关树习题的最后一篇总结.前两篇请参考: LeetCode刷题总结-树篇(上) LeetCode刷题总结-树篇(中) 本文共收录9道题,7道中等题, ...

  8. LeetCode刷题笔记和想法(C++)

    主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...

  9. C#LeetCode刷题-设计

    设计篇 # 题名 刷题 通过率 难度 146 LRU缓存机制   33.1% 困难 155 最小栈 C#LeetCode刷题之#155-最小栈(Min Stack) 44.9% 简单 173 二叉搜索 ...

随机推荐

  1. Nday漏洞组合拳修改全校师生密码

    很久以前写的文章了,发一下:) 本文是我真实的挖洞经历.撰写本文时相关学校已修复漏洞,相关漏洞也提交给了教育漏洞平台.纯粹是挖洞经验的总结和技术分享,由于敏感信息比较多,所以文章里面很多图片已经面目全 ...

  2. pandas 删除列

    ddf = pd.DataFrame({"id":[1,2,3], "name":[4,5,6],"age":[7,8,9]})ddf = ...

  3. 百度前端技术学院-基础-day17-18

    JavaScript小练习 task 1 基于上一个任务中,关于加减乘除的任务,加上对于特殊情况的判断,比如判断两个输入框是否都是正常输入了数字类型的内容,比如除法的时候除数是否为0,当判断到输入有异 ...

  4. 转:minhash

    Minhash算法及其应用 一.引言 MinHash算法属于Locality Sensitive Hashing,用于快速估计两个集合的相似度.最早由Broder Andrei Z. 在1997年提出 ...

  5. MySQL技术内幕InnoDB存储引擎(七)——事务

    什么是数据库的事务? 事务是访问并更新数据库中各种数据的一个程序执行单元.事务也是数据库区别于文件系统的一个重要特性. 事务需要满足的特性 1.原子性 原子性就是指数据库中的一个完整的事务是不可分割的 ...

  6. [JDK8]Map接口与Dictionary抽象类

    package java.util; 一.Map接口 接口定义 public interface Map<K,V> Map是存放键值对的数据结构.map中没有重复的key,每个key最多只 ...

  7. 【Django admin 中文配置】

    打开settings.py文件,找到语言编码.时区的设置项,将内容改为如下: [其中 zh-Hans是简体中文 zh-Hant是繁体中文] LANGUAGE_CODE = 'zh-Hans' # LA ...

  8. 我是如何用go-zero 实现一个中台系统的

    最近发现golang社区里出了一个新星的微服务框架,来自好未来,光看这个名字,就很有奔头,之前,也只是玩过go-micro,其实真正的还没有在项目中运用过,只是觉得 微服务,grpc 这些很高大尚,还 ...

  9. Flink读写Redis(三)-读取redis数据

    自定义flink的RedisSource,实现从redis中读取数据,这里借鉴了flink-connector-redis_2.11的实现逻辑,实现对redis读取的逻辑封装,flink-connec ...

  10. DRF类视图让你的代码DRY起来

    刚开始写views.py模块的代码,一般都是用def定义的函数视图,不过DRF更推荐使用class定义的类视图,这能让我们的代码更符合DRY(Don't Repeat Yourself)设计原则: 使 ...