LeetCode刷题 --基础知识篇-- 链表

  题目来源与力扣,传送门在这里。

  众所周知,链表是很重要的一种数据结构,但同时也很容易出错,二狗在重温这部分内容时被人指点了一些典型的题目,顺手去leetCode刷了一些,记录如下。

《206.单链表反转》(https://leetcode-cn.com/problems/reverse-linked-list/)

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     public int val;
 5  *     public ListNode next;
 6  *     public ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode ReverseList(ListNode head) {
11         ListNode newHead = null;
12         ListNode temp = null;
13
14         if(head == null || head.next == null)
15         {
16             return head;
17         }
18
19         while(head != null)
20         {
21             temp = head;
22             head = head.next;
23
24             temp.next = newHead;
25             newHead = temp;
26         }
27
28         return newHead;
29     }
30 }

  上面代码思路是这样的,建立一个新的结点newHead和一个存放临时内容的temp结点。开始遍历head结点,每次循环中都对head取头结点然后移动head到head.next。同时把取到的结点放入链表的头部,有点类似与栈。

  其实这道题目还可以利用三个指针P0(前一个结点),P1(当前结点),P2(当前结点的next)来操作,思路是每次循环都将P1的next改写为P0,即改变它的指向,然后再将P0,P1,P2依次移动。但要注意这种方法的顺序,一定要保证先移动P0到P1的位置才能移动P1到P2的位置。

《141.环形链表》(https://leetcode-cn.com/problems/linked-list-cycle/)

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     public int val;
 5  *     public ListNode next;
 6  *     public ListNode(int x) {
 7  *         val = x;
 8  *         next = null;
 9  *     }
10  * }
11  */
12 public class Solution {
13     public bool HasCycle(ListNode head) {
14         if(head == null || head.next == null)
15         {
16             return false;
17         }
18
19         ListNode slow = head.next;
20         ListNode fast = head.next.next;
21
22         while(fast != slow)
23         {
24             if(fast == null || fast.next == null)
25             {
26                 return false;
27             }
28
29             slow = slow.next;
30             fast = fast.next.next;
31         }
32
33         return true;
34     }
35 }

  很经典的快慢指针的问题,判断一个链表中有没有环的思路是这样的:如果我们不断的移动当前的指针到next,对于没有环的结点,一定可以到达null。所以如果我们找到了null就说明一定不是环形链表。对于有环的链表,我们设置两个指针开始不断的移动,一个慢指针每次移动一个结点,一个快指针每次移动两个结点。如果存在环,在足够多次的移动后快指针会和慢指针相遇,此时就可以判断出是有环结构了。但这种写法一定要注意边界值的情况。

《21.合并两个有序链表》(https://leetcode-cn.com/problems/merge-two-sorted-lists/)

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

示例:

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

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     public int val;
 5  *     public ListNode next;
 6  *     public ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode MergeTwoLists(ListNode l1, ListNode l2) {
11         ListNode head = new ListNode(1);
12         ListNode temp = head;
13
14         while(l1 != null && l2 != null)
15         {
16             if(l1.val <= l2.val)
17             {
18                 temp.next = l1;
19                 temp = temp.next;
20                 l1 = l1.next;
21             }
22             else
23             {
24                 temp.next = l2;
25                 temp = temp.next;
26                 l2 = l2.next;
27             }
28         }
29
30         if(l1 == null)
31         {
32             temp.next = l2;
33         }
34         else
35         {
36             temp.next = l1;
37         }
38
39         return head.next;
40     }
41 }

  思路很简单,设置一个哨兵结点,然后从两个链表的头部开始比较,依次取得较小的值将其放入哨兵结点的next,并移动哨兵结点到next。注意如果有一个链表已经移动到了末尾,只需要把另一个链表的剩余结点直接添加即可。

《19.删除链表的倒数第n个结点》(https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/)

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

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

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

给定的 n 保证是有效的。

进阶:

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

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     public int val;
 5  *     public ListNode next;
 6  *     public ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode RemoveNthFromEnd(ListNode head, int n) {
11         if(head.next == null)
12         {
13             return null;
14         }
15
16         ListNode first = head;
17         ListNode sec = head;
18         ListNode result = sec;
19
20         for(int i = 0; i<n; i++)
21         {
22             first = first.next;
23         }
24
25         if(first == null)
26         {
27             return result.next;
28         }
29
30         while(true)
31         {
32             if(first.next == null)
33             {
34                 sec.next = sec.next.next;
35                 break;
36             }
37
38             first = first.next;
39             sec = sec.next;
40         }
41
42         return result;
43     }
44 }

  思路是这样的,设置firat和sec两个结点同时指向head,然后先将first执行n次first = first.next.接着将first和sec同时移动,当first.next == null时说明移动到了链表的尾部,此时sec的next结点即为倒数第n个结点,删除即可。

《876.链表的中间结点》(https://leetcode-cn.com/problems/middle-of-the-linked-list/)

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:

输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

提示:

给定链表的结点数介于 1 和 100 之间。

 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     public int val;
 5  *     public ListNode next;
 6  *     public ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode MiddleNode(ListNode head) {
11         if(head.next == null)
12         {
13             return head;
14         }
15
16         ListNode slow = head;
17         ListNode fast = head;
18
19         while(true)
20         {
21             fast = fast.next;
22
23             if(fast == null)
24             {
25                 return slow;
26             }
27
28             fast = fast.next;
29
30             if(fast == null)
31             {
32                 return slow.next;
33             }
34
35             slow = slow.next;
36         }
37     }
38 }

  这道题我借鉴了前面判断环形结点的思路,也是使用快慢两个指针。有一点需要注意的是,对一个链表来说结点的个数可能为偶数个或者奇数个,如果是偶数个根据题目我们需要取得后一个结点。我们在遍历链表时如果保证每次都是快指针先移动就比较方便判断了。快指针是需要移动两次的,当第一次移动后如果快指针为null,则可以说明包含奇数个结点,如果第二次移动后快指针为null则可以说明包含偶数个结点。



原文地址:https://www.cnblogs.com/dogtwo0214/p/12231639.html

时间: 2024-09-28 17:24:23

LeetCode刷题 --基础知识篇-- 链表的相关文章

LeetCode刷题--基础知识篇--KMP算法

KMP算法 关于字符串匹配的算法,最知名的莫过于KMP算法了,尽管我们日常搬砖几乎不可能去亲手实现一个KMP算法,但作为一种算法学习的锻炼也是很好的,所以记录一下. KMP算法是根据三位作者(D.E.Knuth, J.H.Morris和V.R.Pratt)的名字来命名的,算法的全称是Knuth Morris Pratt算法,简称为KMP算法. 关于字符串匹配,我们假设要在字符串A中查找字符串B,那么我们可以把字符串A叫做主串,把B叫做模式串.所以字符串匹配其实就是要在主串中找到与模式串相同的子串

LeetCode刷题总结-字符串篇

本文梳理对LeetCode上有关字符串习题的知识点,并给出对应的刷题建议.本文建议刷题的总数为32题.具体知识点如下图: 1.回文问题 题号:5. 最长回文子串,难度中等 题号:214. 最短回文串,难度困难 题号:564. 寻找最近的回文数,难度困难 2.子串问题(类似子集) 题号:76. 最小覆盖子串,难度困难 题号:115. 不同的子序列,难度困难 题号:522. 最长特殊序列 II,难度中等 题号:1163. 按字典序排在最后的子串,难度困难 3.表达式求值问题 题号:12. 整数转罗马

LeetCode刷题之合并排序链表

合并两个有序链表并返回一个新的列表.新列表应该由连接在一起的节点前两个列表 给定实例:Input: 1->2->4, 1->3->4Output: 1->1->2->3->4->4 思路分析:引入第三个链表,存储合并之后的链表,开两个指针,分别遍历两个链表,当遍历到一个节点的时候,就开始判断大小,然后将小的链表节点存储到第三个链表中,依次递归判断.但是我们需要考虑临界条件,如果第一个链表的数都比第二个链表的小,那么我们就直接将第二个链表链接到第三个链表

刷题基础知识

Map的使用: 1 public class Main 2 { 3 public long factorial(int n){ 4 if(n<=1) 5 return 1; 6 return n * factorial(n-1); 7 } 8 9 public long func(String line){ 10 HashMap<Character, Integer> map = new HashMap<Character, Integer>(); 11 for(int i=

LeetCode刷题总结-链表

LeetCode刷题总结-链表 一.链表     链表分为单向链表.单向循环链表和双向链表,一下以单向链表为例实现单向链表的节点实现和单链表的基本操作. 单向链表 单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域.这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值. 表元素域elem用来存放具体的数据: 链接域next用来存放下一个节点的位置(python中的标识): 变量p指向链表的头节点(首节点)的位置,从p出发能找到表

LeetCode刷题总结之双指针法

Leetcode刷题总结 目前已经刷了50道题,从零开始刷题学到了很多精妙的解法和深刻的思想,因此想按方法对写过的题做一个总结 双指针法 双指针法有时也叫快慢指针,在数组里是用两个整型值代表下标,在链表里是两个指针,一般能实现O(n)的时间解决问题,两个指针的位置一般在第一个元素和第二个元素或者第一个元素和最后一个元素,快指针在前“探路”,当符合某种条件时慢指针向前挪 盛最多水的容器 这道题其实是求最大面积,最大面积取决于较小值.初始时两指针分别位于第一和最后一个元素处,那么明确指针应该向什么方

【leetcode刷题笔记】Insertion Sort List

Sort a linked list using insertion sort. 题解:实现链表的插入排序. 要注意的地方就是,处理链表插入的时候尽量往当前游标的后面插入,而不要往前面插入,后者非常麻烦.所以每次利用kepeler.next.val和head.val比较大小,而不是kepeler.val和head.val比较大小,因为如果用后者,要把head指向的节点插入到kepeler指向的节点的前面,如果kepeler指向的节点是头结点,就更麻烦了. 代码如下: 1 /** 2 * Defi

leetcode 刷题之路 93 Merge k Sorted Lists

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 将k个有序链表合并成一个有序链表. 思路,之前做过两个有序链表的合并操作,对于k个链表,我们最先想到的就是能不能转化为我们熟悉的两个链表的合并,可以我们先将k个链表分为两部分,先对这两部分完成链表的有序合并操作,再对合并得到的两个链表进行合并,这是一个递归性质的描述,采用递归很容易实现这个程序,和数组

【leetcode刷题笔记】Sort List

Sort a linked list in O(n log n) time using constant space complexity. 题解:实现一个链表的归并排序即可.主要分为三部分: 1.找到中点并返回的函数findMiddle; 2.归并函数merge; 3.排序函数sortList. 数组的findMiddle函数非常容易实现,链表就有一点tricky了.首先设置两个指针,一个slow初始化为head,一个fast初始化为head.next,然后slow一次走一步,fast一次走两