type
status
date
slug
summary
tags
category
icon
password
Day1
88. 合并两个有序数组(简单)
直接合并后排序
- 善于使用sort排序(很方便)
这个题是我夏令营的原题(我用的第一种解法)
双指针
- 这个题很容易想到双指针,有两个数组,一个指针指向数组1,另一个指针指向数组2
- 如果我们从前往后遍历不重新开数组的话,nums1是容易被覆盖的,那么怎么解决?
逆向双指针法
- 如果没有多余的额外空间,可以从后往前来,就算num2的所有值都原封不动的放到num1后面,num1的数据也一定不会因为被覆盖而消失。
1. 两数之和(简单)
暴力枚举
- 一般来讲暴力法可取,也最容易想到,但是往往会因为超时而pass不了
- 所以我们只需要有思路即可,尽可能的想办法去优化两层的遍历即可
哈希表
- 哈希表常可以解决这类问题,记录一对一对的数据,常常想到map或者set
- 这里我常用的是unordered_map和unordered_set,由于这个题需要记录一下下标,所以我选用unordered_map
- 每次我们记录一下每个元素出现(类似于标记了),如果寻找到互补元素就输出就可以
- 运行提交之后时间从64ms变成了4ms,虽然多用了一点空间,但无关紧要
auto it = hashtable.find(target - nums[i]);
- 这个auto是一个迭代器(这个迭代器经常用于遍历,经常把它和哈希表最后进行比较)
- 这里的it->first是具体的数值,it->second是下标
Day2
283. 移动零(简单)
双指针
用两个指针,p指向非零元素,q指向current元素
- 用一个额外的变量来存储非0数,再交换值
- 里面的交换也可以直接用swap
485. 最大连续 1 的个数(简单)
一次遍历
- 数组的最后一个元素可能是 1,且最长连续 1 的子数组可能出现在数组的末尾,最后需要再比较一下
双指针
- 注意+1 -1的问题,这种做法就不会出现边界问题
- 这个是我第一个想到的方法
645. 错误的集合(简单)
排序
- 这是我第一时间想到的方法,先排序再说
寻找重复的数字较为简单,如果相邻的两个元素相等,则该元素为重复的数字nums[i] == p,这里的p是i-1的值。
- 寻找少的元素
- 如果少的是1,我直接nums[0] != 1判断
- 如果少的是最后一个n,我直接nums[nums.size() - 1] != nums.size()
- 如果是其他的情况,只需要判断两个相邻差为2即可,即nums[i] - p == 2
哈希表
这个题可以用 map 来记录次数
- 重复的数字在数组中出现 2 次,丢失的数字在数组中出现 0 次,其余的每个数字在数组中出现 1 次。
- 因此可以使用哈希表记录每个元素在数组中出现的次数,然后遍历从 1 到 n 的每个数字,分别找到出现 2 次和出现 0 次的数字,即为重复的数字和丢失的数字。
- 这个思路就是非常巧妙,没有那么多的需要考虑的边界条件
Day3
287. 寻找重复数(中等)
这个题真正的难点我认为是:
你设计的解决方案必须不修改数组nums且只用常量级O(1)的额外空间。
修改下nums,怎么解(非题解)
- 其实可以先排序做的,之后用两个变量就可以,很简单
时间复杂度不为O(1),怎么解(非题解)
- 最简单的就是用哈希表,很容易理解
二分查找(满足题意)
- 查找有范围的整数我们可以考虑二分查找
- 这个视频比官方题解讲的好多了
快慢指针(满足题意)
- 如果单纯两层循环必定会超时(前车之鉴,一定要优化
- 这个优化的思路非常的难想(需要利用快慢指针)(超级难)这里不做过多解释建议去看这两个题解 - 有两个题解写的不错:
667. 优美的排列 II(中等)
数学思维
- 这个题并没有考察算法,而是考的关于数学思维
- 其实关键就是如何翻(我刚开始想的是从第一个翻swap(1,2),swap(2,3)最后发现不对
- 之后找到了更好的方式,完全翻转,有一个较为清晰的图解
697. 数组的度(简单)
哈希表
- 这个是我第一个想到的做法用unordered_map<int, vector<int>> mp
- 里面的vector第一个值是次数,第二个值是这个数在原数组中第一次出现的位置,第三个值这个数在原数组中最后一次出现的位置
这里我卡在mp.find(nums[i]) == mp.end()这里,我开始直接是mp[nums[i]][0] == 0,后来发现有可能根本就没有,这个数组的区域根本就不存在,所以一直显示错误
565. 数组嵌套(中等)
图
- 这个题我第一个想法就是图,很明显要求的是连通图的最长的路径长度
- 我们学过的这种有向图,一定有一个或多个环
- 从 i 向 nums[i] 连边,我们可以得到一张有向图,有向图中每个点的出度和入度均为 1
- 所以我们vector<bool> vec(n)来标记访问过的节点 (这里不是很好想)
原地标记
这个做法就主要利用了那个元素在数组边界的范围内,
直接省去了vector<bool> vec(n),直接覆盖就行了,反正用一次就没用了
769. 最多能完成排序的块(中等)
贪心
- 贪心算法本身我就觉得很玄学(有的时候根本想不到
- 这个题的思路:
- 由于 arr 是 [0,..,n−1] 的一个排列,若已遍历过的数中的最大值 mx 与当前遍历到的下标 i 相等,说明可以进行一次分割,累加答案。(局部最优)
- 但我还是没太搞明白这里(官方题解这里在说什么,放个链接
- 这个链接如果实在看不懂建议跳过看数学思路
数学思路
- 这个想法我主要看到了一个评论区的答案(豁然开朗)
- 考虑到数组长度为n,而且数组元素位于区间[0, n-1]且不重复,那么数组排好序后,每个值和下标恰好是相等的;所以,从左到右遍历数组,并且分别对值和下标累加求和,只要两个和相等,就切出一个块。
单调栈
- 这个题我还真就没想到有单调栈这个做法(也挺厉害的
- 根据题目,我们可以发现,从左到右,每个分块都有一个最大值,并且这些分块的最大值呈单调递增。我们可以用一个栈来存储这些分块的最大值。最后得到的栈的大小,也就是题目所求的最多能完成排序的块。
- 画个图更好理解,如果当前元素大于栈顶,直接推进去,如果小于一直弹出再比较
系列专题介绍
- Author:Chailyn
- URL:https://own.chailyncui.blog/a2221d88095b48889727b438db01eb7e
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts