目录
九、Eg[1,2,3,4,5] =1*2+2*2+3*2+4*2+5*2=30
十六、实现(5).add(3).minus(1),使得其结果为5+3-1=7
二十五、输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
用对象处理相关算法:https://blog.csdn.net/qq_29918313/article/details/98032521
算法整理:https://blog.csdn.net/qq_32766999/article/details/100654382
最大子序和、最长递增子序列:https://blog.csdn.net/qq_29918313/article/details/100232087
最长公共连续子串序列:https://blog.csdn.net/qq_29918313/article/details/102407590
和为k的子数组:https://blog.csdn.net/qq_29918313/article/details/100533780
和为目标值的整数:https://blog.csdn.net/qq_29918313/article/details/88527939
和为K的两个数(一对或多对):https://blog.csdn.net/qq_29918313/article/details/102009832
括号匹配:https://blog.csdn.net/qq_29918313/article/details/89489220
十大排序算法:https://blog.csdn.net/qq_29918313/article/details/94136234
移除数组中的元素:https://blog.csdn.net/qq_29918313/article/details/94648883
最长公共前缀:https://blog.csdn.net/qq_29918313/article/details/106455601
该文章整理了相关算法:https://www.jianshu.com/p/7c2a672fa598
一、闭包实现累加
var count = 0
var fn1 = function () {
return function (){
count++
console.log(count)
}
}
var fn2 = fn1()
fn2()
fn2()
fn2()
fn2()
闭包实现函数只有一次有效调用:
var fn1 = function (fn2) {
var result = null
return function () {
if (fn2) {
result = fn2()
fn2 = null
}
return result
}
}
var callOnce = fn1(function () {
console.log('11111')
})
callOnce ()
callOnce ()
callOnce ()
callOnce ()
二、跳台阶问题
(1)一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
function jumpFloor(number)
{
if (number === 1) return 1
if (number === 2) return 2
return jumpFloor(number - 1) + jumpFloor(number - 2)
}
(2) 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
关于本题,前提是n个台阶会有一次n阶的跳法。分析如下:
f(1) = 1
f(2) = f(2-1) + f(2-2) //f(2-2) 表示2阶一次跳2阶的次数。
f(3) = f(3-1) + f(3-2) + f(3-3)
...
f(n) = f(n-1) + f(n-2) + f(n-3) + ... + f(n-(n-1)) + f(n-n)
说明:
1)这里的f(n) 代表的是n个台阶有一次1,2,...n阶的 跳法数。
2)n = 1时,只有1种跳法,f(1) = 1
3) n = 2时,会有两个跳得方式,一次1阶或者2阶,这回归到了问题(1) ,f(2) = f(2-1) + f(2-2)
4) n = 3时,会有三种跳得方式,1阶、2阶、3阶,
那么就是第一次跳出1阶后面剩下:f(3-1);第一次跳出2阶,剩下f(3-2);第一次3阶,那么剩下f(3-3)
因此结论是f(3) = f(3-1)+f(3-2)+f(3-3)
5) n = n时,会有n中跳的方式,1阶、2阶...n阶,得出结论:
f(n) = f(n-1)+f(n-2)+...+f(n-(n-1)) + f(n-n) => f(0) + f(1) + f(2) + f(3) + ... + f(n-1)
6) 由以上已经是一种结论,但是为了简单,我们可以继续简化:
f(n-1) = f(0) + f(1)+f(2)+f(3) + ... + f((n-1)-1) = f(0) + f(1) + f(2) + f(3) + ... + f(n-2)
f(n) = f(0) + f(1) + f(2) + f(3) + ... + f(n-2) + f(n-1) = f(n-1) + f(n-1)
可以得出:
f(n) = 2*f(n-1)
7) 得出最终结论,在n阶台阶,一次有1、2、...n阶的跳的方式时,总得跳法为:
| 1 ,(n=0 )
f(n) = | 1 ,(n=1 )
| 2*f(n-1),(n>=2)
function jumpFloorII(number)
{
if (number === 0) return 0
if (number === 1) return 1
if (number === 2) return 2
return 2*jumpFloorII(number - 1)
}
(3)在你面前有一个n阶的楼梯(n>=100且n<500),你一步只能上1阶或3阶。请问计算出你可以采用多少种不同的方式爬完这个楼梯(到最后一层为爬完)。https://www.nowcoder.com/practice/1e6ac1a96c3149348aa9009709a36a6f
三、回文系列:
1.判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121
输出: true
示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。
var isPalindrome = function(x) {
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false
}
var result = (x + "").split("").reverse().join("")
if (result == x) {
return true
} else {
return false
}
};
2.给定一个字符串 s
,找到 s
中最长的回文子串。
输入: "cbbd"
输出: "bb"
var s = 'abaaa'
var aa = function (s) {
var result = ''
for (var i = 0; i < s.length; i++) {
for (var j = i + 1; j <= s.length; j++) {
var str = s.slice(i, j)
// console.log(str) // a ab aba abaa abaaa b ba baa baaa a aa aaa a aa a
var f = str.split('').reverse().join('')
console.log(f) // a ba aba aaba aaaba b ab aab aaab a aa aaa a aa a
if (str == f) {
result = str.length > result.length ? str : result
}
}
}
console.log(result)
}
aa(s)
四、js实现阶乘n!(递归形式与for循环形式)
// 非递归实现
function jiecheng(n) {
var result = 1
for (var i = n; i > 0; i--) {
result = result * i
}
console.log(result)
}
jiecheng(5)
// 递归实现
var result = 1
function jiecheng(n) {
if (n == 1) {
return 1
} else {
return n* jiecheng(n-1)
}
}
console.log(jiecheng(5))
var result = 1
function jiecheng(n) {
if (n != 1) {
result = result * n
var m = (--n)
jiecheng(m)
}
}
jiecheng(5)
console.log(result)
五、溢出问题处理
(1)大数相加
var arrA = a.split(''),//将数字转成字符串
arrB = b.split(''),
res = [],
temp = '',
carry = 0,
distance = a.length - b.length, //计算两个数值字符串的长度差
len = distance > 0 ? a.length : b.length;
//在长度小的那个数值字符串前面添加distance个0,这样两个数值的位数就保持一致,
//如:9797979797、34646,需要将这两个数值转成['0','9','7','9','7','9','7','9','7','9','7']、['0','0','0','0','0','3','4','6','4','6']
if(distance > 0){
for(let i = 0; i < distance; i++){
arrB.unshift('0');
}
}else{
for(let i = 0; i < Math.abs(distance); i++){
arrA.unshift('0');
}
}
//从数组的最后一位开始向前遍历,把两个数组对应位置的数值字符串转成整形后相加,
//carry表示相加后的进位,比如最后一位相加是7+6=13,这里进位carry是1
//在遍历的时候每次都加上上次相加后的carry进位
for(let i = len - 1; i >= 0; i--){
temp = +arrA[i] + (+arrB[i]) + carry;
if(temp > 10){
carry = 1;
res.push((temp + '')[1]);
}else{
carry = 0;
res.push(temp);
}
}
res = res.reverse().join('').replace(/^0/,'');
console.log(res)
var a = '843529812342341234'
var b = '236124361425345435'
function add(a, b) {
var res = ''
var c = 0
a = a.split('')
b = b.split('')
while(a.length || b.length || c) {
// ~是按位取反运算,~~是取反两次
c += ~~a.pop() + ~~b.pop()
res = c % 10 + res
c = c > 9
}
console.log(res.replace('/^0+/', ''))
}
add(a, b)
(2)如果阶乘出现数据溢出如何处理
https://blog.csdn.net/qq_27626645/article/details/79028972
https://blog.csdn.net/qq_34587892/article/details/76070330
六、数组乱序,前后相邻输出不一致
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2]
function luanxu(arr) {
var result = []
var len = arr.length
while(len > 0) {
var a = Math.floor(Math.random() * len)
result.push(arr[a])
arr.splice(a, 1)
len = arr.length
}
console.log(result)
}
luanxu(arr)
七、按照年龄进行分类:
[{name:”xiaoxiao’’,age:10},{name:”test”,age:10},{name:”dd”,age:9},{name:”ww”,age:6}]
var person = [{name:'xiaoxiao',age:10},{name:'test',age:10},{name:'dd',age:9},{name:'ww',age:6}]
var obj = {}
function ageClassify(person) {
for (var i = 0; i < person.length; i++) {
console.log(person[i].age)
if (obj[person[i].age] == undefined) {
obj[person[i].age] = []
obj[person[i].age][0] = person[i]
} else {
obj[person[i].age].push(person[i])
}
}
console.log(obj)
}
ageClassify(person)
// 根据年龄升序
var person = [{name:'test12',age:1},{name:'xiaoxiao',age:10},{name:'test',age:10},{name:'dd',age:9},{name:'ww',age:6}]
var obj = []
function ageClassify(person) {
person.sort((a, b) => {
return a.age - b.age
})
console.log(person)
}
ageClassify(person)
var arr =['abc','abb','abd']
console.log(arr.sort())
//[ 'abb', 'abc', 'abd' ]
八、去重系列
- 实现数组flaten(depth)传递具体的参数
var arr = [1,2,[3,4,[5,6]]] function flaten(arr, depth) { let result = [] for (var i = 0; i < arr.length; i++) { if (!Array.isArray(arr[i])) { result.push(arr[i]) } else { if (depth == 0) { result.push(arr[i]) } else { result.push(...flaten(arr[i], depth - 1)) } } } return result } console.log(flaten(arr, 1))
- 扁平化数组:https://github.com/mqyqingfeng/Blog/issues/36
console.log([1,2,3,[1,2,3],[1,2,[1,2]]].flat(2)) 结果:[1, 2, 3, 1, 2, 3, 1, 2, 1, 2] 如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。 console.log([1,2,3,[1,2,3],[1,2,[1,2,[1,[1,[1]]]]]].flat(Infinity)) 结果:[1, 2, 3, 1, 2, 3, 1, 2, 1, 2, 1, 1, 1] console.log([1, [2, [3, 4, [1,2]]]].toString().split(',')) // [ '1', '2', '3', '4', '1', '2' ]
- 数组去重:https://blog.csdn.net/qq_29918313/article/details/79135807
- 求数组求和 数组的每一项*2之后求和,利用reduce进行相加
- 对象去重:https://blog.csdn.net/qq_29918313/article/details/79135807
- 二维数组降为一维数组
var arr = [1,2,3,[1,2,3],[1,2]] function aa(arr) { var result = arr.reduce((pre, cur) => { return pre.concat(cur) }, []) console.log(result) } aa(arr)
九、Eg[1,2,3,4,5] =1*2+2*2+3*2+4*2+5*2=30
- 数组交换元素,不改变原数组[1,5,7,3,6,8]将3与8交换
- Js map实现
- 记住展开的层级,用-代表深度
十、零钱问题
var coins = [1,2,5]
var count = 11
var dp = [0]
for (var i = 1; i <= count; i++) {
dp[i] = count // 钱数为i时最少的硬币数量
}
for (var i = 0; i <= count; i++) {
for(var j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
// 当钱数为i时,最小的硬币数 = min(当前数量,dp[钱数j - 某种硬币面额] + 一张该面额)
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1)
}
}
}
console.log(dp[count] > count ? -1 : dp[count])
十一、二叉树相关
var root = {
value: 'A',
left: {
value: 'B',
left: {
value: 'D',
left: {
value: 'H',
left: null,
right: null
},
right: {
value: 'I',
left: null,
right: null
}
},
right: {
value: 'E',
left: null,
right: null
}
},
right: {
value: 'C',
left: {
value: 'F',
left: null,
right: null
},
right: {
value: 'G',
left: null,
right: null
}
}
}
const preOrderTraverse = root => {
console.log(root.value) // 访问节点(打印节点的值)
root.left && preOrderTraverse(root.left) // 若节点的左子树存在,则遍历节点的左子树
root.right && preOrderTraverse(root.right) // 若节点的右子树存在,则遍历节点的右子树
}
preOrderTraverse(root)
// A B D H I E C F G
const inOrderTraverse = root => {
root.left && inOrderTraverse(root.left) // 若节点的左子树存在,则遍历节点的左子树
console.log(root.value) // 访问节点(打印节点的值)
root.right && inOrderTraverse(root.right) // 若节点的右子树存在,则遍历节点的右子树
}
inOrderTraverse(root)
// H D I B E A F C G
const postOrderTraverse = root => {
root.left && postOrderTraverse(root.left) // 若节点的左子树存在,则遍历节点的左子树
root.right && postOrderTraverse(root.right) // 若节点的右子树存在,则遍历节点的右子树
console.log(root.value) // 访问节点(打印节点的值)
}
postOrderTraverse(root)
// H I D E B F G C A
十二、链表相关
十三、有效的括号
var str = "()[]{}"
function special(str) {
var obj = {
'(': -1,
')': 1,
'[': -2,
']': 2,
'{': -3,
'}': 3
}
var result = []
for (var i = 0; i < str.length; i++) {
if (obj[str[i]] < 0) {
result.push(str[i])
} else {
var last = result.pop()
if (obj[last] + obj[str[i]] !== 0) {
return false
}
}
}
if (result.length > 0) {
return false
} else {
return true
}
}
console.log(special(str))
十四、两个数组的交集
var nums1 = [1, 2, 2, 1, 3,3,4,5,3]
var nums2 = [2, 2, 3,3,4,3]
var result = []
nums1.forEach(function(val) {
if(nums2.includes(val)) {
result.push(val);
}
})
console.log(result); // [ 2, 2, 3, 3, 4, 3 ]
var nums1 = [1, 2, 2, 1, 3,3,4,5,3]
var nums2 = [2, 2, 3,3,4,3]
var result = []
function common(nums1, nums2) {
for (var i = 0; i < nums1.length; i++) {
for (var j = 0; j < nums2.length; j++) {
if (nums1[i] === nums2[j]) {
result.push(nums1[i])
nums1.splice(i, 1)
i--
nums2.splice(j, 1)
j--
}
continue
}
}
return result
}
console.log(common(nums1, nums2)) // [ 2, 2, 3, 3, 4, 3 ]
十五、对象格式处理
已知:
var entry = {
a: {
b: {
c: {
dd: 'abcdd'
}
},
d: {
xx: 'adxx'
},
e: 'ae'
}
}
// 要求转换成如下对象
var output = {
'a.b.c.dd': 'abcdd',
'a.d.xx': 'adxx',
'a.e': 'ae'
}
var keys = []
var output = {}
function flatObj(entry, output) {
for (var key in entry) {
var res = entry[key];
keys.push(key);
if (typeof res === "object") {
flatObj(res, output);
} else {
output[keys.join(".")] = res;
}
keys.pop();
console.log(keys)
}
}
flatObj(entry, output);
console.log(output);
// 已知:
var output = {
'a.b.c.dd': 'abcdd',
'a.d.xx': 'adxx',
'a.e': 'ae'
}
// 要求转换成如下对象
var entry = {
a: {
b: {
c: {
dd: 'abcdd'
}
},
d: {
xx: 'adxx'
},
e: 'ae'
}
}
对象entry的key中含有的.就是一个对象嵌套,所以可以用split()函数将其划分为一个array,所以array的length - 1下标所对应的元素就是entry的一个key的具体值。
利用对象为地址引用原理,进行增加元素。
采用reduce函数,将每一次的引用返回。
const entry = {
'a.b.c.dd': 'abcdd',
'a.d.xx': 'adxx',
'a.e': 'ae',
};
const changObjStructureOfNormal = output => {
const keys = Object.keys(output);
const resObj = {};
for (const key of keys) {
const everyKey = key.split('.');
everyKey.reduce((pre, next, index, array) => {
if (index === array.length - 1) {
pre[next] = output[key];
return;
}
pre[next] = pre[next] || {};
return pre[next];
}, resObj);
}
return resObj;
};
console.log(changObjStructureOfNormal(entry))
// 原始数组
let arr =[
{id:1,name:'部门A',parentId:0},
{id:2,name:'部门B',parentId:0},
{id:3,name:'部门C',parentId:1},
{id:4,name:'部门D',parentId:1},
{id:5,name:'部门E',parentId:2},
{id:6,name:'部门F',parentId:3},
{id:7,name:'部门G',parentId:2},
{id:8,name:'部门H',parentId:4}
]
// 转换后的结果如下
let result = [
{
id: 1,
name: '部门A',
parentId: 0,
children: [
{
id: 3,
name: '部门C',
parentId: 1,
children: [
{
id: 6,
name: '部门F',
parentId: 3
}, {
id: 16,
name: '部门L',
parentId: 3
}
]
},
{
id: 4,
name: '部门D',
parentId: 1,
children: [
{
id: 8,
name: '部门H',
parentId: 4
}
]
}
]
},
···
];
function convert(arr) {
let tree = [];
arr.map((it, idx, array) => {
console.log(array)
let parent = it.parentId;
if (parent === 0) { // 根节点
tree.push(it);
} else {
array.map(item => {
if (item.id === parent) {
if (!item.children) {
item.children = [];
}
item.children.push(it);
}
});
}
});
return tree;
}
console.log(convert(arr))
十六、实现(5).add(3).minus(1),使得其结果为5+3-1=7
Number.prototype.add = function (n) {
return this.valueOf() + n
}
Number.prototype.minus = function (n) {
return this.valueOf() - n
}
var a = (5).add(3).minus(1)
console.log(a) // 7
十七、按月份统计销售额
{1:222, 2:123, 5:888},请把数据处理为如下结构:[222, 123, null, null, 888, null, null, null, null, null, null, null]
var obj = {1:222, 2:123, 5:888}
var arr = [1, 2, 3, 4, 5,6,7,8,9,10,11,12]
var result = []
for (var i = 0; i < arr.length; i++) {
for (var k in obj) {
if (arr[i] == k) {
result[i] = obj[k]
break
} else {
result[i] = null
}
}
}
console.log(result)
// 生成月份
var arr1 = Array.from({length: 12}, (v, k) => k)
console.log(arr1)
十八、正则相关
g修饰符用语规定正则表达式执行全局匹配,也就是在找到第一个匹配之后仍然会继续查找。
1.驼峰式转换
var str = 'border-bottom-color'
var reg = /-(\w)/g
var str1 = str.replace(reg, function ($0, $1) {
return $1.toUpperCase()
})
console.log(str1) // borderBottomColor
// $0代表匹配到的东西 -b,-c;$1代表第一个括号,就是用B去替换-b,用C去替换-c
2.校验email
var email = 'dsdfs_sdfsf@sina.com'
var reg2 = /^\w+@\w+\.[a-z]{2,4}$/i // i为统一转化为小写
console.log(reg.test(email))
var reg1 = /^\w+@\w+\.[a-zA-Z]{2,4}$/
var reg2 = /^\w+@\w+\.[a-z]{2,4}$/i
3.校验手机号
var phone = '13865636710'
var reg = /^1[3|5|7|8|9](\d){9}$/
4.大小写转换
var str = 'vvQwesdfQWE'
var reg = /[a-z]/
var result = []
for (var i = 0; i < str.length; i++) {
if (reg.test(str[i])) {
result.push(str[i].toUpperCase())
} else {
result.push(str[i].toLowerCase())
}
}
var result1 = result.join('')
console.log(result1)
var str = 'border-bottom-color'
var reg = /-(\w)(\w)/g
str=str.replace(reg,function($0,$1,$2){
return $1.toUpperCase()+$2.toUpperCase()
})
console.log(str) //borderBOttomCOlor
5.千分位分割
var a = '2221221225.88';
var b = a.replace(/(\d{3})(?=\d)/g, '$1,')
解析:如下第一个括号(\d{3})代表的是3个数字;
第二个括号\d代表数字,也就是在满足前面的情况下,下一个是数字的就满足要匹配的东西;
$1代表第一个括号的内容;结果如下console.log(b)//222,122,122,5.88
正则表达式(?=pattern)的语法
正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,”Windows(?=95|98|NT|2000)”能匹配”Windows2000”中的”Windows”,但不能匹配”Windows3.1”中的”Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
同样,通过这三个列子的结果,我们也可以理解下面这句话了
预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
我们再来对比一下列1和列2
var a = '13245646';
//列1
var reg1 = /(\d{3})(\d)/g
var reg2 = /(\d{3})(?=\d)/g
console.log('reg1:', a.match(reg1) )
console.log('reg2:',a.match(reg2) )
//输出
//reg1: (2) ["1324", "5646"]
//reg2: (2) ["132", "456"]
可以看到reg1在下一次的匹配中,是从(\d)之后的下一个字符开始匹配,而reg2中的下一次匹配时,却是直接从(\d{3})的下一个字符开始匹配。
6.将某个字符替换中想要的字符
// 将所有的3替换成9
var phone = '13865636710'
var reg = /[3]/g
var a = phone.replace(reg, '9')
console.log(a)
7.判断输入的是否是正确的网址
var str = 'https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/138'
var reg = /^(https?:\/\/)?([a-z0-9]\.|[a-z0-9][-a-z0-9]*[a-z0-9]\.)*([a-z]+)(:\d+)?(\/.*)?$/
console.log(reg.test(str))
十九、随机生成一个数组,并按规则将其转化为二维数组
随机生成一个长度为 10 的整数类型的数组,例如 [2, 10, 3, 4, 5, 11, 10, 11, 20],将其排列成一个新数组,要求新数组形式如下,例如 [[2, 3, 4, 5], [10, 11], [20]]
// 得到一个两数之间的随机整数,包括两个数在内
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
}
// 随机生成10个整数数组, 排序, 去重
let initArr = Array.from({ length: 10 }, (v) => { return getRandomIntInclusive(0, 99) });
initArr.sort((a,b) => { return a - b });
initArr = [...(new Set(initArr))];
var obj = {}
for (var i = 0; i < initArr.length; i++) {
var result = Math.floor(initArr[i] / 10)
if(!obj[result]) {
obj[result] = []
obj[result][0] = initArr[i]
} else {
obj[result].push(initArr[i])
}
}
var result = []
for (var k in obj) {
result.push(obj[k])
}
console.log(result) //[ [ 17 ],[ 23 ],[ 30, 37 ],[ 43, 46 ],[ 56 ],[ 63, 69 ],[ 77 ] ]
二十、旋转数组
原数组中的元素向右移动K位。
var arr = [1, 2, 3, 4, 5, 6, 7]
var k = 3
function rotate(arr, k) {
if (k == 0) return arr
var newArr = arr.splice(arr.length - k)
// newArr.push.apply(newArr, arr)
// console.log(newArr)
var result = [...newArr, ...arr]
console.log(result)
}
rotate(arr, k)
二十一、移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
function move(arr){
var n = 0;
for(var i = 0; i < arr.length; i++){
if(arr[i] === 0){
arr.splice(i, 1);
n++;
i--;
}
}
while(n--){
arr.push(0);
}
return arr;
}
console.log(move(arr))
二十二、求两个数组的中位数
var nums1 = [1, 2]
var nums2 = [3]
nums1.push.apply(nums1, nums2)
nums1.sort((a, b) => {
return a - b
})
var result = 0
var mid = nums1.length/2
if (nums1.length % 2 == 0) {
result = (nums1[mid - 1] + nums1[mid]) / 2
} else {
result = nums1[Math.floor(mid)]
}
console.log(result)
二十三、数值范围内1的个数,从1开始的某个范围
function NumberOf1Between1AndN(n){
let count = 0;
for (let i = 0; i <= n; i++) {
let temp = i;
while (temp > 0) {
if (Math.floor(temp % 10) == 1) {
count++;
}
temp /= 10;
}
}
return count;
}
var n = 20
console.log(NumberOf1Between1AndN(n))
二十四、判断出栈顺序是否合法
var stackA = [1,2,3,4,5]
var stackB = [3,1,2,5,4]
function aa(stackA, stackB) {
var result = []
var j = 0
for (var i = 0; i < stackA.length; i++) {
result.push(stackA[i])
while(result.length != 0 && result[result.length - 1] == stackB[j]) {
result.pop()
j++
}
}
if (result.length == 0) {
return true
} else {
return false
}
}
console.log(aa(stackA, stackB))
二十五、输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
function NumberOf1(n)
{
if(n < 0) {
n = n >>> 0
}
var newN = n.toString(2).split('1')
return newN.length - 1
}
二十六、输入一个链表,输出该链表中倒数第k个结点。
function FindKthToTail(head, k)
{
var arr = []
while(head != null) {
arr.push(head)
head = head.next
}
return arr[arr.length - k]
}
二十七、两个数不使用四则运算得出和
function sum(a, b) {
if (a == 0) return b
if (b == 0) return a
var newA = a ^ b
var newB = (a & b) << 1
return sum(newA, newB)
}
console.log(sum(10, 11))
二十八、0 - 1背包问题
该问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。每个问题只能放入至多一次。
假设我们有以下物品
物品 ID / 重量 | 价值 |
---|---|
1 | 3 |
2 | 7 |
3 | 12 |
对于一个总容量为 5 的背包来说,我们可以放入重量 2 和 3 的物品来达到背包内的物品总价值最高。
对于这个问题来说,子问题就两个,分别是放物品和不放物品,可以通过以下表格来理解子问题
物品 ID / 剩余容量 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
1 | 0 | 3 | 3 | 3 | 3 | 3 |
2 | 0 | 3 | 7 | 10 | 10 | 10 |
3 | 0 | 3 | 7 | 12 | 15 | 19 |
直接来分析能放三种物品的情况,也就是最后一行
- 当容量少于 3 时,只取上一行对应的数据,因为当前容量不能容纳物品 3
- 当容量 为 3 时,考虑两种情况,分别为放入物品 3 和不放物品 3
- 不放物品 3 的情况下,总价值为 10
- 放入物品 3 的情况下,总价值为 12,所以应该放入物品 3
- 当容量 为 4 时,考虑两种情况,分别为放入物品 3 和不放物品 3
- 不放物品 3 的情况下,总价值为 10
- 放入物品 3 的情况下,和放入物品 1 的价值相加,得出总价值为 15,所以应该放入物品 3
- 当容量 为 5 时,考虑两种情况,分别为放入物品 3 和不放物品 3
- 不放物品 3 的情况下,总价值为 10
- 放入物品 3 的情况下,和放入物品 2 的价值相加,得出总价值为 19,所以应该放入物品 3
以下代码对照上表更容易理解
/**
* @param {*} w 物品重量
* @param {*} v 物品价值
* @param {*} C 总容量
* @returns
*/
function knapsack(w, v, C) {
let length = w.length
if (length === 0) return 0
// 对照表格,生成的二维数组,第一维代表物品,第二维代表背包剩余容量
// 第二维中的元素代表背包物品总价值
let array = new Array(length).fill(new Array(C + 1).fill(null))
// 完成底部子问题的解
for (let i = 0; i <= C; i++) {
// 对照表格第一行, array[0] 代表物品 1
// i 代表剩余总容量
// 当剩余总容量大于物品 1 的重量时,记录下背包物品总价值,否则价值为 0
array[0][i] = i >= w[0] ? v[0] : 0
}
// 自底向上开始解决子问题,从物品 2 开始
for (let i = 1; i < length; i++) {
for (let j = 0; j <= C; j++) {
// 这里求解子问题,分别为不放当前物品和放当前物品
// 先求不放当前物品的背包总价值,这里的值也就是对应表格中上一行对应的值
array[i][j] = array[i - 1][j]
// 判断当前剩余容量是否可以放入当前物品
if (j >= w[i]) {
// 可以放入的话,就比大小
// 放入当前物品和不放入当前物品,哪个背包总价值大
array[i][j] = Math.max(array[i][j], v[i] + array[i - 1][j - w[i]])
}
}
}
return array[length - 1][C]
}