一些常见的算法题(积累中...)

写的有啥问题请不吝赐教,万分感谢!

1、斐波那契数列

题目:从第3项开始,当前项等于前两项之和: 1 1 2 3 5 8 13 21 ……,计算第n项的值

输入:20

输出:6765

思路:

        1、核心: dp(n) = dp(n-1) + dp(n-2)

        2、需求:取需求项的前两位数的和

        3、传统做法:遍历数组后,将每次求出的值进行记录,最后根据下标取值

        4、低复杂度做法:只记录需要相加的两个值,两个值的和即所求值

// 斐波那契数列,前两数之和为所求位数的值
// 1 1 2 3 5 8 13 21 ....
function fibonacci(n) {
    if (n <= 2) return 1

    // 一般是声明数组,将每个求得的值记录进去,最后拿索引下标的值,但是这样复杂度太高
    // let dp = [1, 1];
    // for (let i = 2; i < n; i++) {
    //     // 求和之后,进行赋值
    //     dp[i] = dp[i - 1] + dp[i - 2]
    // }
    // return dp[n - 1]


    // 我们所求的值,就是前两位数相加
    // dp[n] = dp[n - 1] + dp[n - 2]
    // 只需声明两个存储值的变量,用来记录前两位数的值; r -- 代表两数的和
    let p1 = 1, p2 = 1, r;

    for (let i = 2; i < n; i++) {
        // 求和之后,进行赋值
        r = p1 + p2;
        p1 = p2;
        p2 = r;
    }
    // 返回我们所需要的值
    return r;
}

2、两数之和

题目:在数组 [8, 2, 6, 5, 4, 1, 3] 中找出两个数的和为目标数

输入:7

输出:[ [2, 5] , [6, 1] , [4, 3] ]

思路:

        1、因为只取两个数的和,不用考虑太多,展示的是无重复项的,所以可以做一步去重操作

        2、最简易的就是遍历两次,取当前位置的数 + 后面位置的数 与所需要对比的值 进行比较

        3、将符合条件的归纳到一个数组中

        4、使用 while 的好处:(注:记得控制条件变量)

                (1)、可以在某个条件表达式为真的前提下,循环执行指定的一段代码,直到那个表达式不为真时结束循环。

                (2)、复杂度更低

/* 在数组中找出两个数的和为目标数 */
const Arr = [8, 2, 6, 5, 4, 1, 3];
let target = 7;


/** 在数组中找出两个数的和为目标数
 * @param arr   数组
 * @param data  合计数
*/
function Summation(arr, data) {
    let SumData = []
    /* 最简易的  复杂度 O(n^2)
    for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
            let sum = arr[i] + arr[j]
            if (sum == data) {
                SumData.push([arr[i], arr[j]])
            }
        }
    } */

    // O(n*m) n--外层循环   m--内层循环  的迭代次数
    for (let i = 0; i < arr.length; i++) {
        let Nums = arr.length - 1;

        while (Nums > i) {
            if (arr[i] + arr[Nums] == data) {
                SumData.push([arr[i], arr[Nums]])
            }
            Nums--
        }
    }
    return SumData
}

3、三数之和

题目:找出数组 [5, 2, 1, 1, 3, 4, 6] 中三个数组合后的值 与 传入值相同,且每组数据不能有重复

输入:8

输出:[ [1, 1, 6] , [1, 2, 5] , [1, 3, 4] ]

思路:

        1、分析:每一组数据不能有重复的另一组数据

        2、将数组进行排序,便于处理数据

                (1)、当前选中项与前一项值相同,直接跳过

                (2)、拿取的两个值一定是在当前项后面的,且两值的索引不能一致或交叉

                (3)、将拿到的三个值合计与需求值对比,大了-右侧索引向左移,小了,左侧索引向右移

                (4)、获取符合条件的数据后,分别向右、向左移动,若与前一位数据相同,则继续移动

const Arr = [5, 2, 1, 1, 3, 4, 6];
let   target = 8;

/** SummationThreeNum 找出数组中三个数组合后的值 与 传入值相同,且每组数据不能有重复
 * @param arr    数组
 * @param target 合计数
  */
function SummationThreeNum(arr, target) {
    let Result = [];
    // 排序 会改变原数组
    arr.sort();

    for (let i = 0; i < arr.length; i++) {
        // 从下标为 1 的开始,如果当前 索引的值 == 前一位的值,则跳出本次循环
        // 数组是排过序的,如果当前项的值跟前一项的值一致,则毫无意义
        if (i && arr[i] === arr[i - 1]) continue;

        // 获取本次循环索引的左侧下一位数的索引
        let Left = i + 1;
        // 获取本次循环数组最后一位的索引
        let Right = arr.length - 1;

        // 因为是按照顺序排的,获取的另外两数必须在当前索引的右侧,
        //左侧的下位索引必须小于右侧索引,避免两数重合或交叉
        while (Left < Right) {
            // 计算获取到的三个数
            let sum = arr[i] + arr[Left] + arr[Right];

            // 当获取的合计数 大于 需求值时,右侧索引下降一位
            if (sum > target) {
                Right--;
            }
            // 当获取的合计数 小于 需求值时,左侧索引上升一位
            else if (sum < target) {
                Left++;
            }
            // 当获取的合计数 等于 需求值时,将获取的三个数组合成数组,push进大数组中
            else {
                // n++ 或 n-- 都是先执行原数据,在进行更改值的操作 
                // ( 如: 先 arr[Left] 再 Left++ )
                Result.push([arr[i], arr[Left++], arr[Right--]]);

                // 数据索引变更后,后更后索引下标对应的值 == 前一位,则继续往后进一位
                while (arr[Left] == arr[Left - 1]) {
                    Left++;
                };
                // 数据索引变更后,后更后索引下标对应的值 == 后一位,则继续往前进一位
                while (arr[Right] == arr[Right + 1]) {
                    Right--;
                };
            };
        };
    };
    return Result;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值