剑指offer刷题记录
题目link
Day 1: 栈与队列
1.用两个栈实现队列
题目描述:
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数:
appendTail 在队列尾部插入整数
deleteHead 在队列头部删除整数的功能。(若队列中没有元素,返回 -1 )
题解:
使用stack 1作为队列,stack 2作为辅助栈。
插入:先将stack 1中的元素逆序移到stack 2中,在stack 1中添加新元素,然后将stack 2中的元素逆序移回stack 2.
删除:直接在stack 2队尾进行删除元素。
pop():移除列表中最后一个元素并返回元素值。
class CQueue:
def __init__(self):
self.A=[]
self.B=[]
#箭头指向表示返回值类型
def appendTail(self, value: int) -> None:
#stack1→stack2
while self.A:
self.B.append(self.A.pop())
#加入新元素
self.A.append(value)
#stack2→stack1
while self.B:
self.A.append(self.B.pop())
def deleteHead(self) -> int:
if self.A:
return self.A.pop()
else:
return -1
1.包含min函数的栈
题目描述:
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
题解:
使用辅助栈minstack保存当前栈的最小值。
push时通过判断更新minstack中的值
pop时判断删除的值是否需要在minstack中删除
min只需要返回minstack最后一个元素
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.stack,self.minstack=[],[]#储存当前栈的最小值
def push(self, x: int) -> None:
self.stack.append(x)
if not self.minstack or x<=self.minstack[-1]:
#注意此处应该用<=而不是<
self.minstack.append(x)
def pop(self) -> None:
if self.stack.pop()==self.minstack[-1]:
#证明上一个推入的值是最小值,需要删除
self.minstack.pop()
def top(self) -> int:
return self.stack[-1]
def min(self) -> int:
return self.minstack[-1]
Day 2: 链表
链表指的是一系列节点,每个节点储存数值以及下一个节点的指针。
1.链表的反转
题目描述:
1)输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
2)定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
题目的区别是
1)返回的是反转后的值组成的数组。
2)将整个链表反转,同时返回翻转后的头节点。
(这里容易被页面上显示的输入输出误导,实际最后输出的只有翻转后的头节点)
题解:
1)递归
当head不为空时,继续调用函数,将对应的值连接在列表末尾。
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
#结束递归的条件
if head:
return self.reversePrint(head.next)+[head.val]
else:
return []
2)
方法一:迭代(双指针)
pre:前一个元素
cur:当前元素
tmp:下一个元素
通过迭代的方式更改链表每一个元素指针的朝向(将cur.next由原来的temp改成pre),然后向前继续迭代,更改下一个元素。最后返回链表最末尾的元素。
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
cur, pre = head, None
while cur:
tmp = cur.next # 暂存后继节点 cur.next
cur.next = pre # 修改 next 引用指向
pre = cur # pre 暂存 cur
cur = tmp # cur 访问下一节点
return pre
方法二:递归(这里没太懂)
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
def recur(cur, pre):
if not cur: return pre # 终止条件
res = recur(cur.next, cur) # 递归后继节点
cur.next = pre # 修改节点引用指向
return res # 返回反转链表的头节点
return recur(head, None) # 调用递归并返回
#https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/solution/jian-zhi-offer-24-fan-zhuan-lian-biao-die-dai-di-2/
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
newHead = self.reverseList(head.next)
head.next.next = head
head.next = None
return newHead
#https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/solution/shi-pin-tu-jie-jian-zhi-offer-24-fan-zhu-oym7/
Day 3:字符串
1.替换空格
题目描述
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
题解
通过判断语句判断空格
class Solution:
def replaceSpace(self, s: str) -> str:
out_str=''
for i in s:
if i ==' ':
out_str+='%20'
else:
out_str+=i
return out_str
2.左旋转字符
题目描述
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
题解
方法一:切片-最简单
注意字符串是可以直接索引的
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return s[n:] + s[:n]
方法二:遍历拼接-不允许使用切片时可以使用
注意此处取余的做法很巧妙
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
res = []
for i in range(n, n + len(s)):
res.append(s[i % len(s)])
return ''.join(res)
也可以直接使用字符串(如果不允许使用join)
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
res = ""
for i in range(n, n + len(s)):
res += s[i % len(s)]
return res