问题说明
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) – 将元素 x 推入栈中。
pop() – 删除栈顶的元素。
top() – 获取栈顶元素。
getMin() – 检索栈中的最小元素。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/min-stack
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
完整代码
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.item = []
def push(self, x: int) -> None:
self.item.append(x)
def pop(self) -> None:
if len(self.item) > 0:
return self.item.pop()
else:
return 0
def top(self) -> int:
if len(self.item) != "":
return self.item[len(self.item)-1]
else:
return 0
def getMin(self) -> int:
if len(self.item) > 0:
return min(self.item)
else:
return 0
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
嗯,感觉有点小问题,参考别人代码后,发现要用两个列表来实现,由于题中要求在常数时间内检索栈中最小值,而min()消耗时间比较长,所以引入minStack列表存放最小值:
class MinStack(object):
def __init__(self):
"""
initialize your data structure here.
"""
self.stack = []
self.minStack = []
def push(self, x):
"""
:type x: int
:rtype: void
"""
self.stack.append(x)
if not self.minStack or self.minStack[-1]>=x:
self.minStack.append(x)
def pop(self):
"""
:rtype: void
"""
if self.minStack[-1]==self.stack[-1]:
del self.minStack[-1]
self.stack.pop()
def top(self):
"""
:rtype: int
"""
return self.stack[-1]
def getMin(self):
"""
:rtype: int
"""
return self.minStack[-1]
问题说明
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
完整代码
这题也没什么能分析的,很直观,如果有多余未匹配括号就报错,另外就是之前做过,点进leetcode链接直接看到之前写的了,然后重新想了下确实还比较快:
class Solution:
def isValid(self, s):
d = {'}': '{', ']': '[', ')': '('}
blank = [' ']
for c in s:
c2 = d.get(c, '')
if blank[-1] == c2:
blank.pop()
elif c2:
return False
else:
blank.append(c)
return len(blank) == 1
执行效率一般,但复杂度低吧,因为用了字典,在python基础数据类型里,字典算是最快的了,另外看到一种完全相反的,执行效率很高,这里记录一下:
class Solution:
def isValid(self, s):
while '{}' in s or '()' in s or '[]' in s:
s = s.replace('{}', '')
s = s.replace('[]', '')
s = s.replace('()', '')
return s == ''
问题说明
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
完整代码
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
sorted_nums = sorted(nums)
return sorted_nums[-k]
先用快排sorted和列表倒叙实现最大值提交后,开始又读了一遍题,发现这题的知识点是堆,然后因为不太会就去看了一下官方题解,用到了heapq堆模块,具体的堆算法,今天没时间看了,在弄VMware的联网问题弄得有点烦。
先get一下:Python 的 heapq 模块源码分析
class Solution:
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
return heapq.nlargest(k, nums)[-1]
题目说明
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
完整代码
这题的一看便是贪心算法,因为标题旁边列出来了。。于是我们便能写出一个逻辑方程如下:
d p [ i ] = { d p [ i ] , i f d p [ i ] < d p [ i − 1 ] s u m ( d p [ i ] − d p [ i − 1 ] ) , i f d p [ i ] > d p [ i − 1 ] dp\left[ i \right] =\left\{ \begin{array}{c} dp\left[ i \right] \text{,}if\ dp\left[ i \right] <dp\left[ i-1 \right]\\ sum\left( dp\left[ i \right] -dp\left[ i-1 \right] \right) \text{,}if\ dp\left[ i \right] >dp\left[ i-1 \right]\\ \end{array} \right. dp[i]={dp[i],if dp[i]<dp[i−1]sum(dp[i]−dp[i−1]),if dp[i]>dp[i−1]
后期考虑会写一篇动态规划与贪心算法的专题来总结这样一个重要的方法,目前感觉火候还没有到,这题相对简单,如果难的就可能想不到了。所以代码为:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
maxprice = 0
for i in range(1,len(prices)):
if prices[i-1] < prices[i]:
# print(prices[i-1],prices[i],"xxxxxxxxxxxxxxx")
max1 = prices[i]-prices[i-1]
maxprice += max1
return maxprice
看到一个网友的比较标准的动态规划代码,观感很好,但感觉这题并不是很适用,首先这只是一维数组,并且是前一个与后一个的比,而没有两个或者三个跨度的延伸,所以很难构成二维,反之延长了时间,但这里收藏记录一下:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
n = len(prices)
dp = [[0]*2 for _ in range(n)]
# dp[i][0]表示第i天不持有股票, dp[i][1]表示第i天持有股票
dp[0][0], dp[0][1] = 0, - prices[0]
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
return dp[n-1][0]
问题说明
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
完整代码
这题没看懂意思,完全不懂怎么拆和合并,然后就去看官方题解了,大概看懂了暴力,然而还是有些不知道其所以然,先在这记录一下吧:
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
self.nodes = []
head = point = ListNode(0)
for l in lists:
while l:
self.nodes.append(l.val)
l = l.next
for x in sorted(self.nodes):
point.next = ListNode(x)
point = point.next
return head.next
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/he-bing-kge-pai-xu-lian-biao-by-leetcode/
题目说明
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
完整代码
这题比上题好理解,大概清楚要干什么了,和合并两个有序数组类似,但没有数组那么简单,同样提供了很多内置函数和api,这个需要自己构造一个排序规则,最核心的步骤就是链表的添加节点了,关于原理可以看我之前总结的:python中数组与链表的总结与实现。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
head = ListNode(0)
first = head # 记录节点,连上原链表的头结点,即first.next
while l1 != None and l2 != None: # 两边都不为空时
if l1.val > l2.val:
head.next = l2
l2 = l2.next
else :
head.next = l1
l1 = l1.next
head = head.next
head.next = l1 or l2 # 两边为空时
return first.next
另外看到很多大佬都用了递归,我表示没有想到也没敢用,确实可以并且效率很高:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
if not l1:return l2
if not l2:return l1
if l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
手机上看leetcode的时候看到的很简单的一个题,基于斐波那契数列,这个可以看我很早之前用了九种方法来表示,python斐波那契数列的九种思路与多解。所以还是比较简单的:
class Solution:
def climbStairs(self, n: int) -> int:
a,b=0,1
i=1
while i<=n:
a,b=b,a+b
i+=1
return b
子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
链接:https://leetcode-cn.com/problems/subsets
这题刚看就记起前不久刚用过的库函数combinations,然后大概写了一下:
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = []
for i in range(len(nums)+1):
for tmp in itertools.combinations(nums, i):
res.append(tmp)
return res
还行吧,也算是活学活用一波了,但如果真的是笔试题肯定不能这样,然后大概想到了将上面的第二个for循环改成迭代的形式,即动态规划,方程为dp = dp + [[i] + nums for nums in res],记录一下:
class Solution(object):
def subsets(self, nums):
dp = [[]]
for i in range(len(nums)):
dp = dp + [each+[nums[i]] for each in dp]
return dp
排序链表
这题依然还是没有什么思路,链表的基础太差了,还需要回炉重造,这里标记一下,看答案依然有些吃力。
2019/8/10号记,把昨天的直接黏贴的官方解答删了,因为发现今天还是理解不了(手动滑稽),再来认真想一下这题,大概懂了一位网友的解法,之后还要反复看,官方的太过于标准,可能我就只能靠背,先在这里记录一下吧:
def sortList(self, head: ListNode) -> ListNode:
if not head or not head.next: # 如果无节点或只有一个节点
return head
elif not head.next.next: # 如果刚好两个结点
if head.next.val < head.val: # 更正顺序
head.next.next = head
head = head.next
head.next.next = None
return head
slow, fast = head, head # 快慢指针找中点
while fast.next and fast.next.next:
fast = fast.next.next
slow = slow.next
# 截断并分别递归
head2 = slow.next
slow.next = None
l1 = self.sortList(head)
l2 = self.sortList(head2)
# 合并
if not l1 or not l2:
return l1 or l2
head = cur = 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 or l2
return head.next
';