Array数组
03 数组中的重复数字 04 二维数组中的查找 以上两题都是双指针;
offer05 替换空格
用到了js里面的split和join;计算空格存在,然后给出新长度,利用双指针实现替换;
118&119 杨辉三角
118那里学会 row[]=rec[][]+rec[][] 这种跨越行的运算;
119学会了滚动算法,减少了空间,但是内存运算还是不变的,本身还是一种遍历,通过focus在所需的数组上,避免别的数组空间占用;
169多数元素
排序一下,最中间那个就是了,不过速度有点慢;
还学会了搞对象,hhh;
学会了摩尔投票法,简称同归于尽法,不过这种我认知是只可以用再有一个或两个主元素的情况下;
229 求众数
升序排序后用lastIndexOf法从右向左遍历;
原来摩尔投票法也可以用在这里,就是else if写得有点麻烦,希望能发现简写的办法;目前可知摩尔投票法运用再1/2和1/3这类简单情况适用;
274.引用H
var hIndex = function(citations) {
citations.sort((a,b)=>a-b) //如果b-a就是降序排列
let h = citations.length;
for(let i=0; i<citations.length;i++){
if(citations[i]<h){
h--;
}
};
return h;
};
因为例子里面有个3,被引用篇数的数目也是3,所以卡住了,画图比较好想出来。答案思路等于是一个正方形在坐标轴上不断缩小,直到缩小到范围内最大;
本来想的是降序排列,但是好像图像上无法直观想象出来;
这个解法用的h--
,follow了for循环。
275.引用H 2
同上; 标记说可以用二分法做。二分法适用在循环中减小复杂度 O(lgn)
var hIndex = function (citations) {
let left = 0;
let right = citations.length - 1;
let N = citations.length;
let res = 0
while (left <= right) {
let mid = left + right >> 1 //Math.floor()
if (citations[mid] >= N - mid) { //能够想出来这个条件就很难了
res = N - mid;
right = mid - 1;
} else {
left = mid + 1
}
}
return res
};
217&&219&&220 重复数
219
用哈希表做很快;
双指针基本原理
双指针轻松但是运行久;且要记得遇到两个for循环时候,外面的for要包住里面的for;
Math.abs()是取绝对值;
220
想尝试能不能继续Hash表,但是看到一个python写的需要另建一个有序集合,用上ceiling和floor,这种做法不够简洁,遂放弃;
桶排序 之前见过这种方法解了一个hard题;
滑动窗口 感觉上就是在Hash表+滚动算法;
55&&45 跳跃游戏
55
动态规划&&贪心算法
这个视频好给力,介绍了动态规划里面的top-down和bottom-up,bottom-up原理和贪心算法很像,而且也比top-down简单常见;
一句话总结bottom-up收获就是:在遍历i的时候,设定了maxJump,在它的数值范围之内再遍历是否有跳跃可能性;
有一个贪心算法的疑问:为什么就肯定成功路径里面一定包含倒二个呢?//ans:会逆着开始倒二个只是再扩大可能性,任何能跳到最后一个位置上的点一定也能跳掉倒二个,而能跳到倒二个也能跳到最后一个;
45
这题是top-down的贪心算法,疑问:可不可以用bottom-up的贪心算法?
// ans:不可,top-down是为了求最优解;
121-123&&128 买卖股票最佳时机
121
第一个想法就是双指针,暴力两层for,但是超出时限了。看到别人的思路,两层for可以精简的;
用dp存储前i天的最大利润,底层思路和上面一样,也是对比取最小,空间和时间占用都比上面大;
因为dp在这里用到的意义不大,所以第三种可以把dp给省略掉;
122
通俗易懂的贪心算法
简而言之,使得每步看起来都是当前的最优解;
通俗易懂的动态规划
一共三个组成部分:初始值,方程式和最终值;
斐波那契数列属于一维的动态规划;
123
let buy1=-prices[0],buy2=-prices[0];
let sell1=0,sell2=0;
for(i=1;i<n;i++){
buy1=Math.max(buy1,-prices[i]);
sell1=Math.max(sell1,buy1+prices[i])
buy2=Math.max(buy2,sell1-prices[i])
sell2=Math.max(sell2,buy2+prices[i])
}
return sell2;
此题对于动态规划的疑惑:每到i天,遇到更优的,buy1和sell1也会改变;可是结果是要选出两个最大的利润,buy2和sell2是如何不被buy1和sell1的变化影响的呢?//我做了图表,也把每一步的b1s1b2s2求解,但是还是不能够理解为什么b2s2可以不受影响//ans如下
fstBuy: 在该天第一次买入股票可获得的最大收益
fstSell: 在该天第一次卖出股票可获得的最大收益
secBuy: 在该天第二次买入股票可获得的最大收益
secSell: 在该天第二次卖出股票可获得的最大收益
分别对四个变量进行相应的更新, 最后secSell就是最大
收益值(secSell >= fstSell)
287 寻找重复数
可以排序数列或者用桶做;
贪心算法
322 玩硬币
这里贪心算法在[1,4,5],n=12的状况下会算错吧?还是要用DP做比较好;
1217 玩筹码
比较奇数偶数谁更多;题目有点难看懂;
55 跳跃游戏
动态规划
509 斐波拉契数列
62 不同路径
需要两个for循环,属于二维动态规划;
121 售出股票最佳时机
动态规划到每个阶段,求当前最大利润;
70 爬楼梯
就是一道典型的斐波拉契数列;
279 完全平方数
这题真的绝了,是322玩硬币的进阶版;
offer10-1 斐波那契数列
记得按题目要求取模,不然会报错;
offer10-2 小青蛙跳格子
终点的全部可能性=倒数第一跳一步到终点+倒数第二只两步到终点;
offer11 旋转数组最小数字
String
28.实现strStr()
学会了用substring()进行多个对比;
14.最长公共前缀
break之后在for外面取for里面的数;
58 最后一个单词的长度
没有考虑到结尾是空格的情况,需要用到两个while;
387 字符串中的第一个唯一一个字符
str.charAt(0) // H 给字母
str.charCodeAt(0)//a的unicode值为97
用新数列计算出现的字母;
383 赎金信
哈希表;
344 反转字符串
for(let left=0,right=n-1;left<right;left++,right--){//双指针;
[s[left],s[right]]=[s[right],s[left]];//学到了[]=[]置换;
}
链表List
先从基础的单链表做起
offer06 从头到尾打印链表
遍历用上unshift;复杂一点就用push加上reverse(自定义func);
链表和数组的区别是一个面试的必考题!
21 合并两个有序链表
学到了l1.next=mergeTwoLists(l2,l1.next)
offer 18 删除链表中的节点
链表题目画图做思路会很清晰,这里就是pre.next=cur.next
,跳过cur;
offer 22 链表中倒数第k个节点
我的思路:把链表一共几个节算出来;然后length-k+1算出倒数第k个所在的位置;接下来遍历去找;
大牛的思路:1快慢指针快的那个指针跑快k步,直到快指针为null则慢指针是想要的答案。2栈方法把所有链表存入栈stack.push(),接着从屁股开始出栈k个stack.pop()。
var getKthFromEnd = function(head, k) {
let p = head, q = head;
let i = 0;
while (p) {
if (i >= k) {
q = q.next;
}
p = p.next;
i++;
}
return i < k ? null : q; //如此的简洁!
};
二叉树
offer07 重建二叉树
二叉树理论基础
TreeNode \ buildTree
Stack
20 有效的括号
我的思路:取第一个和最后一个括号,如果不符合()[]{},就return false;
报错!没有想到(){[]}的情况。
大佬的思路:
用map存储括号(前半部分作为值,后半部分作为键);
把括号入栈,一旦有遍历到后半部分的括号(map可以get到),则出栈;
直到stack的长度为零,return true;
offer 9 用两个栈实现队列
我的思路:直接创立一个栈,然后进行pop和unshift操作;
大佬的思路:需要有两个栈来模拟入栈和出栈;
155 最小栈
我的思路:对stack进行for循环,找最小值;
官方的思路:用辅助栈,在每次push新元素时,同样往辅助栈中push当前最小值;
496 下一个更大元素I
我的思路:遍历nums1,在nums2中再遍历找到对应的nums1中数值的位置,然后往下再套遍历找比它大的家伙???
神仙思路:运用stack和hash表,把每个nums2的item都push到stack里,push的过程里,如果item比栈顶元素大,则淘汰栈顶元素,把栈顶元素对应的右边较大值形成键值(栈顶元素:item)对存储到hash表中;这么结束后,剩余在stack中的item都是找不到右边较大值的,都以item:-1的键值对存到hash表里面;最后,把nums1对应hash.get到的所有值都push到ans里面,则解;
71 简化路径
我的思路:试图用哈希表存储‘/’‘.’‘..’,然后遍历过程中,遇到这些家伙就……?
大牛的思路:先将str以‘/’split开来;遇到‘’‘.’就跳过;遇到‘..’并且stack不为空,就pop栈顶元素;其余情况直接push;最后把得到的stack用‘/’组合起来,在前头再加上个‘/’,return即可。关于‘’的处理,这里非常巧妙的给它忽略掉,这样,join的时候前后都不会出现‘/’了。