链表篇
06. 从尾到头打印链表
- 思路1:直接遍历链表,存到数组后,利用数组逆序即可
- 思路2:链表+逆序 自然想到使用递归
#思路1:遍历
class Solution(object):
def reversePrint(self, head):
nums = []
while(head):
nums.append(head.val)
head = head.next
return nums[::-1]
#思路2:递归
class Solution:
def __init__(self):
self.nums = []
def reversePrint(self, head):
self.my_reverse(head)
return self.nums
def my_reverse(self,head):
if(not head): return
self.my_reverse(head.next)
self.nums.append(head.val)
总结:对于链表和二叉树类型的题目,可以采取递归(费空间)的方式,特别是题目出现逆序的情况下。
206. 反转链表
- 思路1:迭代写法,利用pre、cur双指针完成反转
- 思路2:链表+逆序 自然想到使用递归
# 迭代
class Solution(object):
def reverseList(self, head):
pre,cur = None,head
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
# 递归
class Solution(object):
def reverseList(self, head):
if not head or not head.next: return head
ret = self.reverseList(head.next)
head.next.next = head
head.next = None
return ret
总结:链表经常采取双指针pre、cur
92. 反转链表II
- 思路1:引入哨兵节点,然后记录left的前一个节点和right的下一个节点,对left和right之间的节点进行局部反转
# 迭代
class Solution(object):
def reverseBetween(self, head, left, right):
auxi = ListNode(0,head)
cnt = 0
pre,cur = auxi,head
start,end,start2 = None,None,None
while cur:
cnt += 1
if cnt > right: break
tmp = cur.next
if cnt >= left:
if cnt == right: end = tmp
if cnt ==left:
start = pre
start2 = cur
elif cnt>left and cnt <= right:
cur.next = pre
pre = cur
cur = tmp
start.next = pre
start2.next = tmp
return auxi.next
总结:头节点不确定,通常引入哨兵节点
234. 回文链表
- 思路1:快慢指针对链表二分,然后对链表后半部分采取反转链表,最后一一比较
- 思路2:用额外数组记录链表节点值,然后判断回文数组
- 思路3:回文链表涉及到逆序,可以考虑递归(费空间)
# 链表二分
class Solution(object):
def isPalindrome(self, head):
fast,slow = head,head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
pre,cur = None,slow
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
while pre and head:
if pre.val!=head.val:
return False
pre = pre.next
head = head.next
return True
# 额外数组
class Solution(object):
def isPalindrome(self, head):
ret = []
while head:
ret.append(head.val)
head = head.next
return ret == ret[::-1]
# 递归
class Solution(object):
def __init__(self):
self.cur = None
def isPalindrome(self, head):
self.cur = head
return self.dfs(head)
def dfs(self,head):
if not head: return True
a = self.dfs(head.next)
if self.cur.val == head.val:
self.cur = self.cur.next
return a
return False
总结:链表题目涉及到 前半部分和后半部分概念时,采取快慢指针对链表进行二分(回文链表、链表归并排序、重排链表都有这个思想)
18. 删除链表的节点
- 思路1:引入哨兵节点,采取双指针pre、cur分别记录待删除节点的前一个节点和待删除节点
class Solution(object):
def deleteNode(self, head, val):
ret = ListNode(0)
ret.next = head
pre,cur = ret,head
while cur.val!=val:
pre = cur
cur = cur.next
pre.next = cur.next
return ret.next
总结:头结点不确定时,可引入哨兵节点
237. 删除链表中的节点
- 思路1:把下一个节点的值拷贝到当前节点,然后删除下一个节点
class Solution(object):
def deleteNode(self, node):
node.val = node.next.val
node.next = node.next.next
83. 删除排序链表中的重复元素
- 思路1:如果cur和cur.next值一样,就持续删除,否则更新cur
class Solution(object):
def deleteDuplicates(self, head):
if(not head): return None
cur = head
while(cur.next):
if cur.val == cur.next.val:
cur.next = cur.next.next
else:
cur = cur.next
return head
82. 删除排序链表中的重复元素II
- 思路1:引入哨兵节点,采取pre、cur双指针,借助flag标志位来判断哪些节点需要删除
- 思路2:引入哨兵节点,采取pre、cur双指针,只要相邻节点值一样,就用while循环找到相邻节点不一样的位置,然后再考虑更新pre、cur
# 思路一
class Solution(object):
def deleteDuplicates(self, head):
if not head or not head.next: return head
auxi = ListNode(0,next=head)
pre,cur = auxi,head
flag = False
while cur and cur.next:
if cur.val == cur.next.val:
cur = cur.next
flag = True
else:
if flag:
flag = False
cur = cur.next
else:
pre.next = cur
pre = cur
cur = cur.next
if flag: pre.next = cur.next
else: pre.next = cur
return auxi.next
# 思路二
class Solution(object):
def deleteDuplicates(self, head):
if not head or not head.next: return head
auxi = ListNode(0,next=head)
pre,cur = auxi,head
while cur and cur.next:
if cur.val == cur.next.val:
while cur.next and cur.val==cur.next.val:
cur = cur.next
cur = cur.next
pre.next = cur
else:
pre = cur
cur = cur.next
return auxi.next
总结:头结点不确定时,可引入哨兵节点
203. 移除链表元素
- 思路1:引入哨兵节点,采取pre、cur,根据cur值是否等于val来更新pre、cur
class Solution(object):
def removeElements(self, head, val):
auxi = ListNode(0,next=head)
pre,cur = auxi,head
while cur:
tmp = cur.next
if cur.val == val:
pre.next = tmp
else:
pre = cur
cur = tmp
return auxi.next
总结:头结点不确定时,可引入哨兵节点
160. 相交链表
- 思路1:利用双指针以及两个链表的长度之和是固定的
- 思路2:集合记录访问过的节点,如果重复则相交
# 双指针
class Solution(object):
def getIntersectionNode(self, headA, headB):
cur1,cur2 = headA,headB
while(cur1!=cur2):
cur1 = cur1.next if cur1 else headB
cur2 = cur2.next if cur2 else headA
return cur1
# hash额外空间
class Solution(object):
def getIntersectionNode(self, headA, headB):
mySet = set()
cur = headA
while cur:
mySet.add(cur)
cur = cur.next
cur = headB
while cur:
if cur in mySet: return cur
cur = cur.next
return None