牛客刷题day5
文章目录
1.链表中环的入口节点
题目
对于一个给定的链表,返回环的入口节点,如果没有环,返回null
拓展:
你能给出不利用额外空间的解法么?
解题思路
快慢指针方法:将两指针分别放在链表头(X)和相遇位置(Z),并改为相同速度推进,则两指针在环开始位置相遇(Y),如图所示。
快指针与慢指针均从X出发,在Z相遇。此时,慢指针行使距离为a+b,快指针为a+b+n(b+c)。
所以2*(a+b)=a+b+n*(b+c),推出
a=(n-1)b+nc=(n-1)(b+c)+c;
得到,将此时两指针分别放在起始位置和相遇位置,并以相同速度前进,当一个指针走完距离a时,另一个指针恰好走出 绕环n-1圈加上c的距离。也就是说二者又会在Y点相遇,而Y点就是环的入口。
判断链表是否有环有三种方法,这种方法最巧妙也是最常见的。具体的可参照博客 ,里面详细介绍了三种方法。判断链表中是否有环的三种方法
核心代码
class Solution:
def detectCycle(self, head):
if not head or not head.next:
return
# write code here
slow = head
fast = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if slow == fast:
fast = head
while fast != slow:
fast = fast.next
slow = slow.next
return slow
return
2. 删除有序链表中的重复元素
题目
删除给出链表中的重复元素(链表中元素从小到大有序),使链表中的所有元素都只出现一次
例如:
给出的链表为1→1→2,返回1 1→2.
给出的链表为1→1→2→3→3,返回1→2→3.
解题思路
直接遍历链表,删除重复元素即可
class Solution:
def deleteDuplicates(self, head):
if not head:
return head
p = head
while p.next:
if p.val== p.next.val:
p.next= p.next.next
else:
p = p.next
return head
3.平衡二叉树
题目
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
解题思路
判断一个数是否为平衡二叉树。平衡二叉树是左子树的高度与右子树的高度差的绝对值小于等于1,同样左子树是平衡二叉树,右子树为平衡二叉树。
根据定义,如果我们能够求出以每个结点为根的树的高度,然后再根据左右子树高度差绝对值小于等于1,,就可以判断以每个结点为根的树是否满足定义
核心代码
class Solution:
def IsBalanced_Solution(self, pRoot):
if not pRoot:
return True
leftDepth = self.depth(pRoot.left)
rightDepth = self.depth(pRoot.right)
depth = abs(leftDepth - rightDepth)
if depth <=1 and self.IsBalanced_Solution(pRoot.left)and self.IsBalanced_Solution(pRoot.right):
return True
return False
def depth(self, root):
if not root:
return 0
depth = max(self.depth(root.left), self.depth(root.right)) + 1
return depth
4.股票无数次交易获得最大收益
题目
假定你知道某只股票每一天价格的变动。
你最多可以同时持有一只股票。但你可以无限次的交易(买进和卖出均无手续费)。
请设计一个函数,计算你所能获得的最大收益。
解题思路
只要第二天卖出价格大于第一天买入价格就能获得利润
不限制交易次数 只要将获得利润全部相加就能保证利润最大化(第二天价格大于第一天价格)
核心代码
class Solution:
def maxProfit(self , prices ):
# write code here
if not prices:
return 0
profit = 0
for i,price in enumerate(prices):
if i>0 and price>prices[i-1]:
profit+=price-prices[i-1]
return profit
5. 股票交易最大收益(只能进行两次交易)
题目:
假定你知道某只股票每一天价格的变动。
你最多可以同时持有一只股票。但你最多只能进行两次交易(一次买进和一次卖出记为一次交易。买进和卖出均无手续费)。
请设计一个函数,计算你所能获得的最大收益
输入:[8,9,3,5,1,3]
输出:4
备注:第三天买进,第四天卖出,第五天买进,第六天卖出。总收益为4。
解题思路
这个题其实考察的就是动态规划的思想:
通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决
我们仔细分解这个问题:
首先要取得最大利润,那么第一次和第二次的利润都最大,而股票第二次交易是建立在第一次交易上,第一次交易利润越高,那么第二次购入股票成本最低,将整个问题分解:
第一次购入股票:如果第一次成本最低,要么就是当天的价格,要么就是取整个交易过程中价格最低的那一天
第一次利润最大:要么就是取交易过程中利润最大的 要么就是当日交易价格减去第一次的成本价
第二次交易是建立在第一次之上的:
第二次购入股票成本价:第二次买入的成本就是当前买入的价格减去第一次交易所赚取的利润
那么第二次交易完总利润最大:第二次卖出股票价格减去第二次购入股票最小的成本
那么整个过程中只要执行上面交易规则,最后的利润一定是最大的
核心代码:
class Solution:
def maxProfit(self , prices ):
# write code here
buy1 = buy2 = float('inf')
profit_buy1 = profit_all = 0
for price in prices:
# 第一次买入要求买入的成本最低
# 如果第一次成本最低,要么就是当前的价格,要么就是取整个交易过程中价格最低的那一天
buy1 = min(buy1,price)
# 要求第一次利润最大
# 要么就是取交易过程中利润最大的 要么就是当日交易价格减去第一次的成本价
profit_buy1 =max(profit_buy1,price-buy1)
#第二次买入的成本价就是当前买入的价格减去第一次交易所赚取的利润
buy2 = min(buy2,price-profit_buy1)
# 总利润 就是 当前卖出价格减去第一次的成本价
profit_all = max(profit_all, price-buy2)
return profit_all
6.二叉树根节点到子节点等于指定的数字
题目:
给定一个二叉树和一个值sum,请找出所有的根节点到叶子节点的节点值之和等于 sum 的路径,
例如:
给出如下的二叉树, sum=22
返回
[[5,4,11,2],[5,8,9]]
解题思路
使用二叉树的先序遍历进行递归就好
核心代码
class Solution:
def pathSum(self, root, sum):
# write code here
if not root:
return []
res = []
current = 0
path = []
self.preOrder(root, sum, res, [root.val], current)
return res
def preOrder(self, root, sum, res, path, current):
if not root:
return
current += root.val
if sum == current and not root.left and not root.right:
res.append(path)
if root.left:
self.preOrder(root.left, sum, res, path + [root.left.val], current)
if root.right:
self.preOrder(root.right, sum, res, path + [root.right.val], current)