119题 杨辉三角2
用迭代做:
class Solution:
def getRow(self, rowIndex: int) -> List[int]:
whole = []
for row_order in range(rowIndex + 1):
therow = [1] * (row_order + 1)
for j in range(1, row_order):
therow[j] = whole[row_order-1][j-1] + whole[row_order-1][j]
whole.append(therow)
return whole[rowIndex]
空间复杂度应该是n^2.
我一直在考虑用递归怎么去做,在题解里看到一个思路(来源用户 1501615430):只做一个数组,但是对它做滚动处理,从右至左从len-2的位置依次加上前位,这是利用杨辉三角本身的数学原理去做一个“递归”。空间复杂度只有n,两个时间复杂度都是n^2
class Solution:
def getRow(self, rowIndex: int) -> List[int]:
therow = [1]
for i in range(rowIndex):
therow.append(1)
for j in range(len(therow)-2, 0, -1):
therow[j] += therow[j-1]
return therow
121题 买卖股票的最佳时机
乍一看这个题挺简单的,写了两个时间复杂度分别为n^2和n的,竟然都超时,可能因为用了遍历比较。看了题解才知道正确解法,所以题都是有章法的而不是自己乱写迭代...
方法一: 迭代- 超时题解(官方给的,我自己本身的还加了一个列表
class Solution:
def maxProfit(self, prices: List[int]) -> int:
ans = 0
for i in range(len(prices)):
for j in range(i + 1, len(prices)):
ans = max(ans, prices[j] - prices[i])
return ans
方法二:一次遍历,计算到当天为止的最小价格和最大利润(以下两个方法都来自于用户 腐烂的橘子 题解。)
其实它的本质和动态规划很像,状态转移方程是一样的,虽然也用了max和比较,但是只是在两个之间比较,而不是遍历比较,就会省很多内存。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
minprice = float('inf')
maxprofit = 0
for price in prices:
minprice = min(minprice, price)
maxprofit = max(maxprofit, price - minprice)
return maxprofit
方法三:动态规划
找出dp[0], dp[i], dp[i]与dp[i-1]的状态转移方程,就ok
class Solution:
def maxProfit(self, prices: List[int]) -> int:
minprice = prices[0]
dp = [0] * len(prices)
dp[0] = 0
for i in range(1, len(prices)):
minprice = min(prices[i], minprice)
dp[i] = max(dp[i-1], prices[i] - minprice)
return dp[len(prices)-1]
所以其实方法二和方法三没啥区别,而且方法三的空间复杂度更高,消耗内存多。为什么方法二的minprice是inf而方法三的是prices[0]呢?
我个人认为方法二是从0位置开始遍历,而方法三是从1位开始,会忽视掉0位的价格。所以必须放进去,实质上方法二写成prices[0]也没有任何问题。
167题 两数之和2
这道题很不难,但是有一些学习心得。
方法一: 做这个题的暴力解法,是没有考虑有序性质的,而且时间复杂度O(n2),超时。
方法二: 二分查找。定一个值,用二分法找它与target的差值,遍历一次数组,时间复杂度O(nlogn).
方法三: 双指针。从两边向中间查找,两个指针避免了遍历,大大减少了运行时间和内存的消耗,时间复杂度O(n). 双指针肯定是要更省时间的!
方法四: 一次哈希表。这个方法非常有意思,把哈希思想体现的淋漓尽致。定一个值加为字典的value(即为较小数值索引值),其key就是与target的差值。若遍历至此key,则存在于字典中,此时的索引值即为较大数值索引值。答案就出来了。虽然效率很低,但是思路很有趣
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
dict_helper = {}
for i in range(len(numbers)):
if numbers[i] in dict_helper:
return [dict_helper[numbers[i]]+1, i+1]
#这里的i是较大数索引,较小数索引为较大数的value
else:
dict_helper[target - numbers[i]] = i
#这里i是较小数的索引,key是较大数
心得: 暴力解法行不通我就在思考,怎么才能降低时间复杂度,想到了二分法,但是脑子里走马观花觉得也省不了多少事......就放弃了,可实际上时间复杂度就是少了很多也就可以通过。所以不能“主观臆断”,要有依据和逻辑。