前端刷題用js還是java
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專(zhuān)注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、成都微信小程序、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶(hù)創(chuàng)新互聯(lián)還提供了寶塔免費(fèi)建站歡迎大家使用!
前端刷題用js還是java_用JavaScript刷LeetCode的正確姿勢(shì)
?
韋桂超
原創(chuàng)
關(guān)注
0點(diǎn)贊·1164人閱讀
雖然很多人都覺(jué)得前端算法弱,但其實(shí) JavaScript 也可以刷題??!最近兩個(gè)月斷斷續(xù)續(xù)刷完了 leetcode 前 200 的 middle + hard ,總結(jié)了一些刷題常用的模板代碼。走過(guò)路過(guò)發(fā)現(xiàn) bug 請(qǐng)指出,拯救一個(gè)辣雞(但很帥)的少年就靠您啦!
常用函數(shù)
包括打印函數(shù)和一些數(shù)學(xué)函數(shù)。
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 在提交的代碼中當(dāng)然是用不到的,不過(guò)在調(diào)試時(shí)十分有用。但是當(dāng)代碼里面加了很多 log 的時(shí)候,提交時(shí)還需要一個(gè)個(gè)注釋掉就相當(dāng)麻煩了,只要將 log 賦值為空函數(shù)就可以了。
舉一個(gè)簡(jiǎn)單的例子,下面的代碼是可以直接提交的。
//計(jì)算 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);
位運(yùn)算的一些小技巧
判斷一個(gè)整數(shù) x 的奇偶性: x 1 = 1 (奇數(shù)) , x 1 = 0 (偶數(shù))
求一個(gè)浮點(diǎn)數(shù) x 的整數(shù)部分: ~~x ,對(duì)于正數(shù)相當(dāng)于 floor(x) 對(duì)于負(fù)數(shù)相當(dāng)于 ceil(-x)
計(jì)算 2 ^ n : 1 n 相當(dāng)于 pow(2, n)
計(jì)算一個(gè)數(shù) x 除以 2 的 n 倍: x n 相當(dāng)于 ~~(x / pow(2, n))
判斷一個(gè)數(shù) x 是 2 的整數(shù)冪(即 x = 2 ^ n ): x (x - 1) = 0
※注意※:上面的位運(yùn)算只對(duì)32位帶符號(hào)的整數(shù)有效,如果使用的話,一定要注意數(shù)!據(jù)!范!圍!
記住這些技巧的作用:
提升運(yùn)行速度 ?
提升逼格 ?
舉一個(gè)實(shí)用的例子,快速冪(原理自行g(shù)oogle)
//計(jì)算x^n n為整數(shù)
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;
}
鏈表
剛開(kāi)始做 LeetCode 的題就遇到了很多鏈表的題。惡心心。最麻煩的不是寫(xiě)題,是調(diào)試啊??!于是總結(jié)了一些鏈表的輔助函數(shù)。
/**
* 鏈表節(jié)點(diǎn)
* @param {*} val
* @param {ListNode} next*/
function ListNode(val, next = null) {this.val =val;this.next =next;
}/**
* 將一個(gè)數(shù)組轉(zhuǎn)為鏈表
* @param {array} a
* @return {ListNode}*/const getListFromArray= (a) ={
let dummy= newListNode()
let pre=dummy;
a.forEach(x= pre = pre.next = newListNode(x));returndummy.next;
}/**
* 將一個(gè)鏈表轉(zhuǎn)為數(shù)組
* @param {ListNode} node
* @return {array}*/const getArrayFromList= (node) ={
let a=[];while(node) {
a.push(node.val);
node=node.next;
}returna;
}/**
* 打印一個(gè)鏈表
* @param {ListNode} node*/const logList= (node) ={
let str= 'list: ';while(node) {
str+= node.val + '-';
node=node.next;
}
str+= 'end';
log(str);
}
還有一個(gè)常用小技巧,每次寫(xiě)鏈表的操作,都要注意判斷表頭,如果創(chuàng)建一個(gè)空表頭來(lái)進(jìn)行操作會(huì)方便很多。
let dummy = newListNode();//返回
return dummy.next;
使用起來(lái)超爽噠~舉個(gè)例子。@leetcode 82。題意就是刪除鏈表中連續(xù)相同值的節(jié)點(diǎn)。
/** @lc app=leetcode id=82 lang=javascript
*
* [82] Remove Duplicates from Sorted List II*/
/**
* @param {ListNode} head
* @return {ListNode}*/
var deleteDuplicates = function(head) {//空指針或者只有一個(gè)節(jié)點(diǎn)不需要處理
if (head === null || head.next === null) returnhead;
let dummy= newListNode();
let oldLinkCurrent=head;
let newLinkCurrent=dummy;while(oldLinkCurrent) {
let next=oldLinkCurrent.next;//如果當(dāng)前節(jié)點(diǎn)和下一個(gè)節(jié)點(diǎn)的值相同 就要一直向前直到出現(xiàn)不同的值
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; //記得結(jié)尾置空~
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]));
本地運(yùn)行結(jié)果
list: 1-2-5-end
list:5-end
list: end
list:1-end
是不是很方便!
矩陣(二維數(shù)組)
矩陣的題目也有很多,基本每一個(gè)需要用到二維數(shù)組的題,都涉及到初始化,求行數(shù)列數(shù),遍歷的代碼。于是簡(jiǎn)單提取出來(lái)幾個(gè)函數(shù)。
/**
* 初始化一個(gè)二維數(shù)組
* @param {number} r 行數(shù)
* @param {number} c 列數(shù)
* @param {*} init 初始值*/const initMatrix= (r, c, init = 0) = new Array(r).fill().map(_ = newArray(c).fill(init));/**
* 獲取一個(gè)二維數(shù)組的行數(shù)和列數(shù)
* @param {any[][]} matrix
* @return [row, col]*/const getMatrixRowAndCol= (matrix) = matrix.length === 0 ? [0, 0] : [matrix.length, matrix[0].length];/**
* 遍歷一個(gè)二維數(shù)組
* @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個(gè)元素 從0開(kāi)始
* @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];
}/**
* 設(shè)置矩陣第index個(gè)元素 從0開(kāi)始
* @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;
}
找一個(gè)簡(jiǎn)單的矩陣的題示范一下用法。@leetcode 566。題意就是將一個(gè)矩陣重新排列為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) {//將一個(gè)矩陣重新排列為r行c列
//首先獲取原來(lái)的行數(shù)和列數(shù)
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; //計(jì)算是第幾個(gè)元素
log(index);
setMatrix(matrix, index, val);//在新矩陣的對(duì)應(yīng)位置賦值
});returnmatrix;
};
let x= matrixReshape([[1],[2],[3],[4]], 2, 2);
log(x)
二叉樹(shù)
當(dāng)我做到二叉樹(shù)相關(guān)的題目,我發(fā)現(xiàn),我錯(cuò)怪鏈表了,嗚嗚嗚這個(gè)更惡心。
當(dāng)然對(duì)于二叉樹(shù),只要你掌握先序遍歷,后序遍歷,中序遍歷,層序遍歷,遞歸以及非遞歸版,先序中序求二叉樹(shù),先序后序求二叉樹(shù),基本就能AC大部分二叉樹(shù)的題目了(我瞎說(shuō)的)。
二叉樹(shù)的題目 input 一般都是層序遍歷的數(shù)組,所以寫(xiě)了層序遍歷數(shù)組和二叉樹(shù)的轉(zhuǎn)換,方便調(diào)試。
function TreeNode(val, left = null, right = null) {this.val =val;this.left =left;this.right =right;
}/**
* 通過(guò)一個(gè)層次遍歷的數(shù)組生成一棵二叉樹(shù)
* @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;
}/**
* 層序遍歷一棵二叉樹(shù) 生成一個(gè)數(shù)組
* @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(); //刪掉結(jié)尾的 null
returnres;
}
一個(gè)例子,@leetcode 110,判斷一棵二叉樹(shù)是不是平衡二叉樹(shù)。
/**
* @param {TreeNode} root
* @return {boolean}*/
var isBalanced = function(root) {if (!root) return true; //認(rèn)為空指針也是平衡樹(shù)吧
//獲取一個(gè)二叉樹(shù)的深度
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);//深度差不超過(guò) 1 且子樹(shù)都是平衡樹(shù)
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 。這兩個(gè)函數(shù)真的很好用的!
/**
* 尋找=target的最小下標(biāo)
* @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的最小下標(biāo)
* @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;
}
照例,舉個(gè)例子,@leetcode 34。題意是給一個(gè)排好序的數(shù)組和一個(gè)目標(biāo)數(shù)字,求數(shù)組中等于目標(biāo)數(shù)字的元素最小下標(biāo)和最大下標(biāo)。不存在就返回 -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
前面說(shuō)的那些模板,難道每一次打開(kāi)新的一道題都要復(fù)制一遍么?當(dāng)然不用啦。
首先配置代碼片段 選擇 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);","http:// const log = _ = {}","/**************** 鏈表 ****************/","/**"," * 鏈表節(jié)點(diǎn)"," * @param {*} val"," * @param {ListNode} next"," */","function ListNode(val, next = null) {"," this.val = val;"," this.next = next;","}","/**"," * 將一個(gè)數(shù)組轉(zhuǎn)為鏈表"," * @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;","}","/**"," * 將一個(gè)鏈表轉(zhuǎn)為數(shù)組"," * @param {ListNode} list"," * @return {array}"," */","const getArrayFromList = (list) = {"," let a = [];"," while (list) {"," a.push(list.val);"," list = list.next;"," }"," return a;","}","/**"," * 打印一個(gè)鏈表"," * @param {ListNode} list "," */","const logList = (list) = {"," let str = 'list: ';"," while (list) {"," str += list.val + '-';"," list = list.next;"," }"," str += 'end';"," log(str);","}","/**************** 矩陣(二維數(shù)組) ****************/","/**"," * 初始化一個(gè)二維數(shù)組"," * @param {number} r 行數(shù)"," * @param {number} c 列數(shù)"," * @param {*} init 初始值"," */","const initMatrix = (r, c, init = 0) = new Array(r).fill().map(_ = new Array(c).fill(init));","/**"," * 獲取一個(gè)二維數(shù)組的行數(shù)和列數(shù)"," * @param {any[][]} matrix"," * @return [row, col]"," */","const getMatrixRowAndCol = (matrix) = matrix.length === 0 ? [0, 0] : [matrix.length, matrix[0].length];","/**"," * 遍歷一個(gè)二維數(shù)組"," * @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個(gè)元素 從0開(kāi)始"," * @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];","}","/**"," * 設(shè)置矩陣第index個(gè)元素 從0開(kāi)始"," * @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;","}","/**************** 二叉樹(shù) ****************/","/**"," * 二叉樹(shù)節(jié)點(diǎn)"," * @param {*} val"," * @param {TreeNode} left"," * @param {TreeNode} right"," */","function TreeNode(val, left = null, right = null) {"," this.val = val;"," this.left = left;"," this.right = right;","}","/**"," * 通過(guò)一個(gè)層次遍歷的數(shù)組生成一棵二叉樹(shù)"," * @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;","}","/**"," * 層序遍歷一棵二叉樹(shù) 生成一個(gè)數(shù)組"," * @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(); // 刪掉結(jié)尾的 null"," return res;","}","/**************** 二分查找 ****************/","/**"," * 尋找=target的最小下標(biāo)"," * @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的最小下標(biāo)"," * @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常用代碼模板"}
}
界面上有個(gè)東西叫form的,form里面有個(gè)按鈕類(lèi)型是submit,
一般名字都叫提交,確定,查詢(xún)之類(lèi)的,你按了這個(gè)按鈕后,他會(huì)自己去找form中action所對(duì)應(yīng)的selvet(這個(gè)selvet在web-inf.xml中配置好了的),selvet中再調(diào)用相關(guān)的方法,查詢(xún)出數(shù)據(jù)后,通過(guò) request的request.setAttr...方法,數(shù)據(jù)傳遞到頁(yè)面上去,這樣你就看到了結(jié)果
其實(shí)這個(gè)是基本的mvc模式了
看你最后一句,你好像是說(shuō)用j2se來(lái)發(fā)送和取得信息,也是可以的.那就要用流了,用j2ee就不用考慮他們是怎么傳的,只要知道如何傳就可以了.
public類(lèi)應(yīng)該是具有啟動(dòng)函數(shù)main的類(lèi),然后在main中調(diào)用需要測(cè)試的代碼。我的理解,希望有用