1、
剑指 Offer 05. 替换空格
难度简单
请实现一个函数,把字符串 s
中的每个空格替换成"%20"。
示例 1:
输入:s = "We are happy." 输出:"We%20are%20happy."
class Solution:
def replaceSpace(self, s: str) -> str:
new_s = s.split(" ")
new_s = "%20".join(new_s)
print(new_s)
return new_s
写的过程中,忘记怎么使用json了,主要是 "%20",是用什么来拼接列表,
2、
剑指 Offer 06. 从尾到头打印链表
难度简单
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2] 输出:[2,3,1]
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
output = []
while(head):
output.append(head.val)
head = head.next
output.reverse()
print(output)
return output
一开始while写的是 head.val != None 这是错误的,因为当head = head.next 最后一个的时候,head =None, 而None是没有val和next的
便于搜索,目标小的时候往左走,目标大的时候往右走
左小右大
DLR--前序遍历(根在前,从左往右,一棵树的根永远在左子树前面,左子树又永远在右子树前面 )
LDR--中序遍历(根在中,从左往右,一棵树的左子树永远在根前面,根永远在右子树前面)
LRD--后序遍历(根在后,从左往右,一棵树的左子树永远在右子树前面,右子树永远在根前面)
主要是根的顺序,前序就是,先找根,中序就是,第二个是根,后序就是,最后一个是根
都是从左到右开始
3、
剑指 Offer 07. 重建二叉树
难度中等
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] Output: [3,9,20,null,null,15,7]
示例 2:
Input: preorder = [-1], inorder = [-1] Output: [-1]
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
if not preorder:
return
root = TreeNode(preorder[0])
i = inorder.index(preorder[0])
root.left = self.buildTree(preorder[1:i+1],inorder[:i])
root.right = self.buildTree(preorder[i+1:],inorder[i+1:])
return root
主要是 先找到主要的根,然后将其分开左子树和右子树。进行递归。
每个左右数都可以作为根节点,如上一个左子树点,连接着当前的根。
4、
剑指 Offer 20. 表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
- 若干空格
- 一个 小数 或者 整数
- (可选)一个
'e'
或'E'
,后面跟着一个 整数 - 若干空格
小数(按顺序)可以分成以下几个部分:
- (可选)一个符号字符(
'+'
或'-'
) - 下述格式之一:
- 至少一位数字,后面跟着一个点
'.'
- 至少一位数字,后面跟着一个点
'.'
,后面再跟着至少一位数字 - 一个点
'.'
,后面跟着至少一位数字
- 至少一位数字,后面跟着一个点
整数(按顺序)可以分成以下几个部分:
- (可选)一个符号字符(
'+'
或'-'
) - 至少一位数字
部分数值列举如下:
["+100", "5e2", "-123", "3.1416", "-1E-16", "0123"]
部分非数值列举如下:
["12e", "1a3.14", "1.2.3", "+-5", "12e+5.4"]
示例 1:
输入:s = "0" 输出:true
示例 2:
输入:s = "e" 输出:false
示例 3:
输入:s = "." 输出:false
示例 4:
输入:s = " .1 " 输出:true
提示:
1 <= s.length <= 20
s
仅含英文字母(大写和小写),数字(0-9
),加号'+'
,减号'-'
,空格' '
或者点'.'
。
class Solution(object):
def isNumber(self, s):
"""
:type s: str
:rtype: bool
"""
try:
float(s)
except:
return False
return True
class Solution:
def isNumber(self, s: str) -> bool:
s = s.strip()
return re.search(r"^[\+-]?\d+\.?\d*([eE][\+-]?\d+)?$|^[+-]?\.\d+([eE][\+-]?\d+)?$", s) is not None
5、
剑指 Offer 67. 把字符串转换成整数
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
输入: "42" 输出: 42
示例 2:
输入: " -42" 输出: -42 解释: 第一个非空白字符为 '-', 它是一个负号。 我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: "4193 with words" 输出: 4193 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4:
输入: "words and 987" 输出: 0 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 因此无法执行有效的转换。
示例 5:
输入: "-91283472332" 输出: -2147483648 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (−231) 。
class Solution(object):
def strToInt(self, s):
"""
:type str: str
:rtype: int
"""
s = s.strip()
# if ' ' in s:return 0
pattern = r"^([\+-]?\d+)"
result = re.search(pattern,s)
if result is not None:
result = int(result.groups(1)[0])
if result < -2**31 :
return -1*2**31
elif result > 2**31-1:
return 2**31-1
return result
else:return 0
若不使用 trim() / strip()
方法,而从头开始遍历字符串,则可以将空间复杂度降低至 O(1)O(1)O(1) ,代码如下
class Solution(object):
def strToInt(self, str):
res, i, sign, length = 0, 0, 1, len(str)
int_max, int_min, bndry = 2 ** 31 - 1, -2 ** 31, 2 ** 31 // 10
if not str: return 0 # 空字符串,提前返回
while str[i] == ' ':
i += 1
if i == length: return 0 # 字符串全为空格,提前返回
if str[i] == '-': sign = -1
if str[i] in '+-': i += 1
for c in str[i:]:
if not '0' <= c <= '9' : break
if res > bndry or res == bndry and c > '7':
return int_max if sign == 1 else int_min
res = 10 * res + ord(c) - ord('0')
return sign * res
第二种在空间和时间复杂度上 都要优于第一种。
6、
从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2] 输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def reversePrint(self, head):
return reversePrint(head.next)+[head.val] if head is not None []
# class Solution(object):
# def reversePrint(self, head):
# """
# :type head: ListNode
# :rtype: List[int]
# """
# llist = []
# while(head is not None):
# llist.append(head.val)
# head = head.next
# return llist[::-1]
7、
剑指 Offer 24. 反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
限制:
0 <= 节点个数 <= 5000
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
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) # 调用递归并返回
8、
Offer 35. 复杂链表的复制
请实现 copyRandomList
函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next
指针指向下一个节点,还有一个 random
指针指向链表中的任意节点或者 null
。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]] 输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]] 输出:[[3,null],[3,0],[3,null]]
示例 4:
输入:head = [] 输出:[] 解释:给定的
class Solution:
def copyRandomList(self,head:'Node') -> 'Node':
if not head: return
dic = {}
# 3.复制个节点,并建立”原节点->新节点“的map映射
cur = head
while cur:
dic[cur] = Node(cur.val)
cur = cur.next
cur = head
# 4. 构建新节点的next和random指向
while cur:
dic[cur].next = dic.get(cur.next)
dic[cur].random = dic.get(cur.random)
cur = cur.next
# 5.返回新链表的头节点
return dic[head]
链表为空(空指针),因此返回 null。
提示:
-10000 <= Node.val <= 10000
Node.random
为空(null)或指向链表中的节点。- 节点数目不超过 1000 。
8 18. 删除链表的节点
9 355. 设计推特
设计一个简化版的推特(Twitter),可以让用户实现发送推文,关注/取消关注其他用户,能够看见关注人(包括自己)的最近 10
条推文。
实现 Twitter
类:
Twitter()
初始化简易版推特对象void postTweet(int userId, int tweetId)
根据给定的tweetId
和userId
创建一条新推文。每次调用此函数都会使用一个不同的tweetId
。List<Integer> getNewsFeed(int userId)
检索当前用户新闻推送中最近10
条推文的 ID 。新闻推送中的每一项都必须是由用户关注的人或者是用户自己发布的推文。推文必须 按照时间顺序由最近到最远排序 。void follow(int followerId, int followeeId)
ID 为followerId
的用户开始关注 ID 为followeeId
的用户。void unfollow(int followerId, int followeeId)
ID 为followerId
的用户不再关注 ID 为followeeId
的用户。
示例:
输入 ["Twitter", "postTweet", "getNewsFeed", "follow", "postTweet", "getNewsFeed", "unfollow", "getNewsFeed"] [[], [1, 5], [1], [1, 2], [2, 6], [1], [1, 2], [1]] 输出 [null, null, [5], null, null, [6, 5], null, [5]] 解释 Twitter twitter = new Twitter(); twitter.postTweet(1, 5); // 用户 1 发送了一条新推文 (用户 id = 1, 推文 id = 5) twitter.getNewsFeed(1); // 用户 1 的获取推文应当返回一个列表,其中包含一个 id 为 5 的推文 twitter.follow(1, 2); // 用户 1 关注了用户 2 twitter.postTweet(2, 6); // 用户 2 发送了一个新推文 (推文 id = 6) twitter.getNewsFeed(1); // 用户 1 的获取推文应当返回一个列表,其中包含两个推文,id 分别为 -> [6, 5] 。推文 id 6 应当在推文 id 5 之前,因为它是在 5 之后发送的 twitter.unfollow(1, 2); // 用户 1 取消关注了用户 2 twitter.getNewsFeed(1); // 用户 1 获取推文应当返回一个列表,其中包含一个 id 为 5 的推文。因为用户 1 已经不再关注用户 2
提示:
1 <= userId, followerId, followeeId <= 500
0 <= tweetId <= 104
- 所有推特的 ID 都互不相同
postTweet
、getNewsFeed
、follow
和unfollow
方法最多调用3 * 104
次
class Twitter(object):
def __init__(self):
self.posttweet=defaultdict(list)
self.follows=defaultdict(set)
self.messageMax = 10
self.time = 0
def postTweet(self, userId, tweetId):
"""
:type userId: int
:type tweetId: int
:rtype: None
"""
# 发送推文,将信息存储到相应用户的发送推特列表中
self.time +=1
self.posttweet[userId].append((tweetId,self.time))
if not self.follows.get(userId,None):
self.follows[userId].add(userId)
def getNewsFeed(self, userId):
"""
:type userId: int
:rtype: List[int]
根据题目要求返回前10个相近的推文id
"""
# 首先判断posttweet发推特的存储信息字典中是否存在记录,没有的话,就返回空列表
if len(self.posttweet)==0:
return []
# 判断关注表中,是否存在userID,如果不存在就添加关注列表,并添加自己作为第一个关注者
if not self.follows.get(userId,None):
self.follows[userId].add(userId)
followee = self.follows[userId]
# 将关注表中所有的人发过的tweet存到一个list中
resp = [self.posttweet[i] for i in followee if self.posttweet.get(i,None) ]
# 将每个人的推特消息记录降维
rre = [re for res in resp for re in res]
# sort 根据时间进行排序
re = sorted(rre,key=lambda x: x[1], reverse=True)
# 将排序后的推特消息id存储到列表中
res = [id for id,t in re]
# res = []
# for id,t in re:
# res.append(id)
return res[:self.messageMax]
def follow(self, followerId, followeeId):
"""
:type followerId: int
:type followeeId: int
:rtype: None
"""
# 判断,如果followId中不存在查询followerId的关注列表,就创建一个,
if not self.follows.get(followerId,None):
# 初始化,先将自己作为一个关注对象
self.follows[followerId].add(followerId)
# 增加目标followeeId至follerId的关注列表
self.follows[followerId].add(followeeId)
else:
# 判断,如果followId中存在查询followerId的关注列表,增加目标followeeId至follerId的关注列表
if not followeeId in self.follows[followerId]:
self.follows[followerId].add(followeeId)
def unfollow(self, followerId, followeeId):
"""
:type followerId: int
:type followeeId: int
:rtype: None
"""
# 判断,如果followerId的关注列表中有这个人就移除,没有的话就不做操作
if followeeId in self.follows[followerId]:
self.follows[followerId].remove(followeeId)
10、
875. 爱吃香蕉的珂珂
珂珂喜欢吃香蕉。这里有 n
堆香蕉,第 i
堆中有 piles[i]
根香蕉。警卫已经离开了,将在 h
小时后回来。
珂珂可以决定她吃香蕉的速度 k
(单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k
根。如果这堆香蕉少于 k
根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。
珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。
返回她可以在 h
小时内吃掉所有香蕉的最小速度 k
(k
为整数)。
示例 1:
输入:piles = [3,6,7,11], h = 8 输出:4
示例 2:
输入:piles = [30,11,23,4,20], h = 5 输出:30
示例 3:
输入:piles = [30,11,23,4,20], h = 6 输出:23
class Solution(object):
def minEatingSpeed(self, piles, h):
"""
:type piles: List[int]
:type h: int
:rtype: int
如果用整数计算代替if-else 计算速度会大大提高
"""
k_min = ((sum(piles)+h-1)//h)
k_max = max(piles)
while(k_min<=k_max):
k_mid = (k_min+k_max)//2
h_ = sum((pile+k_mid-1)//k_mid for pile in piles)
if h_ >h:
k_min = k_mid+1
else:
k_max = k_mid-1
return k_min
参见:力扣
11、
剑指 Offer 25. 合并两个排序的链表
简单
356
相关企业
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
if l1 == None and l2 == None:
return None
elif l1 !=None and l2 ==None:
return l1
elif l1 ==None and l2 !=None:
return l2
if l1.val < l2.val:
l3 = ListNode(l1.val)
l1 = l1.next
else:
l3 = ListNode(l2.val)
l2 = l2.next
head = l3
while(l1 or l2):
if l1 != None and l2 !=None:
if (l1.val < l2.val):
l3.next = l1
l1 = l1.next
else:
l3.next = l2
l2 = l2.next
elif l1 !=None and l2 ==None:
l3.next = l1
l1 = l1.next
elif l2 !=None and l1 ==None:
l3.next = l2
l2 = l2.next
if l3== None:
break
l3 = l3.next
return head
官方答案:
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
cur = dum = 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 dum.next
12、
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。
示例:
输入:nums = [1,2,3,4] 输出:[1,3,2,4] 注:[3,1,2,4] 也是正确的答案之一。
# class Solution:
# def exchange(self, nums: List[int]) -> List[int]:
# qishuList, oushuList= [],[]
# [oushuList.append(num) if num %2 == 0 else qishuList.append(num) for num in nums]
# return qishuList+oushuList
# class Solution:
# def exchange(self, nums: List[int]) -> List[int]:
# ll = sorted(nums,key=lambda x: x%2,reverse=True)
# return ll
# class Solution:
# def exchange(self, nums: List[int]) -> List[int]:
# left, right = 0, len(nums) - 1
# while left < right:
# while left < right and nums[left] % 2 == 1:
# left += 1
# while left < right and nums[right] % 2 == 0:
# right -= 1
# if left < right:
# nums[left], nums[right] = nums[right], nums[left]
# left += 1
# right -= 1
# return nums
class Solution:
def exchange(self, nums: List[int]) -> List[int]:
i, j = 0, len(nums) - 1
while i < j:
while i < j and nums[i] & 1 == 1: i += 1
while i < j and nums[j] & 1 == 0: j -= 1
nums[i], nums[j] = nums[j], nums[i]
return nums
13、
Offer 57. 和为s的两个数字
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[2,7] 或者 [7,2]
示例 2:
输入:nums = [10,26,30,31,47,60], target = 40 输出:[10,30] 或者 [30,10]
限制:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^6
# 超时
# class Solution:
# def twoSum(self, nums: List[int], target: int) -> List[int]:
# for i,num in enumerate(nums) :
# res = target - num
# if res in nums[i:]:
# return [num,res]
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
right, left = 0, len(nums)-1
while(right<left):
num_sum = nums[right]+nums[left]
if num_sum <target :
right+=1
elif num_sum >target :
left -=1
else:
return nums[left],nums[right]
14、
剑指 Offer 58 - I. 翻转单词顺序
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。
示例 1:
输入: "the sky is blue
" 输出: "blue is sky the
"
示例 2:
输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: "a good example" 输出: "example good a" 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
说明:
- 无空格字符构成一个单词。
- 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
- 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
注意:本题与主站 151 题相同:力扣
注意:此题对比原题有改动
# class Solution:
# def reverseWords(self, s: str) -> str:
# s = s.strip()
# s = s.split(" ")
# s.reverse()
# return " ".join(s)
# class Solution:
# def reverseWords(self, s: str) -> str:
# s = s.strip()
# s = s.split(" ")
# ll = []
# for st in s:
# if len(st)==0:
# continue
# else:ll.insert(0,st)
# return ' '.join(ll)
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip() # 删除首尾空格
i = j = len(s) - 1
res = []
while i >= 0:
while i >= 0 and s[i] != ' ': i -= 1 # 搜索首个空格
res.append(s[i + 1: j + 1]) # 添加单词
while s[i] == ' ': i -= 1 # 跳过单词间空格
j = i # j 指向下个单词的尾字符
return ' '.join(res) # 拼接并返回
# s.split(" ")解决不了单词间多空格的问题,s.split()可以解决。。。
15、
剑指 Offer 30. 包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.min(); --> 返回 -3. minStack.pop(); minStack.top(); --> 返回 0. minStack.min(); --> 返回 -2.
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.stack = []
def push(self, x: int) -> None:
self.stack.append(x)
def pop(self) -> None:
self.stack.pop()
def top(self) -> int:
return self.stack[-1]
def min(self) -> int:
if len(self.stack)==0:
return []
else:
return min(self.stack)
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()
创建两个链表,一个进行存储正常链表,一个存储最小值链表
class MinStack:
def __init__(self):
"""
initialize your data structure here.
self.A 存储主要的链表
self.B 存储每次加进去的最大值
"""
self.A, self.B = [],[]
def push(self, x: int) -> None:
self.A.append(x)
if not self.B or self.B[-1] >=x:
self.B.append(x)
def pop(self) -> None:
if self.A[-1]==self.B[-1]:
self.B.pop()
self.A.pop()
def top(self) -> int:
return self.A[-1]
def min(self) -> int:
if len(self.B)==0:
return []
return self.B[-1]