4.12
两数之和
自己写的:超出时间限制了
1 | class Solution(object): |
结果:
改进:
1 | class Solution(object): |
结果:
参考答案:
1 | class Solution(object): |
借助哈希表,如果target-nums[i]对应的值不在哈希表中,就将nums[i]和下标i存到哈希表里
遍历数组 nums,i 为当前下标,每个值都判断map中是否存在 target-nums[i] 的 key 值
如果存在则找到了两个值,并返回这两个值对应的下标。
三数之和
自己写的:
1 | class Solution(object): |
结果:
问题:输出的三元组有重复的,如[-1,0,1]和[0,1,-1],不符合题意。使用了三重循环,时间复杂度较大,有待改进。
参考答案:
使用双指针解法,利用排序避免重复答案,头指针start指向第一个元素,尾指针end指向最后一个元素。
1 | class Solution: |
1 | class Solution(object): |
1 | class Solution: #三重循环解法 |
4.13
最大子数组和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
自己写的:
没思路。。。
1 | class Solution(object): |
结果:
参考答案:
1 | class Solution(object): |
动态规划思想
nums[i-1]和nums[i]相加,如果nums[i-1]比0小,那么对于结果无增益效果,nums[i]直接记录结尾为nums[i]的子串的最大值。
4.15
搜索旋转排序数组
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
关键:时间复杂度为O(log n),考虑二分查找。
1 | class Solution(object): |
买卖股票的最佳时机
自己写的:用的暴力解法,结果测试用例中有大数据,超时了。
1 | class Solution: |
结果:
参考答案:
动态规划思想
- 记录【今天之前买入的最小值】
- 计算【今天之前最小值买入,今天卖出的获利】,也即【今天卖出的最大获利】
- 比较【每天的最大获利】,取最大值即可
1
2
3
4
5
6
7
8
9class Solution:
def maxProfit(self, prices: List[int]) -> int:
if len(prices)<=1: # prices数组长度小于等于1,直接返回0.
return 0
minn,maxn=prices[0],0 # 第一天的价格赋予买入的最小值,第一天最大获利为0
for i in range(1,len(prices)):
maxn=max(maxn,prices[i]-minn) # maxn代表今天卖出的最大获利,prices[i]-minn代表如果今天卖出的话,获利多少。
minn=min(minn,prices[i]) # minn代表今天之前买入的最小值
return maxn
合并区间
自己并没有什么思路
参考答案:
1 | class Solution: |
用数组 merged 存储最终的答案。
首先,将列表中的区间按照左端点升序排序。然后将第一个区间加入 merged 数组中,并按顺序依次考虑之后的每个区间:
如果当前区间的左端点在数组 merged 中最后一个区间的右端点之后,那么它们不会重合,我们可以直接将这个区间加入数组 merged 的末尾;
否则,它们重合,我们需要用当前区间的右端点更新数组 merged 中最后一个区间的右端点,将其置为二者的较大值。
4.16
下一个排列
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。
必须 原地 修改,只允许使用额外常数空间。
自己写的:
思路:在数组内倒着找试试?不会实现。。。
参考答案:
思路:
- 我们希望下一个数 比当前数大,这样才满足 “下一个排列” 的定义。因此只需要 将后面的「大数」与前面的「小数」交换,就能得到一个更大的数。比如 123456,将 5 和 6 交换就能得到一个更大的数 123465。
- 我们还希望下一个数 增加的幅度尽可能的小,这样才满足“下一个排列与当前排列紧邻“的要求。为了满足这个要求,我们需要:
- 在 尽可能靠右的低位 进行交换,需要 从后向前 查找
- 将一个 尽可能小的「大数」 与前面的「小数」交换。比如 123465,下一个排列应该把 5 和 4 交换而不是把 6 和 4 交换
- 将「大数」换到前面后,需要将「大数」后面的所有数 重置为升序,升序排列就是最小的排列。以 123465 为例:首先按照上一步,交换 5 和 4,得到 123564;然后需要将 5 之后的数重置为升序,得到 123546。显然 123546 比 123564 更小,123546 就是 123465 的下一个排列
1 | class Solution: |
从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
构造二叉树,使用递归。
参考答案:
1 | class Solution: |
使用递归函数时,要注意递归函数的边界:
4.18
子集
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
参考答案:
方法一:回溯法
1 | class Solution: |
回溯法:增量构造,类似递归。
方法二:位运算法
数组的每个元素,可以有两个状态:
- 不在子数组中(用0表示)
- 在子数组中(用1表示)
1 | class Solution: |
4.19
二叉树的层序遍历
思路:借用队列完成层序遍历,根节点入队,若他的左右孩子不为none,则依次入队。
1 | class Solution: |
1 | class Solution: |
二叉树遍历总结
1 |
|
4.23
无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
自己写的:
1 | class Solution: |
错误:
类似dvd这种两边有重复字符,中间的子串就被忽略了。
参考答案:
1 | class Solution: |
这道题主要用到思路是:滑动窗口
什么是滑动窗口?
其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!
如何移动?
我们只要把队列的左边的元素移出就行了,直到满足题目要求!
一直维持这样的队列,找出队列出现最长的长度时候,求出解!
时间复杂度:O(n)
4.24
反转链表
1 | # Definition for singly-linked list. |