简单算法实例
字符串反转
在 JavaScript 中,可以通过多种方式实现字符串反转。下面介绍两种常见的方法:
方法 1:使用数组的 reverse()
方法
reverse()
方法将字符串转换为数组。
使用数组的
reverse()
方法反转数组元素。使用
join()
方法将数组元素合并成一个字符串。
function reverseString(str) {
return str
.split('')
.reverse()
.join('')
}
方法 2:使用循环
创建一个新的空字符串用于存放反转后的结果。
通过循环遍历原字符串,从最后一个字符开始,逐个将字符添加到新字符串中。
function reverseString(str) {
let reversed = ''
for (let i = str.length - 1; i >= 0; i--) {
reversed += str[i]
}
return reversed
}
这两种方法都可以有效地反转字符串。选择哪种方法取决于个人偏好和具体的应用场景。第一种方法在代码上更简洁,而第二种方法提供了更多的控制能力,可能在处理非常大的字符串或需要优化性能的情况下更有优势。
判断回文
方法 1:将字符串反串后判断与原字符串是否相等
function isPalindrome(str) {
// 也可用上面实现的 reverseString 方法
return (
str ===
str
.split('')
.reverse()
.join('')
)
}
方法 2:双指针
function isPalindrome(str) {
let left = 0
let right = str.length - 1
while (left < right) {
if (str[left] !== str[right]) {
return false
}
left++
right--
}
return true
}
最常出现的字母
function mostFrequentChar(str) {
let charMap = {}
let maxCount = 0
let mostFrequentChar = ''
for (let char of str) {
charMap[char] = (charMap[char] || 0) + 1
if (charMap[char] > maxCount) {
maxCount = charMap[char]
mostFrequentChar = char
}
}
return mostFrequentChar
}
最常出现的连续字母
function longestConsecutiveChar(str) {
let longestChar = ''
let currentChar = ''
let count = 0
let maxCount = 0
for (let i = 0; i < str.length; i++) {
if (str[i] === currentChar) {
count++
} else {
if (count > maxCount) {
maxCount = count
longestChar = currentChar
}
currentChar = str[i]
count = 1
}
}
if (count > maxCount) {
longestChar = currentChar
}
return longestChar
}
股票的最大利润
最长递增子序列
一个经典的动态规划问题是「最长递增子序列(Longest Increasing Subsequence,简称 LIS)」问题。给定一个整数数组 nums,找到其中最长的严格递增子序列的长度。
下面是用 JavaScript 实现 LIS 问题的动态规划算法,并一步一步拆解说明:
定义状态: 我们定义状态 dp[i] 表示以 nums[i] 结尾的最长递增子序列的长度。这里 dp[i] 是一个一维数组,长度与 nums 数组相同。
初始条件: 初始时,每个元素自成一个序列,因此 dp[i] 的初始值都为 1。
状态转移方程: 对于每个位置 i,我们需要计算 dp[i] 的值。遍历 i 之前的所有位置 j,如果 nums[j] 小于 nums[i],说明可以将 nums[i] 加入到以 nums[j] 结尾的子序列中,形成更长的递增子序列。因此,状态转移方程为 dp[i] = max(dp[i], dp[j] + 1),表示考虑将 nums[i] 加入到所有能够使得 nums[i] 大于 nums[j] 的子序列中,并取其中最大值作为 dp[i] 的值。
下面是具体的 JavaScript 代码实现:
function lengthOfLIS(nums) {
const n = nums.length
if (n === 0) {
return 0
}
const dp = new Array(n).fill(1)
for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1)
}
}
}
let maxLength = 0
for (let length of dp) {
maxLength = Math.max(maxLength, length)
}
return maxLength
}
现在来一步一步解释这段代码:
首先,我们定义了函数
lengthOfLIS
,它接收一个整数数组nums
作为参数。我们初始化了一个长度为
n
的数组dp
,初始值都为 1,其中n
是nums
的长度。接着我们使用两层循环遍历数组
nums
,在外层循环中遍历每个位置i
,在内层循环中遍历i
之前的所有位置j
。对于每个位置
i
,我们计算dp[i]
的值,根据状态转移方程dp[i] = max(dp[i], dp[j] + 1)
更新dp[i]
的值。最后,我们遍历
dp
数组,找到其中的最大值作为最长递增子序列的长度,并返回该长度作为结果。
最常连续递增子序列
function lengthOfLongestIncreasingSubsequence(nums) {
const n = nums.length
if (n === 0) {
return 0
}
let maxLength = 1
let currentLength = 1
for (let i = 1; i < n; i++) {
if (nums[i] > nums[i - 1]) {
currentLength++
} else {
maxLength = Math.max(maxLength, currentLength)
currentLength = 1
}
}
return Math.max(maxLength, currentLength)
}
斐波那契数列
使用递归法实现
function fibonacci(n) {
if (n <= 1) {
return n
}
return fibonacci(n - 1) + fibonacci(n - 2)
}
使用动态规划实现
function fibonacci(n) {
if (n <= 1) {
return n
}
let fib = [0, 1]
for (let i = 2; i <= n; i++) {
fib[i] = fib[i - 1] + fib[i - 2]
}
return fib[n]
}
Last updated
Was this helpful?