用JavaScript刷LeetCode的正确姿势
<p><span style="color: rgba(170, 170, 170, 1); font-size: small">虽然很多人都觉得前端算法弱,但其实 JavaScript 也可以刷题啊!最近两个月断断续续刷完了 leetcode 前 200 的 middle + hard ,总结了一些刷题常用的模板代码。<span style="color: rgba(255, 99, 71, 1)">走过路过发现 bug 请指出,拯救一个辣鸡(但很帅)的少年就靠您啦!</span></span></p><h2>常用函数</h2>
<p>包括打印函数和一些数学函数。</p>
<div class="cnblogs_code">
<pre>const _max =<span style="color: rgba(0, 0, 0, 1)"> Math.max.bind(Math);
const _min </span>=<span style="color: rgba(0, 0, 0, 1)"> Math.min.bind(Math);
const _pow </span>=<span style="color: rgba(0, 0, 0, 1)"> Math.pow.bind(Math);
const _floor </span>=<span style="color: rgba(0, 0, 0, 1)"> Math.floor.bind(Math);
const _round </span>=<span style="color: rgba(0, 0, 0, 1)"> Math.round.bind(Math);
const _ceil </span>=<span style="color: rgba(0, 0, 0, 1)"> Math.ceil.bind(Math);
const log </span>=<span style="color: rgba(0, 0, 0, 1)"> console.log.bind(console);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">const log = _ => {}</span></pre>
</div>
<p> <span class="cnblogs_code">log</span> 在提交的代码中当然是用不到的,不过在调试时十分有用。但是当代码里面加了很多 <span class="cnblogs_code">log</span> 的时候,提交时还需要一个个注释掉就相当麻烦了,只要将 <span class="cnblogs_code">log</span> 赋值为空函数就可以了。</p>
<p>举一个简单的例子,下面的代码是可以直接提交的。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算 1+2+...+n</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> const log = console.log.bind(console);</span>
const log = _ =><span style="color: rgba(0, 0, 0, 1)"> {}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> sumOneToN(n) {
let sum </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 1; i <= n; i++<span style="color: rgba(0, 0, 0, 1)">) {
sum </span>+=<span style="color: rgba(0, 0, 0, 1)"> i;
log(`i</span>=${i}: sum=<span style="color: rgba(0, 0, 0, 1)">${sum}`);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sum;
}
sumOneToN(</span>10);</pre>
</div>
<p> </p>
<h2 class="heading">位运算的一些小技巧</h2>
<p>判断一个整数 <code>x</code> 的奇偶性: <span class="cnblogs_code">x & 1 = 1</span> <code> (奇数) , <span class="cnblogs_code">x & 1 = 0</span> (偶数)</code></p>
<p>求一个浮点数 <code>x</code> 的整数部分: <span class="cnblogs_code">~~x</span> ,对于正数相当于 <span class="cnblogs_code">floor(x)</span> 对于负数相当于 <span class="cnblogs_code">ceil(-x)</span> </p>
<p>计算 <span class="cnblogs_code">2 ^ n</span> : <span class="cnblogs_code">1 << n</span> 相当于 <span class="cnblogs_code">pow(2, n)</span> </p>
<p>计算一个数 <code>x</code> 除以 2 的 n 倍: <span class="cnblogs_code">x >> n</span> 相当于 <span class="cnblogs_code">~~(x / pow(2, n))</span> </p>
<p>判断一个数 <code>x</code> 是 2 的整数幂(即 <span class="cnblogs_code">x = 2 ^ n</span> ): <span class="cnblogs_code">x & (x - 1) = 0</span> </p>
<p><strong>※注意※:上面的位运算只对32位带符号的整数有效,如果使用的话,一定要注意数!据!范!围!</strong></p>
<p>记住这些技巧的作用:</p>
<p>提升运行速度 ❌</p>
<p>提升逼格 ✅</p>
<p>举一个实用的例子,快速幂(原理自行google)</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算x^n n为整数</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> qPow(x, n) {
let result </span>= 1<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> (n) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (n & 1) result *= x; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 同 if(n%2)</span>
x = x *<span style="color: rgba(0, 0, 0, 1)"> x;
n </span>>>= 1; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 同 n=floor(n/2)</span>
<span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result;
}</span></pre>
</div>
<p> </p>
<h2 class="heading">链表</h2>
<p>刚开始做 LeetCode 的题就遇到了很多链表的题。恶心心。最麻烦的不是写题,是调试啊!!于是总结了一些链表的辅助函数。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 链表节点
* @param {*} val
* @param {ListNode} next
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span> ListNode(val, next = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.val =<span style="color: rgba(0, 0, 0, 1)"> val;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.next =<span style="color: rgba(0, 0, 0, 1)"> next;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 将一个数组转为链表
* @param {array} a
* @return {ListNode}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
const getListFromArray </span>= (a) =><span style="color: rgba(0, 0, 0, 1)"> {
let dummy </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ListNode()
let pre </span>=<span style="color: rgba(0, 0, 0, 1)"> dummy;
a.forEach(x </span>=> pre = pre.next = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ListNode(x));
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> dummy.next;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 将一个链表转为数组
* @param {ListNode} node
* @return {array}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
const getArrayFromList </span>= (node) =><span style="color: rgba(0, 0, 0, 1)"> {
let a </span>=<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> (node) {
a.push(node.val);
node </span>=<span style="color: rgba(0, 0, 0, 1)"> node.next;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> a;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 打印一个链表
* @param {ListNode} node
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
const logList </span>= (node) =><span style="color: rgba(0, 0, 0, 1)"> {
let str </span>= 'list: '<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> (node) {
str </span>+= node.val + '->'<span style="color: rgba(0, 0, 0, 1)">;
node </span>=<span style="color: rgba(0, 0, 0, 1)"> node.next;
}
str </span>+= 'end'<span style="color: rgba(0, 0, 0, 1)">;
log(str);
}</span></pre>
</div>
<p>还有一个常用小技巧,每次写链表的操作,都要注意判断表头,如果创建一个空表头来进行操作会方便很多。</p>
<div class="cnblogs_code">
<pre>let dummy = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ListNode();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> dummy.next;</pre>
</div>
<p>使用起来超爽哒~举个例子。@leetcode 82。题意就是删除链表中连续相同值的节点。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
* @lc app=leetcode id=82 lang=javascript
*
* Remove Duplicates from Sorted List II
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* @param {ListNode} head
* @return {ListNode}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> deleteDuplicates = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(head) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 空指针或者只有一个节点不需要处理</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (head === <span style="color: rgba(0, 0, 255, 1)">null</span> || head.next === <span style="color: rgba(0, 0, 255, 1)">null</span>) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> head;
let dummy </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ListNode();
let oldLinkCurrent </span>=<span style="color: rgba(0, 0, 0, 1)"> head;
let newLinkCurrent </span>=<span style="color: rgba(0, 0, 0, 1)"> dummy;
</span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> (oldLinkCurrent) {
let next </span>=<span style="color: rgba(0, 0, 0, 1)"> oldLinkCurrent.next;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果当前节点和下一个节点的值相同 就要一直向前直到出现不同的值</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (next && oldLinkCurrent.val ===<span style="color: rgba(0, 0, 0, 1)"> next.val) {
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (next && oldLinkCurrent.val ===<span style="color: rgba(0, 0, 0, 1)"> next.val) {
next </span>=<span style="color: rgba(0, 0, 0, 1)"> next.next;
}
oldLinkCurrent </span>=<span style="color: rgba(0, 0, 0, 1)"> next;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
newLinkCurrent </span>= newLinkCurrent.next =<span style="color: rgba(0, 0, 0, 1)"> oldLinkCurrent;
oldLinkCurrent </span>=<span style="color: rgba(0, 0, 0, 1)"> oldLinkCurrent.next;
}
}
newLinkCurrent.next </span>= <span style="color: rgba(0, 0, 255, 1)">null</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 记得结尾置空~</span>
<span style="color: rgba(0, 0, 0, 1)"> logList(dummy.next);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> dummy.next;
};
deleteDuplicates(getListFromArray([</span>1,2,3,3,4,4,5<span style="color: rgba(0, 0, 0, 1)">]));
deleteDuplicates(getListFromArray([</span>1,1,2,2,3,3,4,4,5<span style="color: rgba(0, 0, 0, 1)">]));
deleteDuplicates(getListFromArray([</span>1,1<span style="color: rgba(0, 0, 0, 1)">]));
deleteDuplicates(getListFromArray([</span>1,2,2,3,3]));</pre>
</div>
<p>本地运行结果</p>
<div class="cnblogs_code">
<pre>list: 1->2->5-><span style="color: rgba(0, 0, 0, 1)">end
list: </span>5-><span style="color: rgba(0, 0, 0, 1)">end
list: end
list: </span>1->end</pre>
</div>
<p>是不是很方便!</p>
<h2 class="heading">矩阵(二维数组)</h2>
<p>矩阵的题目也有很多,基本每一个需要用到二维数组的题,都涉及到初始化,求行数列数,遍历的代码。于是简单提取出来几个函数。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 初始化一个二维数组
* @param {number} r 行数
* @param {number} c 列数
* @param {*} init 初始值
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
const initMatrix </span>= (r, c, init = 0) => <span style="color: rgba(0, 0, 255, 1)">new</span> Array(r).fill().map(_ => <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Array(c).fill(init));
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 获取一个二维数组的行数和列数
* @param {any[][]} matrix
* @return
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
const getMatrixRowAndCol </span>= (matrix) => matrix.length === 0 ? : .length];
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 遍历一个二维数组
* @param {any[][]} matrix
* @param {Function} func
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
const matrixFor </span>= (matrix, func) =><span style="color: rgba(0, 0, 0, 1)"> {
matrix.forEach((row, i) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
row.forEach((item, j) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
func(item, i, j, row, matrix);
});
})
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 获取矩阵第index个元素 从0开始
* @param {any[][]} matrix
* @param {number} index
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getMatrix(matrix, index) {
let col </span>= matrix.length;
let i </span>= ~~(index /<span style="color: rgba(0, 0, 0, 1)"> col);
let j </span>= index - i *<span style="color: rgba(0, 0, 0, 1)"> col;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> matrix;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 设置矩阵第index个元素 从0开始
* @param {any[][]} matrix
* @param {number} index
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> setMatrix(matrix, index, value) {
let col </span>= matrix.length;
let i </span>= ~~(index /<span style="color: rgba(0, 0, 0, 1)"> col);
let j </span>= index - i *<span style="color: rgba(0, 0, 0, 1)"> col;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> matrix =<span style="color: rgba(0, 0, 0, 1)"> value;
}</span></pre>
</div>
<p>找一个简单的矩阵的题示范一下用法。@leetcode 566。题意就是将一个矩阵重新排列为r行c列。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
* @lc app=leetcode id=566 lang=javascript
*
* Reshape the Matrix
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* @param {number[][]} nums
* @param {number} r
* @param {number} c
* @return {number[][]}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> matrixReshape = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(nums, r, c) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 将一个矩阵重新排列为r行c列</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 首先获取原来的行数和列数</span>
let =<span style="color: rgba(0, 0, 0, 1)"> getMatrixRowAndCol(nums);
log(r1, c1);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 不合法的话就返回原矩阵</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (!r1 || r1 * c1 !== r * c) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> nums;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 初始化新矩阵</span>
let matrix =<span style="color: rgba(0, 0, 0, 1)"> initMatrix(r, c);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 遍历原矩阵生成新矩阵</span>
matrixFor(nums, (val, i, j) =><span style="color: rgba(0, 0, 0, 1)"> {
let index </span>= i * c1 + j; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算是第几个元素</span>
<span style="color: rgba(0, 0, 0, 1)"> log(index);
setMatrix(matrix, index, val); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 在新矩阵的对应位置赋值</span>
<span style="color: rgba(0, 0, 0, 1)"> });
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> matrix;
};
let x </span>= matrixReshape([,,,], 2, 2<span style="color: rgba(0, 0, 0, 1)">);
log(x)</span></pre>
</div>
<p> </p>
<h2 class="heading">二叉树</h2>
<p>当我做到二叉树相关的题目,我发现,我错怪链表了,呜呜呜这个更恶心。</p>
<p>当然对于二叉树,只要你掌握先序遍历,后序遍历,中序遍历,层序遍历,递归以及非递归版,先序中序求二叉树,先序后序求二叉树,基本就能AC大部分二叉树的题目了(我瞎说的)。</p>
<p>二叉树的题目 input 一般都是层序遍历的数组,所以写了层序遍历数组和二叉树的转换,方便调试。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> TreeNode(val, left = <span style="color: rgba(0, 0, 255, 1)">null</span>, right = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.val =<span style="color: rgba(0, 0, 0, 1)"> val;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.left =<span style="color: rgba(0, 0, 0, 1)"> left;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.right =<span style="color: rgba(0, 0, 0, 1)"> right;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 通过一个层次遍历的数组生成一棵二叉树
* @param {any[]} array
* @return {TreeNode}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getTreeFromLayerOrderArray(array) {
let n </span>=<span style="color: rgba(0, 0, 0, 1)"> array.length;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!n) <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
let index </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
let root </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> TreeNode(array);
let queue </span>=<span style="color: rgba(0, 0, 0, 1)"> ;
</span><span style="color: rgba(0, 0, 255, 1)">while</span>(index <<span style="color: rgba(0, 0, 0, 1)"> n) {
let top </span>=<span style="color: rgba(0, 0, 0, 1)"> queue.shift();
let v </span>= array;
top.left </span>= v == <span style="color: rgba(0, 0, 255, 1)">null</span> ? <span style="color: rgba(0, 0, 255, 1)">null</span> : <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> TreeNode(v);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (index <<span style="color: rgba(0, 0, 0, 1)"> n) {
let v </span>= array;
top.right </span>= v == <span style="color: rgba(0, 0, 255, 1)">null</span> ? <span style="color: rgba(0, 0, 255, 1)">null</span> : <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> TreeNode(v);
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (top.left) queue.push(top.left);
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (top.right) queue.push(top.right);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> root;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 层序遍历一棵二叉树 生成一个数组
* @param {TreeNode} root
* @return {any[]}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getLayerOrderArrayFromTree(root) {
let res </span>=<span style="color: rgba(0, 0, 0, 1)"> [];
let que </span>=<span style="color: rgba(0, 0, 0, 1)"> ;
</span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> (que.length) {
let len </span>=<span style="color: rgba(0, 0, 0, 1)"> que.length;
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < len; i++<span style="color: rgba(0, 0, 0, 1)">) {
let cur </span>=<span style="color: rgba(0, 0, 0, 1)"> que.shift();
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (cur) {
res.push(cur.val);
que.push(cur.left, cur.right);
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
res.push(</span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
}
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (res.length > 1 && res == <span style="color: rgba(0, 0, 255, 1)">null</span>) res.pop(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 删掉结尾的 null</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> res;
}</span></pre>
</div>
<p> </p>
<p>一个例子,@leetcode 110,判断一棵二叉树是不是平衡二叉树。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* @param {TreeNode} root
* @return {boolean}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> isBalanced = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(root) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!root) <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 认为空指针也是平衡树吧</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取一个二叉树的深度</span>
const d = (root) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!root) <span style="color: rgba(0, 0, 255, 1)">return</span> 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> _max(d(root.left), d(root.right)) + 1<span style="color: rgba(0, 0, 0, 1)">;
}
let leftDepth </span>=<span style="color: rgba(0, 0, 0, 1)"> d(root.left);
let rightDepth </span>=<span style="color: rgba(0, 0, 0, 1)"> d(root.right);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 深度差不超过 1 且子树都是平衡树</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (_min(leftDepth, rightDepth) + 1 >=<span style="color: rgba(0, 0, 0, 1)"> _max(leftDepth, rightDepth)
</span>&& isBalanced(root.left) && isBalanced(root.right)) <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
};
log(isBalanced(getTreeFromLayerOrderArray([</span>3,9,20,<span style="color: rgba(0, 0, 255, 1)">null</span>,<span style="color: rgba(0, 0, 255, 1)">null</span>,15,7<span style="color: rgba(0, 0, 0, 1)">])));
log(isBalanced(getTreeFromLayerOrderArray([</span>1,2,2,3,3,<span style="color: rgba(0, 0, 255, 1)">null</span>,<span style="color: rgba(0, 0, 255, 1)">null</span>,4,4])));</pre>
</div>
<p> </p>
<h2 class="heading">二分查找</h2>
<p>参考 C++ STL 中的 <span class="cnblogs_code">lower_bound</span> 和 <span class="cnblogs_code">upper_bound</span> 。这两个函数真的很好用的!</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 寻找>=target的最小下标
* @param {number[]} nums
* @param {number} target
* @return {number}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> lower_bound(nums, target) {
let first </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
let len </span>=<span style="color: rgba(0, 0, 0, 1)"> nums.length;
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (len > 0<span style="color: rgba(0, 0, 0, 1)">) {
let half </span>= len >> 1<span style="color: rgba(0, 0, 0, 1)">;
let middle </span>= first +<span style="color: rgba(0, 0, 0, 1)"> half;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (nums <<span style="color: rgba(0, 0, 0, 1)"> target) {
first </span>= middle + 1<span style="color: rgba(0, 0, 0, 1)">;
len </span>= len - half - 1<span style="color: rgba(0, 0, 0, 1)">;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
len </span>=<span style="color: rgba(0, 0, 0, 1)"> half;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> first;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* 寻找>target的最小下标
* @param {number[]} nums
* @param {number} target
* @return {number}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> upper_bound(nums, target) {
let first </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
let len </span>=<span style="color: rgba(0, 0, 0, 1)"> nums.length;
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (len > 0<span style="color: rgba(0, 0, 0, 1)">) {
let half </span>= len >> 1<span style="color: rgba(0, 0, 0, 1)">;
let middle </span>= first +<span style="color: rgba(0, 0, 0, 1)"> half;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (nums ><span style="color: rgba(0, 0, 0, 1)"> target) {
len </span>=<span style="color: rgba(0, 0, 0, 1)"> half;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
first </span>= middle + 1<span style="color: rgba(0, 0, 0, 1)">;
len </span>= len - half - 1<span style="color: rgba(0, 0, 0, 1)">;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> first;
}</span></pre>
</div>
<p>照例,举个例子,@leetcode 34。题意是给一个排好序的数组和一个目标数字,求数组中等于目标数字的元素最小下标和最大下标。不存在就返回 -1。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
* @lc app=leetcode id=34 lang=javascript
*
* Find First and Last Position of Element in Sorted Array
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* @param {number[]} nums
* @param {number} target
* @return {number[]}
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> searchRange = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(nums, target) {
let lower </span>=<span style="color: rgba(0, 0, 0, 1)"> lower_bound(nums, target);
let upper </span>=<span style="color: rgba(0, 0, 0, 1)"> upper_bound(nums, target);
let size </span>=<span style="color: rgba(0, 0, 0, 1)"> nums.length;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 不存在返回 [-1, -1]</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (lower >= size || nums !== target) <span style="color: rgba(0, 0, 255, 1)">return</span> [-1, -1<span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 0, 255, 1)">return</span> ;
};</span></pre>
</div>
<p> </p>
<h2 class="heading">在 VS Code 中刷 LeetCode</h2>
<p>前面说的那些模板,难道每一次打开新的一道题都要复制一遍么?当然不用啦。</p>
<p>首先配置代码片段 选择 Code -> Preferences -> User Snippets ,然后选择 JavaScript</p>
<p> </p>
<p><img src="https://user-gold-cdn.xitu.io/2019/6/22/16b7e9c0a793f7d9?w=541&h=254&f=png&s=128089" alt=""></p>
<p> </p>
<p>然后把文件替换为下面的代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"leetcode template"<span style="color: rgba(0, 0, 0, 1)">: {
</span>"prefix": "@lc"<span style="color: rgba(0, 0, 0, 1)">,
</span>"body"<span style="color: rgba(0, 0, 0, 1)">: [
</span>"const _max = Math.max.bind(Math);","const _min = Math.min.bind(Math);","const _pow = Math.pow.bind(Math);","const _floor = Math.floor.bind(Math);","const _round = Math.round.bind(Math);","const _ceil = Math.ceil.bind(Math);","const log = console.log.bind(console);","// const log = _ => {}","/**************** 链表 ****************/","/**"," * 链表节点"," * @param {*} val"," * @param {ListNode} next"," */","function ListNode(val, next = null) {"," this.val = val;"," this.next = next;","}","/**"," * 将一个数组转为链表"," * @param {array} array"," * @return {ListNode}"," */","const getListFromArray = (array) => {"," let dummy = new ListNode()"," let pre = dummy;"," array.forEach(x => pre = pre.next = new ListNode(x));"," return dummy.next;","}","/**"," * 将一个链表转为数组"," * @param {ListNode} list"," * @return {array}"," */","const getArrayFromList = (list) => {"," let a = [];"," while (list) {"," a.push(list.val);"," list = list.next;"," }"," return a;","}","/**"," * 打印一个链表"," * @param {ListNode} list "," */","const logList = (list) => {"," let str = 'list: ';"," while (list) {"," str += list.val + '->';"," list = list.next;"," }"," str += 'end';"," log(str);","}","/**************** 矩阵(二维数组) ****************/","/**"," * 初始化一个二维数组"," * @param {number} r 行数"," * @param {number} c 列数"," * @param {*} init 初始值"," */","const initMatrix = (r, c, init = 0) => new Array(r).fill().map(_ => new Array(c).fill(init));","/**"," * 获取一个二维数组的行数和列数"," * @param {any[][]} matrix"," * @return "," */","const getMatrixRowAndCol = (matrix) => matrix.length === 0 ? : .length];","/**"," * 遍历一个二维数组"," * @param {any[][]} matrix "," * @param {Function} func "," */","const matrixFor = (matrix, func) => {"," matrix.forEach((row, i) => {"," row.forEach((item, j) => {"," func(item, i, j, row, matrix);"," });"," })","}","/**"," * 获取矩阵第index个元素 从0开始"," * @param {any[][]} matrix "," * @param {number} index "," */","function getMatrix(matrix, index) {"," let col = matrix.length;"," let i = ~~(index / col);"," let j = index - i * col;"," return matrix;","}","/**"," * 设置矩阵第index个元素 从0开始"," * @param {any[][]} matrix "," * @param {number} index "," */","function setMatrix(matrix, index, value) {"," let col = matrix.length;"," let i = ~~(index / col);"," let j = index - i * col;"," return matrix = value;","}","/**************** 二叉树 ****************/","/**"," * 二叉树节点"," * @param {*} val"," * @param {TreeNode} left"," * @param {TreeNode} right"," */","function TreeNode(val, left = null, right = null) {"," this.val = val;"," this.left = left;"," this.right = right;","}","/**"," * 通过一个层次遍历的数组生成一棵二叉树"," * @param {any[]} array"," * @return {TreeNode}"," */","function getTreeFromLayerOrderArray(array) {"," let n = array.length;"," if (!n) return null;"," let index = 0;"," let root = new TreeNode(array);"," let queue = ;"," while(index < n) {"," let top = queue.shift();"," let v = array;"," top.left = v == null ? null : new TreeNode(v);"," if (index < n) {"," let v = array;"," top.right = v == null ? null : new TreeNode(v);"," }"," if (top.left) queue.push(top.left);"," if (top.right) queue.push(top.right);"," }"," return root;","}","/**"," * 层序遍历一棵二叉树 生成一个数组"," * @param {TreeNode} root "," * @return {any[]}"," */","function getLayerOrderArrayFromTree(root) {"," let res = [];"," let que = ;"," while (que.length) {"," let len = que.length;"," for (let i = 0; i < len; i++) {"," let cur = que.shift();"," if (cur) {"," res.push(cur.val);"," que.push(cur.left, cur.right);"," } else {"," res.push(null);"," }"," }"," }"," while (res.length > 1 && res == null) res.pop(); // 删掉结尾的 null"," return res;","}","/**************** 二分查找 ****************/","/**"," * 寻找>=target的最小下标"," * @param {number[]} nums"," * @param {number} target"," * @return {number}"," */","function lower_bound(nums, target) {"," let first = 0;"," let len = nums.length;",""," while (len > 0) {"," let half = len >> 1;"," let middle = first + half;"," if (nums < target) {"," first = middle + 1;"," len = len - half - 1;"," } else {"," len = half;"," }"," }"," return first;","}","","/**"," * 寻找>target的最小下标"," * @param {number[]} nums"," * @param {number} target"," * @return {number}"," */","function upper_bound(nums, target) {"," let first = 0;"," let len = nums.length;",""," while (len > 0) {"," let half = len >> 1;"," let middle = first + half;"," if (nums > target) {"," len = half;"," } else {"," first = middle + 1;"," len = len - half - 1;"," }"," }"," return first;","}"<span style="color: rgba(0, 0, 0, 1)">,
</span>"$1"<span style="color: rgba(0, 0, 0, 1)">
],
</span>"description": "LeetCode常用代码模板"<span style="color: rgba(0, 0, 0, 1)">
}
}</span></pre>
</div>
<p> </p>
<p>以后每一次写题之前,键入 <code>@lc</code> 就会出现提示,轻松加入代码模板。 </p>
<p><img src="https://user-gold-cdn.xitu.io/2019/6/22/16b7ea5270447a30?w=508&h=111&f=png&s=15530" alt=""></p>
<p> </p>
<p>当然,必须推荐刷题神器,vscode 中的一款插件 vscode-leetcode</p>
<p><strong>最后我要大声说,前端真的有机会用到算法的(不只面试)!来一起快乐刷题!</strong></p><br><br>
来源:https://www.cnblogs.com/wenruo/p/11100537.html
頁:
[1]