不知道是第几次重振旗鼓刷力扣了,之前都是半途而废,回想起来如鲠在喉。眼看要毕业当程序员了,但是代码还半生不熟,生怕被别人看出自己不会写代码。这种感觉太糟了,想了想不如努努力成为一个会写代码的人吧。
目录
🎯刷题Flag
先立个目标,要不然都不知道自己这次会半途而废还是1/4途而废。就2022年2月13到2022年2月28日这15天,先搞个50题
🍳数据结构到底是个啥
计算机中的数据结构就是数据在计算机中的存储方式,
就两种:数组与链表,分别对应线性存储和链式存储
其他的数据结构:队列,堆栈,图,树都是基于这两者实现
🍽️整那么多花里胡哨的数据结构有啥用
数据结构就是存取数据的方式,就像工具。例如盛菜会用盘子,炒菜要用锅,解决不同的问题会用不同的方法和工具,其中方法对应的“算法”,工具对应着“数据结构”。
所以知道各种数据结构的优缺点,使用场景才能在解决问题时灵活运用。比如知道啥时候用锅啥时候用盘子。
📝学习日记
1、前缀和
2022年2月13日 天气晴 今天搞了3道题 (303+304+560)
适用场景:原始数组不会被修改的情况下,频繁查询某个区间的累加和。O(1)
思想:对于数组中每个元素,都计算从开始到这个元素为止的前缀和,根据前缀和的差值来求(满足条件的)区域和。将区域中每个元素的遍历转化为对区间端点两个元素的操作。
标识词:最长连续
核心代码:
class PrefixSum{
// 前缀和数组
private this.preSum:number[];
constructor(nums:number[]){
this.preSum = new Array<number>(nums.length + 1).fill(0);
// 计算前缀和
for(let i = 0; i < nums.length; i++){
this.preSum[i+1] = this.preSum[i] + nums[i];
}
}
/*计算闭区间[left, right]累加和*/
query (left: number, right: number): number{
return this.preSum[right+1] - this.preSum[left];
}
}
2、差分数组
2022年2月14日 天气阴 今天搞了3道题(370+1109+1094)
适用场景:频繁对原始数组某个区间中的元素仅仅更改。O(1)
思想:将对原始数组区间内每个元素的更改转化为对差分数组中区间端点对应元素的更改。
核心代码:
class Difference{
// 差分数组
diff: number[];
constructor(nums: number[]){
// 构造差分数组
this.diff[0] = nums[0];
for(let i = 1; i < nums.length; i++){
this.diff[i] = nums[i] - nums[i-1];
}
}
// 更新差分数组
update(left: number, right: number, inc: number){
this.diff[left] += inc;
right+1 < nums.length && (this.diff[right+1] -= inc);
}
// 差分数组回推原始数组
result(){
res:number[] = [];
res[0] = this.diff[0];
for(let i = 1; i < this.diff.length; i++){
res[i] = this.diff[i] + this.diff[i-1];
}
return res;
}
}
3、滑动窗口
2022年2月15日 天气阴 元宵节 今天搞了4道题(76+567+438+3)
适用场合:字符串,找子字符串或者子序列
配合使用:映射表window和needs
思想:两个字符串匹配的问题,终归还是要拿着字符串1去对照字符串2。如何遍历读取字符串2呢?采用滑动窗口的思想。窗口的两端分别对应左右指针[left,right),right++窗口内元素增加一个,不断增加直到满足条件,这时left++,窗口内元素逐渐减少,直到不满足条件。这时right再增加…。最后right遍历到字符串长度结束。
注意:区间左开右闭,右到头循环结束
核心代码:
//s1,s2
const window = new Map();
const needs = new Map();
// needs记录s1中字符出现的次数
let left = 0;
let right = 0;
let valid = 0;//记录满足条件字符个数
while(right<s2.length){
const c = s2[right];
right++;
// 进行一些window valid之间的操作
console.log(left,right); //debug
while(window need shrink){
const d = s2[left];
left++;
// 进行一些window valid之间的操作
}
}
4、二分搜索
2022年2月16日 天气阴 今天搞了2道题 (704+34)
适用场合:排好序的数组nums中找元素target O(logN)
思想:left在头,right在尾巴,mid取中间,通过控制nums[mid]===target时,边界以及返回值的变化,来求出target对应的唯一索引值,或者最左最右边界
注意:区间双闭合,left <= right时执行循环
核心代码:
// given nums[] target
let left = 0;
let right = nums.length-1;
while(left <= right ){
const mid = Math.floor(left+(right-left)/2);
if(nums[mid]===target){
return mid; // 值
right = mid - 1; // 左边界
left = mid + 1; // 右边界
}else if(nums[mid]<target){
left = mid + 1;
}else if(nums[mid] > target){
right = mid - 1;
}
}
二分搜索的扩展
2022年2月17日 天气阴 今天搞了两道题(875+1011)
扩展应用:排好序的数组可以抽象为一个单调函数f(x),x为自变量,f(x)为x对应的值。求满足f(x)=target对应的x,或者最左最右边界的x
难点:(1)自变量x的范围,最小和最大值(2)已知x,如何求f(x)(3)不要提前把每个x对应的f(x)都求出来,用到的时候再求
5、数组原地挪动
2022年2月18日 天气阴 今天搞了5道题(870 =85.71%)(26+83+27+283=97.25%)
场景:给一个数组nums,要求删除某一元素,删除重复项,移动零等
解决方法:双指针(快慢指针 or 前后指针)时间复杂度O(N),空间复杂度O(1)
注意事项:一个while循环里面套着while循环,如果判断条件只与同一个变量有关,考虑合并
6、链表数据结构
细品:val和next缺省是undefined,不是null
// 链表单个节点
class Node<T> {
element: T;
next: null | Node<T>;
constructor( element?: T, next?: Node<T> | null){
this.element = element;
this.next = (next===undefined)? null : next;
}
}
// 链表
class LinkedList<T>(){
protected count = 0;
protected head : Node<T> | null;
constructor(protected equalFunction:IEqualFunction<T> = defaultEqualFunction){}
}
👇这些JS语法和我不咋熟
1、for循环遍历
// 遍历元素
for-of 元素
for(let num of nums){
}
// for -in 索引(index)
for(let index in nums){
}
链表问题思维方法:双指针
2、一维度数组和二维数组的初始化
// 初始化一维数组,长度len,全部赋初值为0
const arr = new Array<number>(len).fill(0);
// 初始化二维数组,m行n列,全部赋初值为0
const multiArr = new Array<number>(m).fill(0).map((arr)=>new Array<number>(n).fill(0));
3、映射表Map相关方法
const map = new Map();
// 如何在声明时初始化
const map = new Map([['key1', 'value']]);
map.has('key') // true false
map.get('key') // value
map.set('key','value')
4、字符串slice
slice( start, end) 区间 [start, end)
const str = "0123456";
const partStr = str.slice(1,2); //1
5、Object.entries()方法
数组排序顺带着index也跟着排序,需要用到Object.entries()
方法
const nums = [11, 12, 13];
const arr = Object.entries(nums);
console.log(arr) // [[0, 11], [1, 12], [2, 13]];
// 排序
const maxArr = Object.entries(nums).sort((a,b) => a[1]-b[1]);
const [index, num] = maxArr[0];