文章目录
题目来源:牛客网
1.合并两个有序链表
class Solution:
def Merge(self , pHead1: ListNode, pHead2: ListNode) -> ListNode:
# write code here
if not pHead1: return pHead2
if not pHead2: return pHead1
result = ListNode(-1)
cur = result
while pHead1 and pHead2:
if pHead1.val <= pHead2.val:
cur.next = pHead1
pHead1 = pHead1.next
else:
cur.next = pHead2
pHead2 = pHead2.next
cur = cur.next
cur.next = pHead1 if pHead1 else pHead2
return result.next
错误解答:(错在哪里)
class Solution:
def Merge(self , pHead1: ListNode, pHead2: ListNode) -> ListNode:
# write code here
if not pHead1: return pHead2
if not pHead2: return pHead1
dummy = res = ListNode(0)
while pHead1 and pHead2:
if pHead1.val < pHead2.val:
res.next = pHead1
pHead1 = pHead1.next
if pHead2.val <= pHead1.val:
res.next = pHead2
pHead2 = pHead2.next
res = res.next
if pHead1:
res.next = pHead1
res = res.next
if pHead2:
res.next = pHead2
res = res.next
return dummy.next
错误原因:连续执行两个条件语句,会使得上述条件while pHead1 and pHead2不再成立。因此,将后者的条件语句换做else 或者elif语句可以执行。
2.两个链表的第一个公共结点
class Solution:
def FindFirstCommonNode(self , pHead1 , pHead2):
# write code here
point1 = pHead1
point2 = pHead2
while point1 != point2:
point1 = point1.next if point1 else pHead2
point2 = point2.next if point2 else pHead1
return point1
错误做法:比较point1.val != point2.val
第二次做的时候发现忘记了将头节点暂时使用point保存下来。
3.链表中倒数最后k个结点
使用列表,保存每个遍历的节点,内存空间消耗太大。
class Solution:
def FindKthToTail(self , pHead: ListNode, k: int) -> ListNode:
# write code here
res = []
while pHead:
res.append(pHead)
pHead = pHead.next
if k <= len(res) and k != 0:
return res[-k]
else:
return None
采用快慢指针
快指针比慢指针多走k步,当快指针走完时,慢指针的位置就是当前链表的倒数第k个节点。
class Solution:
def FindKthToTail(self , pHead: ListNode, k: int) -> ListNode:
# write code here
fast = low = pHead
for i in range(k):
try:
fast = fast.next
except:
return None
while fast:
fast = fast.next
low = low.next
return low
4.反转链表
错误做法:
class Solution:
def ReverseList(self, head: ListNode) -> ListNode:
res = ListNode(-1)
cur = head
while cur:
temp = cur.next
cur.next = res
cur = temp
# res = res.next
return res
正确做法:
class Solution:
def ReverseList(self, head: ListNode) -> ListNode:
pre, cur = None, head
while cur:
temp = cur.next #保存下一个节点
cur.next = pre #当前节点指向pre节点
pre = cur
cur = temp #当前节点更新为下一节点
return pre
5.删除链表某一个节点 (重点)
class Solution:
def deleteNode(self , head: ListNode, val: int) -> ListNode:
# write code here
cur = res = ListNode(-1)
while head:
if head.val != val:
cur.next = head
cur = cur.next
head = head.next
return res.next
第二次做的时候想法不是新建一个链表进行
6.删除链表重复节点
正确解法:
重复元素可以考虑使用字典来进行处理,然而缺点是遍历数据2遍,内存空间以及时间代价都不友好。
class Solution:
def deleteDuplication(self , pHead: ListNode) -> ListNode:
# write code here
if not pHead: return None
cur = res = ListNode(-1)
resu = dict()
while pHead:
if pHead.val not in resu:
resu[pHead.val] = 1
else:
resu[pHead.val] += 1
pHead = pHead.next
for key, val in resu.items():
if val == 1:
cur.next = ListNode(key)
cur = cur.next
return res.next
解法2:
class Solution:
def deleteDuplication(self , pHead: ListNode) -> ListNode:
# write code here
if pHead == None:
return None
# 创建一个空表,指向表头
res = ListNode(-1)
res.next = pHead
cur = res
# 判断当前的表头是否和表头的下一个节点相同
while cur.next and cur.next.next:
if cur.next.val == cur.next.next.val:
temp = cur.next.val
while cur.next and cur.next.val == temp:
cur.next = cur.next.next
else:
cur = cur.next
return res.next
该过程可以用文字进行描述:
- 首先创建一个空节点,使得空节点指向表头。cur与res指向空节点。
- 比较cur的下一个节点和cur的下下一个节点的值是否相同
a. 若相同:
记录当前的节点值为temp
跳过所有的重复节点:遍历当前节点和后面的节点直至temp不等于下一个节点的值。
b. 若不同:
cur = cur.next - 返回当前头节点的下一个节点。
流程示意:
7.从尾到头打印链表
输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。
class Solution:
def printListFromTailToHead(self , listNode: ListNode) -> List[int]:
# write code here
res = []
while listNode:
res.append(listNode.val)
listNode = listNode.next
return res[::-1]
8.链表中环的入口结点 (重点)
采用字典进行求解:
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code her2
res = dict()
while pHead:
if pHead not in res:
res[pHead] = 1
else:
return pHead
pHead = pHead.next
return None
正确解法:
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code her2
slow, fast = pHead, pHead
while True:
if not fast or not fast.next: return
fast, slow = fast.next.next, slow.next
# 第一次相遇
if fast == slow: break
# 第二次相遇
pi = pHead
while pi != slow:
pi = pi.next
slow = slow.next
return pi
9.使用栈实现队列
class Solution:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, node):
self.stack1.append(node)
def pop(self):
if not self.stack2:
len_s = len(self.stack1)
for i in range(len_s):
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
10.栈的压入压出顺序
错误做法(错在哪里?)
class Solution:
def IsPopOrder(self , pushV: List[int], popV: List[int]) -> bool:
# write code here
# 引入一个辅助栈
res = []
ind = 0
for i, temp in enumerate(pushV):
res.append(temp)
while res[-1] == popV[ind]:
res.pop()
ind += 1
return True if not res else False
正确做法:
class Solution:
def IsPopOrder(self , pushV: List[int], popV: List[int]) -> bool:
# write code here
# 引入一个辅助栈
res = []
ind = 0
for i, temp in enumerate(pushV):
res.append(temp)
while res and res[-1] == popV[ind]:
res.pop()
ind += 1
return True if not res else False
11.翻转单词序列
class Solution:
def ReverseSentence(self , str: str) -> str:
# write code here
s = str.strip() # 删除字符串前后空格
s = s.split() # 字符串分割
s.reverse() # 字符串顺序反转
return ' '.join(s) # 字符串连接
12.滑动窗口的最大值
下面是最直观的想法,问题是会超时。
class Solution:
def maxInWindows(self , num: List[int], size: int) -> List[int]:
# write code here
res = []
ind = 0
for i in range(len(num)-size+1):
res.append(max(num[ind:ind+size]))
ind += 1
return res
引入双端列表正确做法:
错误的写法(错在哪里):
from collections import deque
class Solution:
def maxInWindows(self , num: List[int], size: int) -> List[int]:
# write code here
temp = deque()
res = []
win_size = 0
# 初始化双端列表
for i in range(size):
temp.append(num[i])
res.append(max(temp))
for val in num[size:]:
# 窗口大小+1
win_size += 1
temp.append(val)
# 当窗口大小超出时:
if win_size > size:
# 遍历所有元素,保证temp首元素最大
# 弹出首元素
temp.popleft()
win_size -= 1
while val > temp[0]:
temp.popleft()
else:
# 若val大于当前的窗口头节点值:
if val > temp[0]:
for i in range(len(temp)-1):
temp.popleft()
else:
temp.append(val)
res.append(temp[0])
return res