符合中小企业对网站设计、功能常规化式的企业展示型网站建设
本套餐主要针对企业品牌型网站、中高端设计、前端互动体验...
商城网站建设因基本功能的需求不同费用上面也有很大的差别...
手机微信网站开发、微信官网、微信商城网站...
前端刷题用js还是java
成都创新互联公司专注于泌阳企业网站建设,成都响应式网站建设,商城建设。泌阳网站建设公司,为泌阳等地区提供建站服务。全流程按需求定制制作,专业设计,全程项目跟踪,成都创新互联公司专业和态度为您提供的服务
前端刷题用js还是java_用JavaScript刷LeetCode的正确姿势

韦桂超
原创
关注
0点赞·1164人阅读
虽然很多人都觉得前端算法弱,但其实 JavaScript 也可以刷题啊!最近两个月断断续续刷完了 leetcode 前 200 的 middle + hard ,总结了一些刷题常用的模板代码。走过路过发现 bug 请指出,拯救一个辣鸡(但很帅)的少年就靠您啦!
常用函数
包括打印函数和一些数学函数。
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 = _ = {}
log 在提交的代码中当然是用不到的,不过在调试时十分有用。但是当代码里面加了很多 log 的时候,提交时还需要一个个注释掉就相当麻烦了,只要将 log 赋值为空函数就可以了。
举一个简单的例子,下面的代码是可以直接提交的。
//计算 1+2+...+n//const log = console.log.bind(console);
const log = _ ={}functionsumOneToN(n) {
let sum= 0;for (let i = 1; i = n; i++) {
sum+=i;
log(`i=${i}: sum=${sum}`);
}returnsum;
}
sumOneToN(10);
位运算的一些小技巧
判断一个整数 x 的奇偶性: x 1 = 1 (奇数) , x 1 = 0 (偶数)
求一个浮点数 x 的整数部分: ~~x ,对于正数相当于 floor(x) 对于负数相当于 ceil(-x)
计算 2 ^ n : 1 n 相当于 pow(2, n)
计算一个数 x 除以 2 的 n 倍: x n 相当于 ~~(x / pow(2, n))
判断一个数 x 是 2 的整数幂(即 x = 2 ^ n ): x (x - 1) = 0
※注意※:上面的位运算只对32位带符号的整数有效,如果使用的话,一定要注意数!据!范!围!
记住这些技巧的作用:
提升运行速度 ❌
提升逼格 ✅
举一个实用的例子,快速幂(原理自行google)
//计算x^n n为整数
functionqPow(x, n) {
let result= 1;while(n) {if (n 1) result *= x; //同 if(n%2)
x = x *x;
n= 1; //同 n=floor(n/2)
}returnresult;
}
链表
刚开始做 LeetCode 的题就遇到了很多链表的题。恶心心。最麻烦的不是写题,是调试啊!!于是总结了一些链表的辅助函数。
/**
* 链表节点
* @param {*} val
* @param {ListNode} next*/
function ListNode(val, next = null) {this.val =val;this.next =next;
}/**
* 将一个数组转为链表
* @param {array} a
* @return {ListNode}*/const getListFromArray= (a) ={
let dummy= newListNode()
let pre=dummy;
a.forEach(x= pre = pre.next = newListNode(x));returndummy.next;
}/**
* 将一个链表转为数组
* @param {ListNode} node
* @return {array}*/const getArrayFromList= (node) ={
let a=[];while(node) {
a.push(node.val);
node=node.next;
}returna;
}/**
* 打印一个链表
* @param {ListNode} node*/const logList= (node) ={
let str= 'list: ';while(node) {
str+= node.val + '-';
node=node.next;
}
str+= 'end';
log(str);
}
还有一个常用小技巧,每次写链表的操作,都要注意判断表头,如果创建一个空表头来进行操作会方便很多。
let dummy = newListNode();//返回
return dummy.next;
使用起来超爽哒~举个例子。@leetcode 82。题意就是删除链表中连续相同值的节点。
/** @lc app=leetcode id=82 lang=javascript
*
* [82] Remove Duplicates from Sorted List II*/
/**
* @param {ListNode} head
* @return {ListNode}*/
var deleteDuplicates = function(head) {//空指针或者只有一个节点不需要处理
if (head === null || head.next === null) returnhead;
let dummy= newListNode();
let oldLinkCurrent=head;
let newLinkCurrent=dummy;while(oldLinkCurrent) {
let next=oldLinkCurrent.next;//如果当前节点和下一个节点的值相同 就要一直向前直到出现不同的值
if (next oldLinkCurrent.val ===next.val) {while (next oldLinkCurrent.val ===next.val) {
next=next.next;
}
oldLinkCurrent=next;
}else{
newLinkCurrent= newLinkCurrent.next =oldLinkCurrent;
oldLinkCurrent=oldLinkCurrent.next;
}
}
newLinkCurrent.next= null; //记得结尾置空~
logList(dummy.next);returndummy.next;
};
deleteDuplicates(getListFromArray([1,2,3,3,4,4,5]));
deleteDuplicates(getListFromArray([1,1,2,2,3,3,4,4,5]));
deleteDuplicates(getListFromArray([1,1]));
deleteDuplicates(getListFromArray([1,2,2,3,3]));
本地运行结果
list: 1-2-5-end
list:5-end
list: end
list:1-end
是不是很方便!
矩阵(二维数组)
矩阵的题目也有很多,基本每一个需要用到二维数组的题,都涉及到初始化,求行数列数,遍历的代码。于是简单提取出来几个函数。
/**
* 初始化一个二维数组
* @param {number} r 行数
* @param {number} c 列数
* @param {*} init 初始值*/const initMatrix= (r, c, init = 0) = new Array(r).fill().map(_ = newArray(c).fill(init));/**
* 获取一个二维数组的行数和列数
* @param {any[][]} matrix
* @return [row, col]*/const getMatrixRowAndCol= (matrix) = matrix.length === 0 ? [0, 0] : [matrix.length, matrix[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*/
functiongetMatrix(matrix, index) {
let col= matrix[0].length;
let i= ~~(index /col);
let j= index - i *col;returnmatrix[i][j];
}/**
* 设置矩阵第index个元素 从0开始
* @param {any[][]} matrix
* @param {number} index*/
functionsetMatrix(matrix, index, value) {
let col= matrix[0].length;
let i= ~~(index /col);
let j= index - i *col;return matrix[i][j] =value;
}
找一个简单的矩阵的题示范一下用法。@leetcode 566。题意就是将一个矩阵重新排列为r行c列。
/** @lc app=leetcode id=566 lang=javascript
*
* [566] Reshape the Matrix*/
/**
* @param {number[][]} nums
* @param {number} r
* @param {number} c
* @return {number[][]}*/
var matrixReshape = function(nums, r, c) {//将一个矩阵重新排列为r行c列
//首先获取原来的行数和列数
let [r1, c1] =getMatrixRowAndCol(nums);
log(r1, c1);//不合法的话就返回原矩阵
if (!r1 || r1 * c1 !== r * c) returnnums;//初始化新矩阵
let matrix =initMatrix(r, c);//遍历原矩阵生成新矩阵
matrixFor(nums, (val, i, j) ={
let index= i * c1 + j; //计算是第几个元素
log(index);
setMatrix(matrix, index, val);//在新矩阵的对应位置赋值
});returnmatrix;
};
let x= matrixReshape([[1],[2],[3],[4]], 2, 2);
log(x)
二叉树
当我做到二叉树相关的题目,我发现,我错怪链表了,呜呜呜这个更恶心。
当然对于二叉树,只要你掌握先序遍历,后序遍历,中序遍历,层序遍历,递归以及非递归版,先序中序求二叉树,先序后序求二叉树,基本就能AC大部分二叉树的题目了(我瞎说的)。
二叉树的题目 input 一般都是层序遍历的数组,所以写了层序遍历数组和二叉树的转换,方便调试。
function TreeNode(val, left = null, right = null) {this.val =val;this.left =left;this.right =right;
}/**
* 通过一个层次遍历的数组生成一棵二叉树
* @param {any[]} array
* @return {TreeNode}*/
functiongetTreeFromLayerOrderArray(array) {
let n=array.length;if (!n) return null;
let index= 0;
let root= new TreeNode(array[index++]);
let queue=[root];while(index
let top=queue.shift();
let v= array[index++];
top.left= v == null ? null : newTreeNode(v);if (index
let v= array[index++];
top.right= v == null ? null : newTreeNode(v);
}if(top.left) queue.push(top.left);if(top.right) queue.push(top.right);
}returnroot;
}/**
* 层序遍历一棵二叉树 生成一个数组
* @param {TreeNode} root
* @return {any[]}*/
functiongetLayerOrderArrayFromTree(root) {
let res=[];
let que=[root];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[res.length - 1] == null) res.pop(); //删掉结尾的 null
returnres;
}
一个例子,@leetcode 110,判断一棵二叉树是不是平衡二叉树。
/**
* @param {TreeNode} root
* @return {boolean}*/
var isBalanced = function(root) {if (!root) return true; //认为空指针也是平衡树吧
//获取一个二叉树的深度
const d = (root) ={if (!root) return 0;return _max(d(root.left), d(root.right)) + 1;
}
let leftDepth=d(root.left);
let rightDepth=d(root.right);//深度差不超过 1 且子树都是平衡树
if (_min(leftDepth, rightDepth) + 1 =_max(leftDepth, rightDepth) isBalanced(root.left) isBalanced(root.right)) return true;return false;
};
log(isBalanced(getTreeFromLayerOrderArray([3,9,20,null,null,15,7])));
log(isBalanced(getTreeFromLayerOrderArray([1,2,2,3,3,null,null,4,4])));
二分查找
参考 C++ STL 中的 lower_bound 和 upper_bound 。这两个函数真的很好用的!
/**
* 寻找=target的最小下标
* @param {number[]} nums
* @param {number} target
* @return {number}*/
functionlower_bound(nums, target) {
let first= 0;
let len=nums.length;while (len 0) {
let half= len 1;
let middle= first +half;if (nums[middle]
first= middle + 1;
len= len - half - 1;
}else{
len=half;
}
}returnfirst;
}/**
* 寻找target的最小下标
* @param {number[]} nums
* @param {number} target
* @return {number}*/
functionupper_bound(nums, target) {
let first= 0;
let len=nums.length;while (len 0) {
let half= len 1;
let middle= first +half;if (nums[middle] target) {
len=half;
}else{
first= middle + 1;
len= len - half - 1;
}
}returnfirst;
}
照例,举个例子,@leetcode 34。题意是给一个排好序的数组和一个目标数字,求数组中等于目标数字的元素最小下标和最大下标。不存在就返回 -1。
/** @lc app=leetcode id=34 lang=javascript
*
* [34] Find First and Last Position of Element in Sorted Array*/
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}*/
var searchRange = function(nums, target) {
let lower=lower_bound(nums, target);
let upper=upper_bound(nums, target);
let size=nums.length;//不存在返回 [-1, -1]
if (lower = size || nums[lower] !== target) return [-1, -1];return [lower, upper - 1];
};
在 VS Code 中刷 LeetCode
前面说的那些模板,难道每一次打开新的一道题都要复制一遍么?当然不用啦。
首先配置代码片段 选择 Code - Preferences - User Snippets ,然后选择 JavaScript
然后把文件替换为下面的代码:
{"leetcode template": {"prefix": "@lc","body": ["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 [row, col]"," */","const getMatrixRowAndCol = (matrix) = matrix.length === 0 ? [0, 0] : [matrix.length, matrix[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[0].length;"," let i = ~~(index / col);"," let j = index - i * col;"," return matrix[i][j];","}","/**"," * 设置矩阵第index个元素 从0开始"," * @param {any[][]} matrix "," * @param {number} index "," */","function setMatrix(matrix, index, value) {"," let col = matrix[0].length;"," let i = ~~(index / col);"," let j = index - i * col;"," return matrix[i][j] = 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[index++]);"," let queue = [root];"," while(index n) {"," let top = queue.shift();"," let v = array[index++];"," top.left = v == null ? null : new TreeNode(v);"," if (index n) {"," let v = array[index++];"," 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 = [root];"," 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[res.length - 1] == 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[middle] 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[middle] target) {"," len = half;"," } else {"," first = middle + 1;"," len = len - half - 1;"," }"," }"," return first;","}","$1"],"description": "LeetCode常用代码模板"}
}
1、语法:必须比较熟悉,在写代码的时候,IDE(Integrated Development Environment,集成开发环境)的编辑器对某一行报错应该能够根据报错信息知道是什么样的语法错误,并且知道任何修正。
2、命令:必须熟悉JDK(Java Development Kit,Java开发工具箱——JDK 是整个Java的核心,包括了Java运行环境,Java工具和Java基础的类库。JDK是学好Java的第一步。)带的一些常用命令及其常用选项,命令至少需要熟悉:appletviewer、HtmlConverter、jar、 java、javac、javadoc、javap、javaw、native2ascii、serialver,如果这些命令你没有全部使用过,那么你对java实际上还很不了解。
3、工具:必须至少熟练使用一种IDE的开发工具,例如Eclipse、Netbeans、JBuilder、Jdeveloper、IDEA、JCreator或者Workshop,包括进行工程管理、常用选项的设置、插件的安装配置以及进行调试。
4、API(Application Programming Interface,应用程序编程接口):Java的核心API是非常庞大的,但是有一些内容笔者认为是必须熟悉的,否则不可能熟练的运用Java,包括:
◆java.lang包下的80%以上的类的功能的灵活运用。
◆java.util包下的80%以上的类的灵活运用,特别是集合类体系、规则表达式、zip、以及时间、随机数、属性、资源和Timer.
◆java.io包下的60%以上的类的使用,理解IO体系的基于管道模型的设计思路以及常用IO类的特性和使用场合。
◆java.math包下的100%的内容。
◆java.net包下的60%以上的内容,对各个类的功能比较熟悉。
◆java.text包下的60%以上的内容,特别是各种格式化类。
◆熟练运用JDBC. 80%、java.security包下40%以上的内容,如果对于安全没有接触的话根本就不可能掌握java.
◆AWT的基本内容,包括各种组件事件、监听器、布局管理器、常用组件、打印。
◆Swing的基本内容,和AWT的要求类似。
◆XML处理,熟悉SAX、DOM以及JDOM的优缺点并且能够使用其中的一种完成XML的解析及内容处理。
5、测试:Junit测试是程序员测试,即所谓白盒测试。一位合格的Java开发工程师必须熟悉使用junit编写测试用例完成代码的自动测试。
6、管理:必须熟悉使用Ant(中文译为蚂蚁,是一种基于Java的build工具。)完成工程管理的常用任务,例如工程编译、生成javadoc、生成jar、版本控制、自动测试。
7、排错:应该可以根据异常信息比较快速的定位问题的原因和大致位置。
8、思想:必须掌握OOP(Object Oriented Programming,面向对象编程)的主要要求,这样使用Java开发的系统才能是真正的Java系统。
9、规范:编写的代码必须符合流行的编码规范,例如类名首字母大写,成员和方法名首字母小写,方法名的第一个单词一般是动词,包名全部小写等,这样程序的可读性才比较好。
10、博学:掌握J2EE 、Oracle 、WebLogic、Jboss、Spring、Struts、Hibernate 等流行技术,掌握软件架构设计思想、搜索引擎优化、缓存系统设计、网站负载均衡、系统性能调优等实用技术。
LearnJava 在线 这是一个非常不错的学习 Java 的在线网站,纯免费。
Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。
Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。