本文仅供自己复习用
1、剑指 Offer 13. 机器人的运动范围
a、BFS
如图红色表示入队列顺序,可以看出其实每一步只是往右走和往下走,而且会有重复
/**
* @param {number} m
* @param {number} n
* @param {number} k
* @return {number}
*/
var movingCount = function(m, n, k) {
let queue = ['0,0']
let res = 0
let getSum = function(num) {
let sum = 0
while(num !== 0) {
sum += num % 10
num = Math.floor(num / 10)
}
return sum
}
let map = new Map()
while(queue.length !== 0) {
let [row, col] = queue.shift().split(',')
row = parseInt(row)
col = parseInt(col)
if(getSum(row) + getSum(col) <= k && row < m && col < n) {
// 如果有重复的就别加进去
if(queue.indexOf(row + ',' + (col + 1)) === -1) {
queue.push(row + ',' + (col + 1))
}
if(queue.indexOf((row + 1) + ',' + col) === -1) {
queue.push((row + 1) + ',' + col)
}
res++
}
}
return res
};
b、DFS
感觉和BFS差别不大
/**
* @param {number} m
* @param {number} n
* @param {number} k
* @return {number}
*/
var movingCount = function(m, n, k) {
let queue = ['0,0']
let visited = [...queue]
let res = 0
let getSum = function(num) {
let sum = 0
while(num !== 0) {
sum += num % 10
num = Math.floor(num / 10)
}
return sum
}
let map = new Map()
while(queue.length !== 0) {
let [row, col] = queue.pop().split(',')
row = parseInt(row)
col = parseInt(col)
if(getSum(row) + getSum(col) <= k && row < m && col < n) {
// 如果有重复的就别加进去
if(visited.indexOf(row + ',' + (col + 1)) === -1) {
queue.push(row + ',' + (col + 1))
}
if(visited.indexOf((row + 1) + ',' + col) === -1) {
queue.push((row + 1) + ',' + col)
}
res++
visited.push(row + ',' + col)
}
}
return res
};
2、剑指 Offer 14- I. 剪绳子
关键词,最大,而且我们把某一段切开后,还可以把这一段继续切,相当于数据是可以记忆化的,所以我们自然而然地想到动态规划
/**
* @param {number} n
* @return {number}
*/
var cuttingRope = function(n) {
let dp = new Array(n + 1).fill(0)
dp[1] = 1
dp[2] = 1
for(let i = 3; i < n + 1; i++) {
for(let j = 1; j < i; j++) {
// 分别为dp,当切了一刀后就直接乘上,或者当切了一刀后找切了那一刀的最大乘积再乘上
dp[i] = Math.max(dp[i], (i - j) * j, dp[i - j] * j)
}
}
return dp[n]
};
3、剑指 Offer 14- II. 剪绳子 II
这道题和13(上一道题)的区别其实只是数更大了,而因为在他会超过Math.MAX_VALUE,所以这里就需要另外找方法进行计算(毕竟大整数乘法有问题嘛)
这里采用贪心算法,因为当绳子0m长,那肯定结果是0,绳子为1m那结果也是0,绳子为2m结果是1,绳子为3m结果是2,绳子为4m结果是4,绳子为5m结果是6
首先我们要了解的是因为绳子可以不断向下分,所以我们要知道什么时候该收手,也就是不往下分了,可以看出当绳子小于等于4m时往下分会很亏,而我们可以知道因为5=2+3,6=3+3,7=2+2+3这可以让我们看出其实每个数都可以分成若干个2和若干个3,而在这里面肯定是3多一点乘积会大一点,如8=2+2+2+2和8=3+3+2这里面3多一点的乘积会大一点,所以我们可以开始写代码(只要小于等于4就不分,大于4的就每次分一个3,直到小于等于4)
/**
* @param {number} n
* @return {number}
*/
var cuttingRope = function(n) {
if(n <= 3) {
return n - 1
}
let res = 1
while(n > 4) {
res *= 3
res %= (1e9 + 7)
n -= 3
}
return res * n % (1e9 + 7)
};
4、剑指 Offer 15. 二进制中1的个数
a、正则
这道题除了直接循环,就是正则最容易想出来了,循环就不多说了,正则写一下
/**
* @param {number} n - a positive integer
* @return {number}
*/
var hammingWeight = function(n) {
let arr = n.toString(2).match(/1/g)
return arr === null ? 0 : arr.length
};
b、与和右移的位运算
这里有个重点就是要用无符号右移,因为无符号右移是高位全部补0,而有符号右移的正数是高位补0,负数高位补1
/**
* @param {number} n - a positive integer
* @return {number}
*/
var hammingWeight = function(n) {
let res = 0
while(n !== 0) {
res += n & 1
// 这里的重点在于要用无符号右移,而非有符号右移
n = n >>> 1
}
return res
};
c、n&n-1
n&n-1可以把最后一个1消掉,然后返回消掉后的值
/**
* @param {number} n - a positive integer
* @return {number}
*/
var hammingWeight = function(n) {
let res = 0
while(n !== 0) {
// 只要进得来也就是说只要值不是0,必定有一个1
res++
// n & (n - 1)相当于把最后一个1消除
n &= n - 1
}
return res
};
拓展:
2的幂
/**
* @param {number} n
* @return {boolean}
*/
var isPowerOfTwo = function(n) {
// 这里必须给(n - 1) & n加个括号,否则会被认为是(n - 1) & (n === 0)
return n > 0 && (((n - 1) & n) === 0)
};
5、剑指 Offer 16. 数值的整数次方
这道题需要用到一些技巧,主要就是快速幂
a、二分
首先,我们如果暴力地循环肯定超时,所以如果我们要求4的8次方,可以通过先算到4的2次方,然后再平方得到4的4次方,再平方得到4的8次方
这其实就是二分的思想
/**
* @param {number} x
* @param {number} n
* @return {number}
*/
var myPow = function(x, n) {
if(x === 1 || n === 0) {
return 1
}
if(n < 0) {
n = Math.abs(n)
x = 1 / x
}
let multi = function(num) {
if(num === 0) {
return 1
}
if(num % 2 === 0) {
return multi(num / 2) ** 2
} else {
return multi(Math.floor(num / 2)) ** 2 * x
}
}
return multi(n)
};
b、位运算
如图,可以将指数从10进制转为2进制
/**
* @param {number} x
* @param {number} n
* @return {number}
*/
var myPow = function(x, n) {
if(x === 1 || n === 0) {
return 1
}
let res = 1
if(n < 0) {
n = Math.abs(n)
x = 1 / x
}
let index = 1
while(n > 0) {
if(n & 1) {
res *= x ** index
}
index *= 2
n = n >>> 1
}
return res
};
6、剑指 Offer 17. 打印从1到最大的n位数
a、暴力循环
/**
* @param {number} n
* @return {number[]}
*/
var printNumbers = function(n) {
n = 10 ** n
let res = []
for(let i = 1; i < n; i++) {
res.push(i)
}
return res
};
7、剑指 Offer 18. 删除链表的节点
a、快慢指针
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var deleteNode = function(head, val) {
let node = head
let pre = null
while(node !== null) {
if(node.val === val) {
if(pre === null) {
return head.next
}
pre.next = node.next
return head
}
pre = node
node = node.next
}
return head
};
8、剑指 Offer 19. 正则表达式匹配
9、剑指 Offer 20. 表示数值的字符串
10、剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
a、两个数组存储,暴力循环
/**
* @param {number[]} nums
* @return {number[]}
*/
var exchange = function(nums) {
let res1 = []
let res2 = []
for(let i = 0; i < nums.length; i++) {
if(nums[i] % 2 === 0) {
res2.push(nums[i])
} else {
res1.push(nums[i])
}
}
return [...res1, ...res2]
};