js常规算法题
由于在工作中有很多常用计算方法无法记住,每次都是在使用到的时候去搜索,为了加深记忆,在工作之余去牛客网做华为机试练习题,这里记录部分练习结果:
字符串逆序
描述
将一个字符串内容颠倒过来,并输出。
数据范围:1≤len(str)≤10000 ;
- 方法1 使用数组的reverse();
const strReverse1 = (str: string) => {
if(!str || str.length > 1000) console.log('请输入正确字符!')
const newArr = Array.from(str);
return newArr.reverse().join('')
}
- 方法2 使用的也是数组的reverse() 方法,先将字符串变为数组;str.split()
const strReverse2 = (str: string) => {
if(!str || str.length > 1000) console.log('请输入正确字符!')
const newArr = Array.from(str);
retrun newArr.reverse().join('')
}
- 方法3 使用遍历方法 使用字符串 charAt() 方法 反正指定位置字符串
const strReverse3 = (str: string) => {
let newStr = ''
for(let i = str.length-1; i > 0; i ++){
newStr += str.charAt(i)
}
retrun newStr
}
求解立方根
描述
计算一个浮点数的立方根,不要使用库函数。
保留一位小数
这里常规解题时我们会使用 js Match库函数 cbrt() 函数很方便就计算出来了,但是题目要求不能使用库函数;
四则运算
描述
输入一个表达式(用字符串表示),求这个表达式的值。
保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法
实现方式:
1、解释说明:
这个问题可以通过Python的内置函数eval()来解决。eval()函数用来执行一个字符串表达式,并返回表达式的值。在这个问题中,我们需要将输入的字符串表达式传递给eval()函数,然后返回计算结果。
2、使用示例:
expression = "1 + 2 * (3 - 4) / 5"
result = eval(expression)
print(result)
在这个示例中,我们定义了一个字符串表达式"1 + 2 * (3 - 4) / 5",然后使用eval()函数计算这个表达式的值,并将结果打印出来。
3、注意事项:
在使用eval()函数时,需要确保输入的字符串表达式是合法的,否则会抛出异常。此外,由于eval()函数可以执行任何Python代码,因此在处理用户输入时需要特别小心,以防止恶意代码的执行。
素数伴侣
描述
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的 N ( N 为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。
输入:
有一个正偶数 n ,表示待挑选的自然数的个数。后面给出 n 个具体的数字。
输出:
输出一个整数 K ,表示你求得的“最佳方案”组成“素数伴侣”的对数。
实现方式:
1、解释说明:
这个问题可以通过动态规划来解决。首先,我们需要一个函数来判断一个数是否为素数。然后,我们需要一个二维数组dp,其中dp[i][j]表示前i个数中选择j对的“最佳方案”组成“素数伴侣”的对数。我们可以通过遍历所有的数,对于每一个数,我们都有两种选择,一种是选择它作为一对中的其中一个数,另一种是不选择它。如果我们选择了它,那么我们需要在前i-1个数中选择j-1对,这可以通过dp[i-1][j-1]来得到。如果我们不选择它,那么我们需要在前i-1个数中选择j对,这可以通过dp[i-1][j]来得到。最后,我们需要在所有的选择中找出最大的那个,这就是我们的“最佳方案”。
2、使用示例:
假设我们有4个正整数:2,5,6,13,我们可以使用以下代码来找出“最佳方案”:
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5)+1):
if n % i == 0:
return False
return True
def best_plan(n, nums):
dp = [[0 for _ in range(n//2+1)] for _ in range(n+1)]
for i in range(1, n+1):
for j in range(1, n//2+1):
if is_prime(nums[i-1] + nums[j-1]):
dp[i][j] = max(dp[i-1][j-1]+1, dp[i-1][j])
else:
dp[i][j] = dp[i-1][j]
return dp[n][n//2]
nums = [2, 5, 6, 13]
print(best_plan(len(nums), nums))
3、注意事项:
这个问题的时间复杂度是O(n2),空间复杂度也是O(n2),所以当n非常大的时候,可能会导致运行时间过长或者内存不足。在实际使用时,需要考虑到这一点。
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
这是一个常见的编程问题,我们可以通过模拟螺旋路径的方式来解决这个问题。具体步骤如下:
- 初始化一个空列表 result 用于存储结果。
- 定义四个边界值,分别是 top、bottom、left、right,分别表示矩阵的上、下、左、右边界。
- 使用一个 while 循环,当 top <= bottom 且 left <= right 时,执行以下操作:
- 从左到右遍历上边界的元素,将元素添加到 result 中,然后将 top 加 1。
- 从上到下遍历右边界的元素,将元素添加到 result 中,然后将 right 减 1。
- 如果 top <= bottom,那么从右到左遍历下边界的元素,将元素添加到 result 中,然后将 bottom 减 1。
- 如果 left <= right,那么从下到上遍历左边界的元素,将元素添加到 result 中,然后将 left 加 1。
- 返回 result。
以下是 Python 代码实现:
def spiralOrder(matrix):
if not matrix: return []
result = []
top, bottom, left, right = 0, len(matrix) - 1, 0, len(matrix[0]) - 1
while top <= bottom and left <= right:
for i in range(left, right + 1):
result.append(matrix[top][i])
top += 1
for i in range(top, bottom + 1):
result.append(matrix[i][right])
right -= 1
if top <= bottom:
for i in range(right, left - 1, -1):
result.append(matrix[bottom][i])
bottom -= 1
if left <= right:
for i in range(bottom, top - 1, -1):
result.append(matrix[i][left])
left += 1
return result
这个函数接受一个二维列表 matrix 作为输入,返回一个包含 matrix 中所有元素的列表,元素的顺序是按照顺时针螺旋顺序排列的。
以下是 js 代码实现:
function spiralOrder(matrix) {
if (!matrix || matrix.length === 0) return [];
let result = [];
let rowStart = 0;
let rowEnd = matrix.length - 1;
let colStart = 0;
let colEnd = matrix[0].length - 1;
while (rowStart <= rowEnd && colStart <= colEnd) {
// 从左到右遍历上边界
for (let i = colStart; i <= colEnd; i++) {
result.push(matrix[rowStart][i]);
}
rowStart++;
// 从上到下遍历右边界
for (let i = rowStart; i <= rowEnd; i++) {
result.push(matrix[i][colEnd]);
}
colEnd--;
// 从右到左遍历下边界
if (rowStart <= rowEnd) {
for (let i = colEnd; i >= colStart; i--) {
result.push(matrix[rowEnd][i]);
}
rowEnd--;
}
// 从下到上遍历左边界
if (colStart <= colEnd) {
for (let i = rowEnd; i >= rowStart; i--) {
result.push(matrix[i][colStart]);
}
colStart++;
}
}
return result;
}
生命游戏
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态: 1 即为 活细胞 (live),或 0 即为 死细胞 (dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
这是一个经典的编程问题,被称为"生命游戏"。我们可以使用JavaScript来实现这个游戏的规则。以下是一个简单的实现:
function gameOfLife(board) {
const m = board.length;
const n = board[0].length;
const dx = [-1, -1, -1, 0, 0, 1, 1, 1];
const dy = [-1, 0, 1, -1, 1, -1, 0, 1];
const copyBoard = JSON.parse(JSON.stringify(board));
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
let liveNeighbors = 0;
for (let k = 0; k < 8; k++) {
const x = i + dx[k];
const y = j + dy[k];
if (x >= 0 && x < m && y >= 0 && y < n && copyBoard[x][y] === 1) {
liveNeighbors++;
}
}
if (copyBoard[i][j] === 1 && (liveNeighbors < 2 || liveNeighbors > 3)) {
board[i][j] = 0;
} else if (copyBoard[i][j] === 0 && liveNeighbors === 3) {
board[i][j] = 1;
}
}
}
return board;
}
这个函数接受一个二维数组board
作为输入,表示面板的初始状态。然后,它创建了一个copyBoard
来保存面板的初始状态,以便我们可以在不改变原始面板的情况下计算每个细胞的新状态。
对于面板上的每个细胞,我们计算其周围八个位置的活细胞数。如果一个活细胞周围活细胞数少于两个或多于三个,那么它将死亡(即变为死细胞)。如果一个死细胞周围正好有三个活细胞,那么它将复活(即变为活细胞)。
最后,我们返回更新后的面板。
旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
要实现旋转图像,我们可以先将矩阵进行转置,然后将每一行进行翻转。这里是一个使用JavaScript实现的示例代码:
function rotate(matrix) {
const n = matrix.length;
// 转置矩阵
for (let i = 0; i < n; i++) {
for (let j = i; j < n; j++) {
const temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 翻转每一行
for (let i = 0; i < n; i++) {
for (let j = 0; j < n / 2; j++) {
const temp = matrix[i][j];
matrix[i][j] = matrix[i][n - j - 1];
matrix[i][n - j - 1] = temp;
}
}
return matrix;
}
// 测试用例
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
console.log(rotate(matrix));
输出结果:
[
[7, 4, 1],
[8, 5, 2],
[9, 6, 3]
]