joken-前端工程师

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::
  394 随笔 :: 39 文章 :: 8 评论 :: 20万 阅读

原理:在已排序数组中,通过每次折半缩小范围查找目标值。

实现

function binarySearch(arr, target) {
    let left = 0;
    let right = arr.length - 1;

    while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        if (arr[mid] === target) return mid;
        if (arr[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

案例

// 案例:查找学生成绩表中某个分数的位置
const scores = [60, 72, 85, 90, 95, 98, 100];
const targetScore = 90;
const position = binarySearch(scores, targetScore);
console.log(`分数 ${targetScore} 在第 ${position} 个位置`); // 输出: 分数 90 在第 3 个位置

const notFound = binarySearch(scores, 88);
console.log(`查找 88: ${notFound}`); // 输出: 查找 88: -1

复杂度:时间 O(log n),空间 O(1)。
应用:快速定位有序数据,如查找书籍编号。


2. 洗牌 (Shuffle Array, Fisher-Yates Algorithm)

原理:从数组末尾向前,每次随机交换元素,保证均匀分布。

实现

function shuffleArray(arr) {
    const result = [...arr];
    for (let i = result.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [result[i], result[j]] = [result[j], result[i]];
    }
    return result;
}

案例

// 案例:随机排列一副扑克牌(简化版)
const cards = ['A♠', 'K♠', 'Q♠', 'J♠', '10♠'];
const shuffled = shuffleArray(cards);
console.log('洗牌结果:', shuffled); 
// 输出示例: 洗牌结果: ['Q♠', '10♠', 'A♠', 'J♠', 'K♠']

复杂度:时间 O(n),空间 O(1)(复制版本 O(n))。
应用:游戏中随机发牌、随机推荐内容。


3. 去重与交集 (Array Deduplication & Intersection)

原理:利用 Set 的高效去重和查找特性。

实现

function uniqueArray(arr) {
    return [...new Set(arr)];
}

function arrayIntersection(arr1, arr2) {
    const set2 = new Set(arr2);
    return arr1.filter(item => set2.has(item));
}

案例

// 案例1:清理重复的用户ID
const userIds = [101, 102, 103, 102, 104, 101];
const uniqueIds = uniqueArray(userIds);
console.log('去重后的ID:', uniqueIds); // 输出: 去重后的ID: [101, 102, 103, 104]

// 案例2:找出两个团队的共同成员
const teamA = ['Alice', 'Bob', 'Charlie'];
const teamB = ['Bob', 'David', 'Charlie'];
const commonMembers = arrayIntersection(teamA, teamB);
console.log('共同成员:', commonMembers); // 输出: 共同成员: ['Bob', 'Charlie']

复杂度

  • 去重:时间 O(n),空间 O(n)。
  • 交集:时间 O(n + m),空间 O(m)。
    应用:数据清洗、查找共同兴趣用户。

4. 最长公共子序列 (Longest Common Subsequence, LCS)

原理:通过动态规划比较两个字符串,计算最长公共子序列长度。

实现

function longestCommonSubsequence(str1, str2) {
    const m = str1.length;
    const n = str2.length;
    const dp = Array(m + 1).fill().map(() => Array(n + 1).fill(0));

    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            if (str1[i - 1] === str2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[m][n];
}

案例

// 案例:比较两个单词的相似度
const word1 = "HELLO";
const word2 = "HALO";
const lcsLength = longestCommonSubsequence(word1, word2);
console.log(`"${word1}" 和 "${word2}" 的LCS长度: ${lcsLength}`); 
// 输出: "HELLO" 和 "HALO" 的LCS长度: 4

// 案例:DNA序列匹配
const dna1 = "AGGTAB";
const dna2 = "GXTXAYB";
const dnaLcs = longestCommonSubsequence(dna1, dna2);
console.log(`DNA序列的LCS长度: ${dnaLcs}`); // 输出: DNA序列的LCS长度: 4

复杂度:时间 O(mn),空间 O(mn)。
应用:文本对比、生物信息学。


5. 快速幂 (Fast Exponentiation)

原理:通过二分法将幂运算分解为平方和乘法,优化计算。

实现

function fastPower(base, exponent) {
    if (exponent === 0) return 1;
    if (exponent < 0) return 1 / fastPower(base, -exponent);

    const half = fastPower(base, Math.floor(exponent / 2));
    return exponent % 2 === 0 ? half * half : half * half * base;
}

案例

// 案例1:计算大数的幂
const result1 = fastPower(2, 10);
console.log(`2^10 = ${result1}`); // 输出: 2^10 = 1024

// 案例2:计算负指数
const result2 = fastPower(2, -3);
console.log(`2^-3 = ${result2}`); // 输出: 2^-3 = 0.125

复杂度:时间 O(log n),空间 O(log n)。
应用:密码学(如RSA)、高效数学计算。


6. 前缀和 (Prefix Sum)

原理:预计算累积和,快速查询区间和。

实现

function createPrefixSum(arr) {
    const prefixSum = [0];
    for (let i = 0; i < arr.length; i++) {
        prefixSum[i + 1] = prefixSum[i] + arr[i];
    }
    return (start, end) => prefixSum[end + 1] - prefixSum[start];
}

案例

// 案例:统计一周每天的销售额区间总和
const sales = [100, 150, 200, 120, 180, 90, 110]; // 7天销售额
const getRangeSum = createPrefixSum(sales);

// 周一到周三的总销售额
const weekStart = getRangeSum(0, 2);
console.log(`周一到周三总销售额: ${weekStart}`); // 输出: 周一到周三总销售额: 450

// 周四到周日总销售额
const weekEnd = getRangeSum(3, 6);
console.log(`周四到周日总销售额: ${weekEnd}`); // 输出: 周四到周日总销售额: 500

复杂度

  • 预处理:时间 O(n),空间 O(n)。
  • 查询:时间 O(1)。
    应用:区间统计、实时数据分析。

综合对比与案例总结

算法 时间复杂度 空间复杂度 案例输出示例
二分查找 O(log n) O(1) 查找 90: 位置 3
洗牌 O(n) O(1) 洗牌: ['Q♠', '10♠', ...]
去重 O(n) O(n) 去重ID: [101, 102, 103, 104]
交集 O(n + m) O(m) 共同成员: ['Bob', 'Charlie']
LCS O(m*n) O(m*n) LCS长度: 4 (HELLO, HALO)
快速幂 O(log n) O(log n) 2^10 = 1024
前缀和 O(n) / O(1) O(n) 周一到周三: 450
posted on   joken1310  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示