- 6: 从头到尾打印链表
- 18 : 删除链表的节点
- 22:链表中倒数第A个节点
- 23: 链表中环的入口节点
- 24: 反转链表
- 25: 合并两个排序的链表
- Definition for singly-linked list.
- class ListNode:
- def init(self, x):
- self.val = x
- self.next = None
- 22. 链表中倒数第k个节点(8.12)
- Definition for singly-linked list.
- class ListNode:
- def init(self, x):
- self.val = x
- self.next = None
- 141. 环形链表 一 (8.12)
- Definition for singly-linked list.
- class ListNode:
- def init(self, x):
- self.val = x
- self.next = None
- 142. 环形链表 二 (8.12,13)
- 24. 反转链表(8.13)
- 25. 合并两个排序的链表
任务:
- 学习周期:8.10-8.16 号,共计 7 天。
- 学习专题:链表。链表的基本原理和操作非常重要,比如增、删、反转、合并、找中点等等。涉及到的技巧不多,大概就是dummy Node和快慢指针。个人觉得其终极原则就是链表这个数据结构的形式,以及这个形式造成了哪些优缺点。
- 训练题目:标红的重点再多巩固巩固
6. 从头到尾打印链表(8.10)
1. 思路
- 递归
- 递归调用取值函数,合并数组
- 辅助栈
- 先进后出
- 反转
- 遍历链表,存到数组,把数组反转
2. 递归
class Solution:
def reversPrint(self,head):
return self.reversPrint(head.next) + [head.val] if head else []
int* reversePrint(struct ListNode* head, int* returnSize){
if (head == NULL){
*returnSize = 0;
return NULL;
}
int* ans = reversePrint(head->next, returnSize);
ans[(*returnSize)++] = head->val;
return ans;
}
3. 辅助栈
class Solution:
def reversePrint(self, head):
stack = []
result = []
while head:
stack.append(head.val)
head = head.next
while stack:
result.append(stack.pop())
return result
4. 反转
class Solution:
def reversePrint(self, head):
res = []
while head:
res.append(head.val)
head = head.next
return res[::-1]
5. 总结
这道题比较简单,原理都是遍历一下列表,可以直接在遍历中取逆序,也可以遍历后反转数组,还可以利用栈的先进后出,让所有元素出栈。
- 遍历链表,存到数组,把数组反转
18. 删除链表的节点(8.11)
1. 思路
遍历链表,当节点的值等于val时跳过这个节点,跳过这个节点需要他的上一个值,
- 可以直接在判断节点值时使用cur.next 来判断,跳过的步骤为 cur.next = cur.next.next
- 单指针法
- 边界条件
- 头节点
- 链表为空
- 也可以使用双指针让一个指针指向节点的前一个节点,跳过的步骤为 pre.next = cur.next
class Solution: def deleteNode(self, head, val):
# 为空
if not head:
return head
# 头节点
if head.val == val :
return head.next
cur = head
while cur.next:
if cur.next.val == val:
cur.next = cur.next.next
break
cur = cur.next
return head
<a name="GbgUj"></a>
### 3. 双链表
```python
class Soluton:
def deleteNode(self,head,val):
# 头节点
if head.val == val:
return head.next
pre, cur = head, head.next
while cur:
if cur.val == val :
pre.next = cur.next
break
pre, cur = cur, cur.next
return head
4. 总结
这道题是删除链表中的节点,要通过匹配删除的话就需要知道节点的前一个节点,将前一个节点的next指向这个节点的next,即可以删除成功,在做题过程中要注意考虑边界情况,链表为空,删头节点,删尾节点。
22. 链表中倒数第k个节点(8.12)
1. 思路
- 列表
- 将链表遍历一遍,把每个节点存到列表中,返回列表后k个元素
- 快慢指针
class Solution: def getKthFromEnd(self, head, k): res = [] while head: res.append(head) head = head.next return res[-k]
<a name="ENKij"></a>
### 3. 快慢指针
```python
class Solution:
def getKthFromEnd(self, head, k):
fast, slow = head, head
for i in range(k):
fast = fast.next
while fast:
fast = fast.next
slow = slow.next
return slow
4. 总结
这道题比较经典的做法是使用快慢指针,使用数组列表的方法有点巧,快慢指针针对环的问题和这个问题会比较好一些。
141. 环形链表 一 (8.12)
今天完成了链表中倒数第k个节点,看下一个题正好是环形链表,可以练习一下快慢指针
- 一 是判断是否有环
- 二 是不仅判断是否有环,还要确定环在哪个位置
1. 思路
前提是链表中不含有重复元素
- 快慢指针
- 快指针一次走俩步
- 慢指针一次走一步
- 如果有环则快慢指针一定会相遇
- 辅助空间
class Solution: def hasCycle(self, head): fast, slow = head, head while fast and fast.next: fast = fast.next.next slow = slow.next if fast == slow: return True return False
<a name="PpGUr"></a>
### 3. 辅助空间
```python
class Solution:
def hasCycle(self, head):
temp = set()
while head;
if head in temp:
return True:
temp.add(head)
head = head.next
return False
4. 总结
快慢指针想到了就不难,但是要考虑边界条件,while fast and fast.next ,这俩个判断条件不可以缺少。辅助空间法巧妙到用到了集合的特性
142. 环形链表 二 (8.12,13)
1. 思路
- 如何来求解这个位置
- 辅助空间
- 用一个set把访问过的节点存起来
- 如果有重复的,则返回节点
- 遍历完没有,返回none
- 双指针两次相遇
- 第一次相遇判断是否有环
- 第二次相遇寻找位置
- 设slow走到环节点时走了k,那么fast走了2k,在环中走了k
- 设fast在环中走了k之后还要走x,那么slow在环中走了x和fast相遇
- 则第一次相遇时slow和fast距环节点k
- 而head距环节点也为k
- 则将一个指针从head走到环节点为k,slow走到环节点也为k
- 第二次相遇在环节点
2. 辅助空间
class Solution:
def detectCycle(self, head):
temp = set()
node = head
while node:
if node in temp:
return node
else:
temp.add(node)
node = node.next
return None
3. 双指针二次相遇
class Solution:
def detectCycle(self, head):
fast, slow = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
fast = head
while fast != slow:
fast, slow = fast.next, slow.next
return fast
return None
4. 总结
辅助空间和上一个判断是否有环没有太大区别,但是双指针法变成了二次相遇,如何可以让两个指针相遇到环节点的位置是需要好好思考的。
24. 反转链表(8.13)
1. 思路
- 双指针
- pre的next指向cur,实现一次局部反转
- 反转后,每次往前移动一个位置
- 递归
- 找终止条件
- head == null 或 head.next == null
- 处理逻辑
- head.next.next = head
2. 双指针
class Solution:
def reverseList(self,head):
pre = None
cur = head
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
3. 递归
class Solution:
def reverseList(self, head):
if (head === None or head.next == None):
return head
cur = self.reverseList(head.next)
head.next.next = head
head.next = None
return cur
4. 总结
反转链表,双指针比较好想一些,递归要注意结束条件和处理的逻辑,head.next.next = head,并且要把head.next 置空,否则会出现循环的错误
- head.next.next = head
- 找终止条件
25. 合并两个排序的链表
1. 思路
- 判断l1,l2的值,小一些的添加到新链表中,然后往回移动一位
- 伪节点
- 建立一个新链表,设置一个伪节点来返回链表
- 判断l1和l2的值,添加到新链表的后面
- 递归
- 返回l1指向的结点和l2指向的结点中,值较小的结点
- 递归调用
2. 伪节点
class Solution:
def mergeTwoLists(self, l1, l2):
dummy = cur = ListNode(0)
while l1 and l2:
if l1.val < l2.val:
cur.next, l1 = l1, l1.next
else:
cur.next, l2 = l2, l2.next
cur = cur.next
cur.next = l1 if l1 else l2
return dummy.next
3. 递归
class Solution:
def mergeTwoLists(self, l1, l2):
if not l1:
return l2
elif not l2:
return l1
elif l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
4. 总结
这道题要注意哑节点的使用,是为了返回这个新链表,因为cur随着链表的添加已经到了最后。