跟着B站学算法-时间空间复杂度、数组、LC485/283/27

本文详细介绍了时间空间复杂度的概念,包括时间复杂度和空间复杂度的定义。接着,讨论了常见数据结构如数组、链表、栈等的特点。然后,通过LC485、LC283和LC27三个LeetCode题目,分别讲解了动态规划、双指针等算法的应用,旨在帮助读者深入理解算法和数据结构。
摘要由CSDN通过智能技术生成

1 空间和时间复杂度

资料来源:力扣《图解算法数据结构》

N:输入数据量、数据大小 

算法复杂度:分为时间复杂度和空间复杂度

时间复杂度:指输入数据大小为 N 时,算法运行所需花费的时间,这个时间是算法云习惯的“计算操作的数量”,而非绝对时间

N:算法处理的输入数据量(排序算法下是需要排序的元素数量,搜索算法是搜索范围的元素总数)

大O是最常使用的时间复杂度评价渐进符号

空间复杂度:在最差的情况下,算法运行所使用的最大空间

通常情况下,空间复杂度指在输入数据大小为 N 时,算法运行所使用的「暂存空间」+「输出空间」的总体大小。

空间复杂度涉及的空间类型有:

输入空间: 存储输入数据所需的空间大小;

暂存空间: 算法运行过程中,存储所有中间变量和对象等数据所需的空间大小;

输出空间: 算法运行返回时,存储输出数据所需的空间大小;

2 数据结构

常见的数据结构可分为「线性数据结构」与「非线性数据结构」,具体为:「数组」、「链表」、「栈」、「队列」、「树」、「图」、「散列表」、「堆」。

数组

数组是将相同类型的元素存储于连续内存空间的数据结构,其长度不可变。

如下图所示,构建此数组需要在初始化时给定长度,并对数组每个索引元素赋值

链表

链表以节点为单位,每个元素都是一个独立对象,在内存空间的存储是非连续的。链表的节点对象具有两个成员变量:「值 val」,「后继节点引用 next」 。

栈是一种具有 「先入后出」 特点的抽象数据结构,可使用数组或链表实现。

队列

队列是一种具有 「先入先出」 特点的抽象数据结构,可使用链表实现。

树是一种非线性数据结构,根据子节点数量可分为 「二叉树」 和 「多叉树」,最顶层的节点称为「根节点 root」。以二叉树为例,每个节点包含三个成员变量:「值 val」、「左子节点 left」、「右子节点 right」 。

图是一种非线性数据结构,由「节点(顶点)vertex」和「边 edge」组成,每条边连接一对顶点。根据边的方向有无,图可分为「有向图」和「无向图」。

散列表

散列表是一种非线性数据结构,通过利用 Hash 函数将指定的「键 key」映射至对应的「值 value」,以实现高效的元素查找。

堆是一种基于「完全二叉树」的数据结构,可使用数组实现。以堆为原理的排序算法称为「堆排序」,基于堆实现的数据结构为「优先队列」。堆分为「大顶堆」和「小顶堆」,大(小)顶堆:任意节点的值不大于(小于)其父节点的值。

数组相关的算法习题

3 LC485. 最大连续1的个数 

给定一个二进制数组 nums , 计算其中最大连续 1 的个数。

 【动态规划】

var findMaxConsecutiveOnes = function(nums) {
    // max: 记录当前次数的最大值, count: 记录当前1连续出现的次数
    var max = 0; count = 0;
    for (var i = 0; i < nums.length; i ++) {
        // nums[i] == 1, count++
        if (nums[i] === 1) count++;
        // 否则,count重新计数
        else count = 0;
        // 重置当前次数的最大值
        max = Math.max(max, count);
    }

    return max;
};

方法二:转换数据类型,求最长字符串长度
既然数组中只有0和1,还可以以元素0作为分割点将原数组转换成多个只包含1的字符串数组:

[1, 1, 0, 1, 1, 1] => '110111' => ['11', '111']
这样就变成了求转换后数组中最长字符串长度。

Array.sort从长到短排序

var findMaxConsecutiveOnes = function(nums) {
    // 将数组以0分割 ['11', '111']
    var temp = nums.join('').split('0');
    // 获取数组中最长的字符串
    var max = temp.sort((a, b) => b.length - a.length)[0]

    return max.length;
};
Math.max取长度最大值

var findMaxConsecutiveOnes = function(nums) {
    // 将数组以0分割 ['11', '111']
    var temp = nums.join('').split('0');

    return Math.max(...(temp.map(item => item.length)));
};

4 LC283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

答案一:双指针

思路二:双指针
慢指针 j 从 0 开始,当快指针 i 遍历到非 0 元素的时候,i 和 j 位置的元素交换,然
后把 j + 1;

也就是说,快指针 i 遍历完毕后, [0, j) 区间就存放着所有非 0 元素,而剩余的[j,
n]区间再遍历一次,用 0 填充满即可。

var moveZeroes = function (nums) {
  let j = 0

  for (let i = 0; i < nums.length; i++) {
    if (nums[i] !== 0) {
      nums[j] = nums[i]
      j++
    }
  }

  while (j < nums.length) {
    nums[j] = 0
    j++
  }
}

答案二:

var moveZeroes = function(nums) {
        //获取数组长度
        let len = nums.length;
        //循环遍历数组
        for(let i =0;i<len;i++){
            //当数组哪个位置是0 ,就删除这个这个位置的元素,然后在末尾补 0
            //从而就达到了 把所有0移动到数组末尾的要求且保持的非零元素的相对顺序
            if(nums[i]==0){
                nums.splice(i,1)
                nums.push(0)
            //当为0的元素删除后,下一个元素就会前进一位占据该位置,所以要从该位置在进行判断
                i--
            //当移动到末尾的元素,就不用再一次进行遍历了,所以遍历的长度要减去1位
                len--
            }
        }
        return nums
}

5 LC27. 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

第一次通过测例耶耶耶

var removeElement = function(nums, val) {
    for (var i = 0; i<nums.length ; i++){
        if ( nums[i] == val) {
            nums.splice(i,1);
            i--
        }
    }
    return nums.length;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值