目录

  • 1.[删除链表中等于给定值 val 的所有节点](https://leetcode-cn.com/problems/remove-linked-list-elements/description/)
  • 2.[反转一个单链表](https://leetcode-cn.com/problems/reverse-linked-list/description/).
  • 3.[链表的中间结点 ](https://leetcode-cn.com/problems/middle-of-the-linked-list/description/)
  • 4.[链表中倒数第k个节点](https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/)
  • 5.[合并两个有序链表](https://leetcode-cn.com/problems/merge-two-sorted-lists/description/)
  • 6.[删除链表中重复节点](https://www.nowcoder.com/practice/fc533c45b73a41b0b44ccba763f866ef?tpId=13&&tqId=11209&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking)
  • 7.[链表的回文结构](https://leetcode-cn.com/problems/palindrome-linked-list/)
  • 8.[分割链表](https://leetcode-cn.com/problems/partition-list/)

在记录作者自己学习过程和解题时的思路方便复习的同时分享给其他同学们,如有错误或不足还请指正。

1.删除链表中等于给定值 val 的所有节点

解法一:创建一条新链表,遍历旧链表,将不等于定值val的结点加入到新链表,要注意的是,新链表最后一个结点的next可能指向旧链表中后面的结点(因为自这个节点以后的其他结点都不满足进入新链表的条件),所以在遍历完旧链表即新链表创建完成后要让新链表的newCur.next = null; 最后return newList.next。

public  ListNode removeElements(ListNode head, int val) {ListNode newList = new ListNode();ListNode newCur = newList;ListNode cur = head;while (cur != null){if (cur.val != val){newCur.next = cur;newCur = cur;cur = cur.next;}else {cur = cur.next;}}newCur.next = null;return newList.next;}

解法二:不用创建新链表,创建一个哨兵结点指向head,创建一个prev引用指向哨兵结点,一个cur引用指向head,开始依次遍历,不满足条件时让cur = cur.next; prev = prev.next; 直到遇见val等于给定值的结点,此时让cur = cur.next; prev.next = cur; 这样通过修改prev.next的值来跳过满足条件的结点。

public  ListNode removeElements(ListNode head, int val) {ListNode newList = new ListNode();newList.next = head;ListNode prev = newList;ListNode cur = head;while (cur != null){if (cur.val == val){cur = cur.next;prev.next = cur;}else {prev = cur;cur = cur.next;}}return newList.next;}

解法三:因为链表的定义使链表具有递归特性,这使得好多链表的题目都有递归解法,是递归解法就得考虑到递归出口,这个题目递归出口明显是链表遍历完,从出口开始一层一层返回,返回是判断当前head结点val是否满足删除条件,若满足这一层的返回值是当前head.next,若不满足则返回当前头结点给上一层。

public ListNode removeElements(ListNode head, int val){if (head == null){return null;}head.next = solve(head.next, val);return head.val == val ? head.next : head;}

2.反转一个单链表.

解法一:只要一提到反转就会想到栈,因为栈先进后出的特性使的进栈出栈之后一个序列就会被反转,这个方法先依次遍历链表,遍历的过程中将每个结点依次入栈,留下最后一个节点,然后依次pop,这样就达到了目的,需要注意的是,出栈反转链表的最后,原链表的头结点的next指向的是原链表的第二个结点,所以需要将原链表头结点.next = null。

 public  ListNode reverseList(ListNode head) {if (head == null){return null;}Stack<ListNode> reversse = new Stack<>();ListNode cur = head;while(cur.next != null){reversse.push(cur);cur = cur.next;}ListNode newHead = cur;while (!reversse.isEmpty()){cur.next = reversse.pop();cur = cur.next;}cur.next = null;return newHead;}

解法二:设置一个提前引用prev,一个遍历引用cur,在每次遍历的时候创建一个引用next指向cur.next(因为cur.next要指向前一个节点即prev指向的节点),然后prev指向cur,cur指向next,这样就完成了一次局部反转。

public ListNode reverseList(ListNode head){ListNode prev = null;ListNode cur = head;while (cur != null){ListNode next = cur.next;cur.next = prev;prev = cur;cur = next;}return prev;}

解法三:递归解法,这道题目的递归解法主要目的是遍历到最后节点(如果传入链表本来为空就返回null),然后拿到最后结点当新的头结点 ,反转的操作在每一层递归中,让每层递归的head.next.next = head;(即让head的下一个节点的指针域指向head)这条命令是这个方法最难理解的地方。

public ListNode reverseList(ListNode head){if (head == null || head.next == null){return head;}//自递归出口返回head后,newhead一直没有变,因为newHead是//反转后链表的头结点ListNode newHead = reverseList(head);head.next.next = head;head.next = null;return newHead;}

3.链表的中间结点

解法:快慢指针发,定义两个指针指向头结点front,last,同时让两个指针往后走,fast一次走两步,slow一次往后走一步,当fast走完时,slow刚好走到中间位置。

 public ListNode middleNode(ListNode head) {ListNode front = head;ListNode last = head;/*之所以循环结束有两个条件是因为如果有单数节点的话,front会停在最后一个结点处,再往后走就会出现空指针异常;如果有双数个节点的话,front最后会停在null(最后一个结点next指向null),此时慢的节点也刚好走到中间第二个节点。*/while (front != null && front.next != null){front = front.next.next;last = last.next;}return last;}

4.链表中倒数第k个节点

解法:这个解法和题目三的快慢指针解法有异曲同工之妙,找到倒数第k个节点,那么先让front指针先走到正数第k的节点,last指针在第一个节点,这样front指针走到最后,last指针刚好走到倒数第k个节点处,因为不管是正数第k个还是倒数第k个,他们俩相差的节点数是相同的,让前后指针现有这个相差的节点数,然后去走,最后停下来lasst指针就会停在单数第k个节点处。

public ListNode FindKthToTail(ListNode head, int k) {//链表为空或者要找不存在的倒数第0个节点就返回空if (head == null || k == 0){return null;}ListNode fast = head;ListNode slow = head;int count = 1;while (fast.next != null){if (count < k){fast = fast.next;count++;}else {fast = fast.next;slow = slow.next;}}//因为存在k大于节点数的情况,即一共五个节点,但是要找倒数//第六个节点,这样的话在让头指针先走的过程中还没到第六个节点//就已经到null了退出循环了,此时count就会小于kif (count != k){return null;}return slow;

5.合并两个有序链表

解法:创建一条新链表,然后依次遍历两条旧链表,遍历过程中比较,哪个节点小就将那个节点插入到新链表中,然后让这个cur = cur.next; 另一个链表的遍历指针不动,遍历过程中但凡有一条链表遍历完了,就结束循环,将没有遍历完的链表直接尾插到新链表,因为两个链表都是有序的,所以不存在后面节点的值大于前面节点值的情况。

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {ListNode newList = new ListNode();ListNode cur1 = l1;ListNode cur2 = l2;ListNode cur = newList;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 = cur2;}if (cur2 == null){cur.next = cur1;}return newList;}

6.删除链表中重复节点

解法:设置一个prev引用一个哨兵结点,prev刚开始指向哨兵结点,后面这个引用一直指向删除后部分的最后一个节点,设置一个slow和一个fast引用,分别指向第一个第二个节点,然后开始循环遍历,如果slow.val != fast.val;那么fast = fast.next; prev.nxet = slow; prev = slow; slow = slow.next;,如果两个值相等则slow先不动,让fast往后走,一直到fast的val不等于slow时停止,因为会存在大于两个重复节点的情况。

public static ListNode deleteDuplication1(ListNode pHead) {if (pHead == null || pHead.next == null){return pHead;}ListNode frontNode = new ListNode(0);frontNode.next = pHead;ListNode prev = frontNode;ListNode fast = pHead.next;ListNode slow = pHead;while (fast != null){if (slow.val == fast.val){while (fast != null && fast.val == slow.val){fast = fast.next;}if (fast == null){prev.next = null;return frontNode.next;}else {slow = fast;fast = fast.next;prev.next = slow;}}else {prev = slow;slow = fast;fast = fast.next;}}return frontNode.next;}

7.链表的回文结构

解法一:我的暴力解法,将节点装到栈里的同时将每个节点的值加入一个定义好的StringBuffer str1,然后依次出栈,出栈的同时把每个节点的值加入一个定义好的StringBuffer str2,最后equal比较两个str.toString()是否相同。这个解法比较慢,但是个人觉得好理解。

 public static boolean chkPalindrome(ListNode A) {StringBuilder str1 = new StringBuilder();StringBuilder str2 = new StringBuilder();Stack<ListNode> stack = new Stack<>();ListNode cur = A;while (cur != null){stack.push(cur);str1.append(cur.val);cur = cur.next;}while (!stack.isEmpty()){str2.append(stack.pop().val);}System.out.println(str1);System.out.println(str2);return str1.toString().equals(str2.toString());}

8.分割链表

解法:大的的思路是创建一个装小于等于x值的链表small,创建一个装大于x值的链表big,然后遍历所给链表,遍历过程中小于等于x的节点插入到small的链表中,大于x的节点插入到big中,最后把smallCur.next = big.next;就完成了连接,返回small.next。

 public ListNode partition(ListNode head, int x) {if (head == null){return null;}ListNode small = new ListNode();ListNode smallCur = small;ListNode big = new ListNode();ListNode bigCur = big;ListNode cur = head;while (cur != null){if (cur.val < x){smallCur.next = cur;smallCur = cur;cur = cur.next;}else {bigCur.next = cur;bigCur = cur;cur = cur.next;}}bigCur.next = null;smallCur.next = big.next;return small.next;}

老师说过链表是分水岭,至少得会这些题目相关推荐

  1. 单表带换密码C语言程序,帮忙写个C语言程序!题目在下面!关于链表的。还没学,题目:“建立一个链表,逐个输入字符,每一个字符存放在一个链。...

    帮忙写个C语言程序!题目在下面!关于链表的.还没学,题目:"建立一个链表,逐个输入字符,每一个字符存放在一个链. Posted By : Admin 2016-05-16 21:16 网友问 ...

  2. 尹成老师,关于链表的一些操作(C)

    ///.h文件 #include <stdio.h> #include <stdlib.h> struct student{ int num; float score; str ...

  3. 链表结构定义、操作以及经典题目

    标题 前言 什么是链表(List/LinkedList) 链表的特点 单向链表的实现 凡是 结构操作 插入 删除 翻转 其他操作 单向链表代码 经典例题 单向循环链表 经典例题 双向链表实现(Doub ...

  4. 【数据结构与算法】03 链表(基础知识+面试高频leetcode题目)

    目录 数组&链表基础 高频面试题(leetcode) 206 反转链表(常考) 方法1:迭代算法(双指针)(cpp&python) 方法2:递归解法 妖魔化的双指针算法. 24 两两交 ...

  5. l2-004 这是二叉搜索树吗?_LeetCode 例题精讲 | 11 二叉树转化为链表:二叉树遍历中的相邻结点...

    本期例题: LeetCode 98. Validate Binary Search Tree 验证二叉搜索树(Medium) LeetCode 426. Convert Binary Tree to ...

  6. c语言关于链表选择题看不懂,有关链表基本操作三题

    因为觉得C语言老师讲链表讲的太匆忙了,况且PPT太乱太杂,看不懂 因此特地重写了次这周三上机有关链表操作的三题.(所写题目默认已排序,不考虑排序) 问题A:在单链表中按学号查成绩 时间限制: 1 Se ...

  7. 循环双链表的手动构建总结

    我们常用的是单链表的算法.虽然双链表和循环双链表的算法常常被拿来作为一种设计的思路,也常假想有一个循环双链表,对它进行操作,实际上我从没动手写过循环双链表. 在手动实现单链表的习题多道以后,有了一种对 ...

  8. c语言建立并存储树,利用十字链表存储树结构(便于同时求出某一点的入度与出度)------C语言实现...

    #include #include #include /* 利用十字链表存储有向图,可用于同时查找某个顶点的出度与入度: */ typedef struct edge {//顶点表 int headv ...

  9. 【链表习题集1】整体和局部反转链表同频和快慢指针合并链表

    前言: 刷题和面试兼顾还得看你啊-牛客网 近几年互联网受疫情影响,许多互联网都使用牛客网在线笔试招人 很多同学因为不熟悉牛客网的环境和使用,最后在线笔试面试中屡屡受挫 牛客网提供了语言巩固,算法提高等 ...

最新文章

  1. 2018年全球十大新兴技术:细胞植入人体、营养人造肉……你想试试吗?
  2. python中异常和错误是一个概念_Python的异常概念介绍以及处理
  3. SqlDataReader对象的NextResult方法读取存储过程多个结果集
  4. python二维列表写入excel_用Python实现合并excel列表
  5. 怎么真正入行Web前端行业?JavaScript五大新特性是什么?
  6. 远程无法连接数据库的问题
  7. 蓝桥杯 ADV-148算法提高 排队打水问题(贪心)
  8. 组织架构适配下的敏捷开发
  9. AUTOCAD——射线命令
  10. 短信验证码接口被恶意攻击怎么办?
  11. 用Changedetection监控网页的变化
  12. 基于asp.net的排球赛事网站设计与实现
  13. WEB安全——CS中Beacon的使用
  14. 复旦计算机课程谁的好,复旦大学计算机研究生导师有哪些
  15. VS2019生成DLL
  16. slub allocator工作原理
  17. 历史上的今天:“超级计算机之父”诞生;三星推出移动支付;LibreOffice 发布...
  18. Matlab信号添加噪声及信噪比SNR的计算
  19. 背后的力量 | 搭建新型IT基础架构 华云数据助力妇幼保健院提升数字化医院建设水平
  20. 为什么国家政府发的国债,被央行自己印的钱大量购买时,利率会降低呢?

热门文章

  1. extend_gcd求解不定方程/膜线性方程/乘法(模)逆元
  2. D3中数据与DOM element绑定之data() enter() exit()浅析
  3. 连网获取图片的小程序
  4. 【BZOJ】【3295】【CQOI2011】动态逆序对
  5. 朋友面试被问到---静态构造函数
  6. JavaScript 音频插件和图表插件
  7. 每个前端工程师都应该懂的前端性能优化总结:
  8. 入门机器学习(九)--应用机器学习的建议
  9. OpenCV3学习(3)——视频文件的读取与写入
  10. mysql 查询包含1或者2_Mysql:同一个表上有2个不同的查询,包含count和group by