3、一个数组 par 中存放有多个人员的信息,每个人员的信息由年龄 age 和姓名 name 组成,如{age: 2, name: 'xx'}。请写一段 JS 程序,对这个数组按年龄从小到大进行排序。
优化:
function parSort(par) {
return par.sort(function(arr1, arr2) {
return arr1.age > arr2.age ? -1 : 1;
});
}
4、有字符串 var = 'abc345efgabcab',请写出 3 条 JS 语句分别实现如下 3 个功能:
1)去掉字符串中的a、b、c 字符,形成结果:'345efg'
2)将字符串中的数字用中括号括起来,形成结果:'abc3[5]efgabcab'
3)将字符串中的每个数字的值分别乘以 2,形成结果:'abc6810efgabcab'
我的:
var str= 'abc345efgabcab';
var arrStr=str.split('');
var result= arrStr.filter(function(s){
return s=='a' || s=='b' || s=='c'?'':s
}).join('')
var result=[];
arrStr.forEach(function(s){
var num=s;
if(Number(s)==s){
num='['+num+']'
}
result.push(num)
})
result.join('');
这个时候对正则表达式还不了解,看了别人的发现用正则表达式会非常简洁
优化:
// 1)
str.replace(/([a-c])/g, '');
// 2)
str.replace(/(\d)/g, '[$1]');
// 3)
str.replace(/(\d)/g, function(num) {return num*2;});
5、请写一段 JS 程序类,定义一个列表类List,该类包含两个成员:属性 length(表示列表中的元素个数)和方法 add (像列表中添加元素),其中要求构造函数和 add 方法的参数为动态参数。
我的:
function List() {
this.data = [];
for(var i in arguments){
this.data.push(arguments[i])
}
this.length = this.data.length;
this.add = function () {
for(var i in arguments){
this.data.push(arguments[i])
this.length++;
}
}
}
var newlist = new List('a', 'b', 'c');
//newlist.add('a', 'b')
arguments
对象不是一个 Array
。它类似于Array
,但除了length属性和索引元素之外没有任何Array
属性
6、请问这个 JS 程序有什么问题?应该如何优化?
function setStyle(element) {
element.style.fontWeight = "bold";
element.style.textDecoration = "none";
element.style.color = "#000000";
}
优化:
function setStyle(element) {
if (!element.style) {
return;
}
var eleStyle = element.style;
eleStyle.fontWeight = "bold";
eleStyle.textDecoration = "none";
eleStyle.color = "#000000";
}
7、请写出一下正则表达式:
1)匹配一个全部是数字的字符串
2)提取一个 url 所使用的协议类型如 http、ftp 和 host 名称
我的:
var patt1= /^\d+$/
var patt2 = /^(\w+):\/\/w*\.?(\w+)\.\w+\/.*\.(\w+)/;
8、请使用闭包的方式,写一段 JS 程序实现如下功能:函数每调用一次则该函数的返回值加 1。
我的:
function creatSumFun(){
var s=0;
return function(){
return ++s;
}
}
var sumFun=creatSumFun();
sumFun();
9、请写出下面 JS 程序中几个 document.write 的结果:
function Parent() {
this.a = 1;
this.b = [1, 2, this.a];
this.c = {demo: 5};
this.show = function() {
document.write(this.a + ' ' + this.c.demo + ':' + this.b + '
')
}
}
function Child() {
this.a = 2;
this.change = function() {
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;
}
}
Child.prototype = new Parent();
var parent = new Parent();
var child1 = new Child();
var child2 = new Child();
child1.a = 11;
child2.a = 12;
parent.show();
child1.show();
child2.show();
child1.change();
child2.change();
parent.show();
child1.show();
child2.show();
我的:无
真的是基础不行,看了好久发现是js的继承,继续努力!
11、请用 js 程序实现二分算法。
function midSearch(arr , target){
var low=0;
var heigh=arr.length-1;
while (low<=heigh) {
var mid=parseInt(low+(heigh-low)/2);
if(target>arr[mid]){ low=mid+1 }
if(target
12、有这样一个 URL:http://vip.qq.com/a.php?a=1&b...,请写一段 JS 程序提取 URL 中的各个参数(参数名和参数个数不确定),将其按 key-value 形式返回到一个 json 结构中,如{a:'1',b:'2',c:'',d:'xxx',e:undefined}。
function getQueJson(url) {
var url=url.split('?');
var part = /\w+(=)?(\w+)*/g;
var str = url.match(part);
var json = {};
for (var i = 0; i < str.length; i++) {
var s = str[i].split('=');
json[s[0]] = s[1]==''?undefined:s[1];
} return json }
2019.3.20 再次更新 奋战秋招!!!
13.柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。简单理解,就是指,我们将预定义的函数的参数逐一传入到curryIt中,当参数全部传入之后,就执行预定义函数。
me
function curryIt(fn) {
var args = [];
var length=fn.length;
var cr = function (x) {
args.push(x);
if (args.length === length) {
return fn.apply(null, args);
} else {
return cr;
}
};
return cr
}
var fn = function (a, b, c) {
return a + b + c;
};
var r = curryIt(fn)(1)(2)(3);
console.log(r);
arguments.callee
链接:https://www.nowcoder.com/questionTerminal/bb78d69986794470969674a8b504ac00
来源:牛客网
function curryIt(fn) {
//获取fn参数的数量
var n = fn.length;
//声明一个数组args
var args = [];
//返回一个匿名函数
return function(arg){
//将curryIt后面括号中的参数放入数组
args.push(arg);
//如果args中的参数个数小于fn函数的参数个数,
//则执行arguments.callee(其作用是引用当前正在执行的函数,这里是返回的当前匿名函数)。
//否则,返回fn的调用结果
if(args.length < n){
return arguments.callee;
}else return fn.apply("",args);
}
}
14.属性遍历 获取对象属性的方法很多其中只获取自身属性的(不在原型链上)有 Object.keys (可枚举) 和getOwnPropertyNames(包括不可枚举的)、获取所有属性的 for-in (可枚举), 用来判断是否是自身属性的hasOwnProperty
me
// 获取自身属性
function iterate(obj) {
return Object.keys(obj).map(function(key){
return key + ": " + obj[key];
})
}
all
链接:https://www.nowcoder.com/questionTerminal/0158a4f165154f2eaf27d1907aa55e57
来源:牛客网
function iterate(obj) {
const res = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
res.push(prop + ": " + obj[prop]);
}
}
return res;
}
function iterate(obj) {
return Object.getOwnPropertyNames(obj).map(function(key) {
return key + ": " + obj[key];
});
}
15.检查连续重复字符串
在正则表达式中,利用()进行分组,使用斜杠加数字表示引用,\1就是引用第一个分组,\2就是引用第二个分组。将[a-zA-Z]做为一个分组,然后引用,就可以判断是否有连续重复的字母。
function containsRepeatingLetter(str) {
return /([a-zA-Z])\1/.test(str);
}
16.从上往下打印二叉树
使用两个队列一个存放节点,一个存放值。先将根节点加入到队列中,然后遍历队列中的元素,遍历过程中,访问该元素的左右节点,再将左右子节点加入到队列中来
function PrintFromTopToBottom(root) {
if(!root){
return []
}
var res = [];
var list = [root];
while(list.length!==0){
var temp = list.shift();
if(temp.left){
list.push(temp.left);
}
if(temp.right){
list.push(temp.right);
}
res.push(temp.val);
}
return res;
}
17.复杂链表的复制
1、复制每个节点,如:复制节点A得到A1,将A1插入节点A后面
2、遍历链表,A1->random = A->random->next;
3、将链表拆分成原链表和复制后的链表
function Clone(pHead) {
if(!pHead) return null;
var curNode = pHead;
// 在每个节点添加复制节点
while(curNode){
let node = new RandomListNode(curNode.label);
node.next = curNode.next;
curNode.next = node;
curNode = node.next;
}
// 为每个复制节点添加random节点
curNode = pHead;
while(curNode){
let node = curNode.next; // node既为复制节点
if(curNode.random){
node.random = curNode.random.next;
}
curNode = node.next;
}
// 拆分
curNode = pHead;
var pCloneHead = pHead.next;
while(curNode.next){
var tmp = curNode.next;
curNode.next = tmp.next;
curNode = tmp;
}
return pCloneHead;
}
18.二叉搜索树与双向链表
二叉搜索树 中序遍历 的结果就是升序数组
节点的前一个元素是左子树上的最右的一个端点,后一个元素是右子树最左的一个端点
function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
}
function Convert(pRootOfTree) {
if (!pRootOfTree) {
return null
}
var pre = null;
var ConvertList = function (node) {
if (!node) {
return
}
ConvertList(node.left);
node.left = pre;
if (pre) {
pre.right = node;
}
pre = node;
ConvertList(node.right);
}
ConvertList(pRootOfTree);
var res = pRootOfTree;
while (res.left) {
res = res.left;
}
return res;
}
19.连续子数组的最大和
例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和
me
function FindGreatestSumOfSubArray(array) {
if (!array) {
return null;
}
var res = array[0];
var start = 0;
while (start < array.length) {
var sum = array[start];
var maxSum = sum;
for (let i = start + 1; i < array.length; i++) {
sum += array[i];
maxSum = sum > maxSum ? sum : maxSum;
}
res = res < maxSum ? maxSum : res;
start++;
}
return res;
}
这道题最好的方是使用动态规划
function FindGreatestSumOfSubArray(array) {
if (!array) {
return null;
}
var sum = array[0];
var sumTemp = array[0];
for (var i = 1; i < array.length; i++) {
sumTemp = Math.max(sumTemp + array[i], array[i]);
sum = Math.max(sumTemp, sum);
}
return sum;
}
20.把数组排成最小的数
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路:先将数组排序,比较规则为:两数字符串相加(顺序不同),较小结果前面的数排在前面
me
function PrintMinNumber(numbers) {
numbers.sort(function (a, b) {
return addString(a, b) - addString(b, a);
});
return numbers.join('');
}
function addString(a, b) {
return Number(a + '' + b);
}
21.丑数
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路复杂 直接上链接https://www.nowcoder.com/questionTerminal/6aa9e04fc3794f68acf8778237ba065b
总结:首先从丑数的定义我们知道,一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,
换句话说一个丑数一定由另一个丑数乘以2或者乘以3或者乘以5得到
那么我们从1开始乘以2,3,5,就得到2,3,5三个丑数,在从这三个丑数出发乘以2,3,5就得到4,6,10,6,9,15,10,15,25九个丑数,
我们发现这种方法会得到重复的丑数,而且我们题目要求第N个丑数,这样的方法得到的丑数也是无序的
我们可以定义一个丑数数组,将这个乘以2,3,5得出后的数中最小的那个放入数组,以此循环就是有序的丑数数组
22.二叉树的深度
me
function TreeDepth(pRoot) {
if (!pRoot) {
return 0;
}
var tempDepth = 0;
var maxDepth = 0;
var preOrder = function (node) {
if (node === null) {
if (tempDepth > maxDepth) {
maxDepth = tempDepth;
}
return
}
tempDepth++;
preOrder(node.left);
preOrder(node.right);
tempDepth--;
}
preOrder(pRoot);
return maxDepth;
}
better
function TreeDepth(pRoot) {
if (!pRoot) {
return 0;
}
var left = TreeDepth(pRoot.left);
var right = TreeDepth(pRoot.right);
return Math.max(left, right) + 1;
}
23.数组中只出现一次的数字
hashMap 或者 异或
me
// 使用es6 中的 Set对象
function FindNumsAppearOnce(array)
{
var setList = new Set();
for (var num of array) {
if (setList.has(num)) {
setList.delete(num);
} else {
setList.add(num);
}
}
return [...setList];
}
// 不使用特性
function FindNumsAppearOnce(array) {
var hashMap = {}
for (var i of array) {
if (String(i) in hashMap) {
hashMap[String(i)] += 1;
} else {
hashMap[String(i)] = 1;
}
}
res = [];
for (var k of Object.keys(hashMap)) {
if (hashMap[k] == 1) {
res.push(Number(k))
}
}
return res
}
24.和为S的连续正数序列
me
function FindContinuousSequence(sum) {
if (sum < 2) {
return sum;
}
var res = [];
var queue = [];
for (var i = 1; i <= Math.ceil(sum / 2) + 1; i++) {
queue.push(i);
if (listSum(queue) > sum) {
queue = queueShift(queue, sum);
}
if (listSum(queue) === sum) {
if (queue.length > 1) {
res.push(queue.slice());
}
}
}
return res;
}
function queueShift(queue, target) {
if (listSum(queue) > target) {
queue.shift();
queueShift(queue, target);
}
return queue;
}
function listSum(list) {
return list.length !== 0 ? list.reduce(function (total, value) {
return total + value;
}) : null;
}
我完全想复杂了,需要优化的地方1.连续正数序列就是等差数列,可直接求和不需要遍历 2.不需要使用队列移动,只需定义两个遍历记录前后位置即可(移动窗口)
better
待完成
25.不用加减乘除做加法
function Add(num1, num2) {
var n1 = num1 ^ num2; // ^异或 做加法
var n2 = (num1 & num2) << 1; // &与 模拟进位
while (n1 & n2) { // 如果没有进位表示运算结束
num1 = n1;
num2 = n2;
n1 = num1 ^ num2;
n2 = (num1 & num2) << 1;
}
return n1 | n2;
}
26.数组中重复的数字
https://www.nowcoder.com/questionTerminal/623a5ac0ea5b4e5f95552655361ae0a8
27.输出斐波那契数列的第n项(从0开始,第0项为0)。
f(n) = fn(n-1) + f(n-2) ,典型的递归。但递归其实不好会有很多重复的计算
Fibonacci(4) = Fibonacci(3) + Fibonacci(2);
= Fibonacci(2) + Fibonacci(1) + Fibonacci(1) + Fibonacci(0);
= Fibonacci(1) + Fibonacci(0) + Fibonacci(1) + Fibonacci(1) + Fibonacci(0);
me
function Fibonacci(n) {
if (n == 0) {
return 0
}
if (n == 1) {
return 1
}
return Fibonacci(n - 1) + Fibonacci(n - 2)
}
better 动态规划
function Fibonacci(n)
{
var f = 0;
var g = 1;
while (n--) {
g += f;
f = g - f;
}
return f;
}
27.合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
me 迭代,找出较小的头结点的链表,为主轴,将另一条链表插入主轴
function ListNode(x) {
this.val = x;
this.next = null;
}
function Merge(pHead1, pHead2) {
if (!pHead1 && !pHead2) {
return null;
}
if (!pHead1) {
return pHead2;
}
if (!pHead2) {
return pHead1;
}
var sHead = null;
var bHead = null;
if (pHead1.val <= pHead2.val) {
sHead = pHead1;
bHead = pHead2;
} else {
sHead = pHead2;
bHead = pHead1;
}
var head = sHead;
while (bHead) {
if (sHead.next && bHead.val < sHead.next.val) {
var tmpNode = bHead;
bHead = bHead.next;
tmpNode.next = sHead.next;
sHead.next = tmpNode;
}
if (bHead && !sHead.next) {
sHead.next = bHead;
break;
}
sHead = sHead.next
}
return head;
}
other: 递归,代码简洁很多
28.二叉搜索树的后序遍历序列
BST的后序序列的合法序列是,对于一个序列S,最后一个元素是x (也就是根),如果去掉最后一个元素的序列为T,那么T满足:T可以分成两段,前一段(左子树)小于x,后一段(右子树)大于x,且这两段(子树)都是合法的后序序列。
29.二叉树中和为某一值的路径
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
me
function FindPath(root, expectNumber) {
if (!root) {
return [];
}
var res = [];
var sum = 0;
var temp = [root.val];
var preOrder = function (node) {
sum += node.val;
if (sum === expectNumber && !node.left && !node.right) {
res.push(temp.slice());
return;
}
if (node.left) {
temp.push(node.left.val);
preOrder(node.left);
sum -= node.left.val;
temp.pop();
}
if (node.right) {
temp.push(node.right.val);
preOrder(node.right);
sum -= node.right.val;
temp.pop();
}
}
preOrder(root);
return res;
}
other 更加精简
var res = [];
var temp = [];
function FindPath(root, expectNumber) {
if (!root) {
return res;
}
temp.push(root.val);
expectNumber -= root.val;
if (expectNumber === 0 && !root.left && !root.right) {
res.push(temp.slice());
}
FindPath(root.left, expectNumber);
FindPath(root.right, expectNumber);
temp.pop();
return res;
}
30.数字在排序数组中出现的次数
找出k + 0.5,k - 0.5的位置相减
me
function GetNumberOfK(data, k) {
return biSearch(data, k + 0.5) - biSearch(data, k - 0.5);
}
function biSearch(arr, k) {
var s = 0;
var e = arr.length - 1;
var mid;
while (s <= e) {
mid = parseInt((s + e) / 2);
if (arr[mid] < k) {
s = mid + 1;
}
if (arr[mid] > k) {
e = mid - 1;
}
}
return s;
}
31.扑克牌顺子
如果给的数组能组成顺子就输出true,否则就输出false
思路:
1.正常的,排序后再判断,快排的话时间复杂度nlogn
2.max - min < 5、除0外没有重复的数字(牌)、数组长度 为5。时间复杂度n。重复判断可以利用hash表或set
32.孩子们的游戏(圆圈中最后剩下的数)
他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友
分析:约瑟夫环
解:1.模拟游戏过程
2.数学归纳法分析约瑟夫环
33.构建乘积数组
给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。