分治、动态规划、贪心算法、广度优先搜索

分治算法

  1. 归并排序:将数组分为两半,分别排序后合并。
  2. 快速排序:选择一个基准,将数组分为比基准小和大的两部分,递归排序。
  3. 二分查找:在有序数组中查找目标值的位置。
  4. 矩阵乘法:使用分治法计算两个矩阵的乘积。

动态规划

  1. 斐波那契数列:计算第 n 项的斐波那契数。
  2. 最大子数组和:找到数组中和最大的连续子数组。
  3. 最小路径和:在网格中找到从左上角到右下角的最小路径和。
  4. 背包问题
    • 0-1 背包问题:给定每个物品的重量和价值,背包的最大容量,目标是选择物品使得总价值最大,同时不超过背包的容量。
    • 完全背包问题:可以选择多个相同的物品。
  5. 最长公共子序列:找到两个序列的最长子序列。
  6. 编辑距离:计算将一个字符串转换成另一个字符串所需的最少操作次数。

贪心算法

  1. 活动选择问题:给定的开始时间和结束时间中选择最多的互不重叠的活动
  2. 零钱兑换:用最少的硬币数兑换特定金额。
  3. 霍夫曼编码:为字符生成最优的二进制编码。
  4. 最小生成树
    • Prim 算法:在加权图中找到最小生成树。
    • Kruskal 算法:通过边的权重选择边构造最小生成树。
  5. 区间调度问题:选择互不重叠的区间,使得选择的区间数最大。

广度优先搜索

  1. 编写国际跳棋AI:计算最少走多少步获胜
  2. 编写拼写检查器:计算最少该多少个地方可以将错拼的单词改成正确的。
//最大子数组和---动态规划
function maxSubArray(nums) {
    let res = nums[0];       //全局最大和
    let maxCur = nums[0];    //当前最大和
    for (let i = 1; i < nums.length; i++) {
        maxCur = Math.max(nums[i], maxCur + nums[i]);
        res = Math.max(res, maxCur);
    }

    return res;
}

// 示例
console.log(maxSubArray([-2, 1, -3, 4, -1, 2, 1, -5, 4]));
//最小路径和------动态规划
function minPathSum(grid) {
    const m = grid.length;
    const n = grid[0].length;
    const dp = Array.from({ length: m }, () => Array(n).fill(0));

    dp[0][0] = grid[0][0];

    // 将原始grid的值复制到dp数组的第一行和第一列 
    for (let i = 1; i < m; i++) {
        dp[i][0] = dp[i - 1][0] + grid[i][0];
    }
    for (let j = 1; j < n; j++) {
        dp[0][j] = dp[0][j - 1] + grid[0][j];
    }

    for (let i = 1; i < m; i++) {
        for (let j = 1; j < n; j++) {
            dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
        }
    }

    return dp[m - 1][n - 1];
}

// 示例
const grid = [
    [1, 3, 1],
    [1, 5, 1],
    [4, 2, 1]
];
console.log(minPathSum(grid)); // 输出: 7

//初始化二维数组
const matrix = new Array(m).fill(0)
                              .map(() => new Array(n).fill(0));

 0-1 背包问题-----动态规划

// 0-1 背包问题-----动态规划
function knapsack(weights, values, capacity) {
    const n = weights.length;  //物品数量
    //dp[i][w] 表示前 i 个物品在容量为 w 的情况下的最大价值
    //const dp = Array(n + 1).fill(0).map(() => Array(capacity + 1).fill(0));
    const dp = Array.from({ length: n + 1 }, () => Array(capacity + 1).fill(0));

    for (let i = 1; i <= n; i++) {
        for (let w = 0; w <= capacity; w++) {
            if (weights[i - 1] <= w) {
                dp[i][w] = Math.max(dp[i - 1][w], dp[i - 1][w - weights[i - 1]] + values[i - 1]);
            } else {
                dp[i][w] = dp[i - 1][w];
            }
        }
    }
    return dp[n][capacity];
}

// 示例
console.log(knapsack([1, 2, 3], [10, 15, 40], 6)); // 55

  完全背包问题-----动态规划

//完全背包问题-----动态规划
function completeKnapsack(weights, values, capacity) {
    const dp = Array(capacity + 1).fill(0); // dp[i] 表示容量为 i 时的最大价值

    for (let i = 0; i < weights.length; i++) {
        for (let w = weights[i]; w <= capacity; w++) {
           //对于每一种物品,都会遍历从它的重量到最大容量,以确保可以选择该物品多次
            dp[w] = Math.max(dp[w], dp[w - weights[i]] + values[i]);
        }
    }

    return dp[capacity]; 
}

// 示例
const weights = [1, 3, 4]; // 物品的重量
const values = [15, 20, 30]; // 物品的价值
const capacity = 4; // 背包容量

console.log(completeKnapsack(weights, values, capacity)); // 输出: 45

最长公共子串      

                                        

   

最长公共子序列

//最长公共子序列-------动态规划
function longestCommonSubsequence(text1, text2) {
    const m = text1.length;
    const n = text2.length;
    const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));

    //dp[i][j] 表示 text1 的前 i 个字符与 text2 的前 j 个字符的最长公共子序列长度
    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            if (text1[i - 1] === text2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1; // 字符匹配,长度加1
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); // 取最大值
            }
        }
    }

    return dp[m][n];
}

// 示例用法
const text1 = "abcde";
const text2 = "ace";
const result = longestCommonSubsequence(text1, text2);
console.log(result); // 输出: 3
//活动选择---------贪心
function activitySelection(start, finish) {
    const n = start.length;
    //activities 将是一个包含多个对象的数组,每个对象表示一个活动的开始和结束时间
    //finish[i]: 用索引 i 从 finish 数组中获取对应的结束时间
    const activities = start.map((s, i) => ({ start: s, finish: finish[i] }));

    //按活动结束时间(升序),确保优先选择最早结束的活动
    activities.sort((a, b) => a.finish - b.finish);

    const selected = [activities[0]];
    let lastFinishTime = activities[0].finish;

    for (let i = 1; i < n; i++) {
        if (activities[i].start >= lastFinishTime) {
            selected.push(activities[i]);
            lastFinishTime = activities[i].finish;
        }
    }
    
    return selected;
}

// 示例
console.log(activitySelection([1, 3, 0, 5, 8, 5], [2, 4, 6, 7, 9, 9]));

1.给一个字符串 s,找到 s 中最长的 回文子串。

中心扩展法 

function longestPalindrome(s) {  
    if (s.length < 2) return s;  
    let start = 0, maxLength = 1;    
    // 辅助函数,用于通过中心向两边扩展检查回文  
    const expandAroundCenter = (left, right) => {  
        while (left >= 0 && right < s.length && s[left] === s[right]) {  
            // 更新最长回文的边界  
            if (right - left + 1 > maxLength) {  
                start = left;  
                maxLength = right - left + 1;  
            }  
            // 向两边扩展  
            left--;  
            right++;  
        }  
    };  
  
    // 遍历字符串的每一个字符作为中心  
    for (let i = 0; i < s.length - 1; i++) {  
        // 奇数长度的回文  
        expandAroundCenter(i, i);  
        // 偶数长度的回文  
        expandAroundCenter(i, i + 1);  
    }  
  
    return s.substring(start, start + maxLength);  
}  

console.log(longestPalindrome("babad"));  // 输出: "bab"  
console.log(longestPalindrome("cbbd"));   // 输出: "bb"

 动态规划法     dp[i][j] 用于表示子串 s[i...j] 是否是回文串

function longestPalindrome(s) {  
    if (s.length < 2) return s;  
    let start = 0, maxLength = 1;  
    const n = s.length;  
    // 初始化dp数组,长度为n的字符串需要n*n的二维数组  
    const dp = Array.from({ length: n }, () => Array(n).fill(false));    
    // 所有长度为1的子串都是回文  
    for (let i = 0; i < n; i++) {  
        dp[i][i] = true;  
    }   
    // s.length = 2  
    for (let i = 0; i < n - 1; i++) {  
        if (s[i] === s[i + 1]) {  
            dp[i][i + 1] = true;  
            start = i;  
            maxLength = 2;  
        }  
    }    
    // s.length > 2 
    for (let len = 3; len <= n; len++) {  
        for (let i = 0; i <= n - len; i++) {  
            const j = i + len - 1;  
            if (s[i] === s[j] && dp[i + 1][j - 1]) {  
                dp[i][j] = true;  
                start = i;  
                maxLength = len;  
            }  
        }  
    }  
  
    return s.substring(start, start + maxLength);  
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值