数据结构算法之数组篇
一、二分查找
- LeetCode题目链接
- 卡尔老师代码随想录讲解
- 关键点:二分法大家再也熟悉不过了,但是很多人搞不明白二分法中边界设置和中间值的关系。 其实,我们只要确定自己的合法区间范围 就可以很简单的区分了,详情请查看卡尔老师代码随想录讲解。
- 代码:
第一种:设置区间 left 初始值为0, right 为 nums.length-1,即左闭右闭([ ]),因为 nums.length-1 在数组中是合法下标。
var search = function(nums, target) {let left = 0let right = nums.length - 1while (left <= right) {//左开右闭所以left和right相等也属于合法区间let middle = Math.floor((left+right)/2)if (nums[middle] < target) {//改变左边界left = middle + 1 //middle已经不相等了所以应该+1}else if (nums[middle] > target) {//改变右边界right = middle - 1} else {//middle和target相等情况return middle} }//没找到即返回-1return -1
};
第二种:设置区间 left 初始值为0, right 为 nums.length,即左闭右开([ )),因为 nums.length 在数组中是非法下标。
var search = function(nums, target) {let left = 0let right = nums.lengthwhile (left < right) {//左闭右开所以left和right相等属于非法区间let middle = Math.floor((left+right)/2)if (nums[middle] < target) {left = middle + 1 }else if (nums[middle] > target) {right = middle //因为右开区间,所以right取middle即可} else {return middle} }return -1
};
- 注意:
1、二分法适应于有序数组
2、 Matn.floor((left+right)/2) 为防止溢出可以写成 left + Math.floor((right - left)/2) - 复杂度分析:
时间:O( log n \log_{} {n} logn)
空间:O( 1 1 1)
二、移除元素
- LeetCode题目链接
- 卡尔老师代码随想录讲解
- 关键点: 因为题目强调原地,不开辟新空间,也不强求元素的顺序变化,所以想到双指针的做法。一个指针用来指向下一个元素被保存的位置,一个指针用来不断遍历原数组寻找不被删除的元素
- 代码:
我思考的方法:
想到了一个头指针和尾指针,头指针不断往前用来保存尾指针已经查验过与目标元素不相等的元素,而尾指针用来不断往前将尾部无需删除的元素都置换到前面,找到要删除的元素则不置换。
var removeElement = function(nums, val) {let start = 0let end = nums.length-1while (start <= end) {if (nums[end] != val) {let tmp = nums[start]nums[start] = nums [end]nums[end] = tmpstart++}else {end --}}return start
};
卡尔老师讲解的:
卡尔老师也讲解了一种双指针的做法,但两个指针都从头开始,一个指针用于遍历数组元素,一个指针用于指向将要保存与目标元素不相等的元素的位置。
var removeElement = function(nums, val) {let i = 0; //用来保存非目标元素的指针let j = 0 ; //用来遍历原数组的指针for (;j < nums.length ; j++ ) {if (nums[j] == val ) {//找到要删除的元素,跳过continue}else {//不是要删除的元素,保存到i所指向的位置nums[i] = nums [j]i++}}return i
};
- 注意:
无 - 复杂度分析:
时间:O( n n n)
空间:O( 1 1 1)
三、有序数组的平方
- LeetCode题目链接
- 卡尔老师代码随想录讲解
- 关键点: 按照题目描述是一个非递减顺序排序的整数数组,因为平方组成新数组,考虑负数原因并不能直接平方得到新数组,而数据特征是从数组头和尾部两边往中间,越靠近中间的数其平方越小。
- 代码:
var sortedSquares = function(nums) {let newarr = [] let head = 0let end = nums.length - 1while (head <= end) {let head_2 = Math.pow(nums[head],2)let end_2 = Math.pow(nums[end],2)if (head_2 >= end_2) {newarr.unshift(head_2)head++}else {newarr.unshift(end_2)end--}}return newarr
};
- 注意:
可以先通过 Math.abs() 求得绝对值直接比较,在加入新数组的时候再算平方 - 复杂度分析:
时间:O( n n n),如果先求得平方再进行快排时间复杂度就为O( n n n + + + l o g n log_{}{n} logn)
空间:O( 1 1 1)
四、长度最小的子数组
- LeetCode题目链接
- 卡尔老师代码随想录讲解
- 关键点: 按照题目很容易想到暴力解法,即滑动窗口从第一个元素开始,不断更新滑动窗口末尾位置,但这样的算法会在运行时超时,从而达不到题目要求。根据卡尔老师讲解我们可以确定滑动窗口的末尾,移动滑动窗口的始端,因为要找到长度最小的数组,所以当我们找到更小的长度数组时需要缩小滑动窗口(即将始端前移以找到更小的),不符合 sum > > > target 时需要扩大滑动窗口(即将尾端前移来增加 sum)。
- 代码:
卡尔老师所写的代码简洁明了:
var minSubArrayLen = function(target, nums) {let start, endstart = end = 0let sum = 0let len = nums.lengthlet ans = Infinitywhile(end < len){sum += nums[end];while (sum >= target) {ans = Math.min(ans, end - start + 1);sum -= nums[start];start++;}end++;}return ans === Infinity ? 0 : ans
};
我的写法:代码有问题,但我自查觉得逻辑没问题,在LeetCode两个测试用例没过,希望大家帮我找出问题。
var minSubArrayLen = function(target, nums) {let res = nums.length+1for (let i = 0,j = 0; j < nums.length;) {let sum = 0for (let k=i;k<=j;k++) {sum+=nums[k]}if (sum >= target) {newres = j-i+1console.log(newres)if (newres <= res) { //这里跟卡尔老师的有所区别用的ifres = newresi++}else {j++}}else {j++}}return res > nums.length ? 0 : res
}
- 注意:
卡尔老师的算法的精髓就是在发现比存储的长度小时会让 sum 减去当前 i 的值,并让 i 自减以缩小滑动窗口 - 复杂度分析:
只对卡尔老师参考代码的进行分析
时间:O( n n n),不要以为for里放一个while就以为是O( n 2 n^2 n2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 ∗ n 2*n 2∗n 也就是O( n n n)。
空间:O( 1 1 1)
五、螺旋矩阵II
- LeetCode题目链接
- 卡尔老师代码随想录讲解
- 关键点: 这道题目逻辑不难,因为按螺旋将值填满矩阵即可,我们可以先填充外部矩阵再填充内部矩阵,但关键点是在填充矩阵时什么时候转折,以及转折点在什么时候处理。卡尔老师讲到循环不变量原则,即处理边界时我们不处理边界尾元素,每条边界都按照这样的原则 这样就不会在转折点犯迷糊。
- 代码:
卡尔老师思想代码:
var generateMatrix = function(n) {let arr = Array.from(new Array(n), () => new Array(n))let x = 0 //每次填充的开始x坐标let y = 0 //每次填充的开始y坐标let offset = 1 //缩小边界let count = 1 //需要填充的值从1开始let loop = Math.floor(n/2) //需要几圈螺旋循环while (loop--) {let i,j = 0//处理上边界for (j = y;j < n-offset; j++) {arr [x] [j] = count++ //这里开始位置要看x,不能取i}//处理右边界for (i = x;i < n-offset; i++ ) {arr [i] [j] = count++}//处理下边界for ( ;j > y; j-- ) {arr [i] [j] = count++}//处理左边界for ( ;i > x; i-- ) {arr [i] [j] = count++}//更新开始坐标位置x++y++offset++}if ( n % 2 == 1) {arr [x] [y] = count //奇数圈要填充最后一个元素}return arr
}
不遵循循环不变量 原则:这里用了四个点分别是左上点、右上点、右下点、左下点 从代码简洁读上来看上面明显优于下面。
var generateMatrix = function(n) {//这里我用了正方形的四个角点来获取边界循环条件let topleft = [0,0]let topright = [0,n-1]let bottom_left = [n-1,0]let bottom_right = [n-1,n-1]let i = 1while (i<=n*n) {//左上点和右上点重合说明是最后一个元素了if(topleft[1] == topright[1]){arr[topleft[0]][topleft[1]] = n*nreturn arr}for (let j = topleft[1];j <= topright[1]; j++) {arr[topleft[0]][j]=ii++}for (let j = topright[0]+1;j <= bottom_right[0]; j++) {arr[j][topright[1]]=ii++}for (let j = bottom_right[1]-1;j >= bottom_left[1]; j--) {arr[bottom_right[0]][j]=ii++}for (let j = bottom_left[0]-1;j > topleft[0]; j--) {arr[j][bottom_left[1]]=ii++}topleft[0]++,topleft[1]++topright[0]++,topright[1]--bottom_left[0]--,bottom_left[1]++bottom_right[0]--,bottom_right[1]--}return arr
}
- 注意:
无 - 复杂度分析:
两种写法时间和空间复杂度一致
时间:O( n 2 n^2 n2)
空间:O( 1 1 1)
数据结构算法之数组篇相关推荐
- 用js来实现那些数据结构01(数组篇01-数组的增删)
在开始正式的内容之前,不得不说说js中的数据类型和数据结构,以及一些比较容易让人混淆的概念.那么为什么要从数组说起?数组在js中是最常见的内存数据结构,数组数据结构在js中拥有很多的方法,很多初学者记 ...
- LeetCode算法练习-数组篇
从排序数组中删除重复项 给定一个排序数组,你需要在原地(原地算法)删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度.不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) ...
- 【经典回放】多种语言系列数据结构算法:数组
数组如同前面学过的顺序表,一次性申请一片地址连续的存储空间,我们还知道,计算机中数组是以一维的形式存储的,因为计算机的内存的一维的.在知道了多维数据的计算机存储方式后,我们还要知道构造一个多维数据的方 ...
- java 数组 算法_常见算法总结 - 数组篇
1.给定一个数值在1-100的整数数组,请找到其中缺少的数字. 找到丢失的数字 利用byte数组的1或0标记该数字是否被删除,例如byte数组下标为0的数值为1的话,代表数字1存在 public st ...
- 【数据结构与算法】多种语言(VB、C、C#、JavaScript)系列数据结构算法经典案例教程合集目录
文章目录 1. 专栏简介 2. 专栏地址 3. 专栏目录 1. 专栏简介 2. 专栏地址 「 刘一哥与GIS的故事 」之<数据结构与算法> 3. 专栏目录 [经典回放]多种语言系列数据结构 ...
- 数据结构与算法---稀疏数组
数据结构与算法-稀疏数组 1.基本介绍: 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组. 2.稀疏数组的处理方法是: (1)记录数组一共有几行几列,有多少个 ...
- js 数组 实现 完全树_算法和数据结构 | 树状数组(Binary Indexed Tree)
本文来源于力扣圈子,作者:胡小旭.点击查看原文 力扣leetcode-cn.com 树状数组或二叉索引树(英语:Binary Indexed Tree),又以其发明者命名为 Fenwick 树.其初 ...
- 大话数据结构与算法:基础篇
1.数据结构的重要性 数据结构是计算机软件相关专业的基础课程,几乎可以说,要想从事编程工作,无论是否是科班出身(比如我,标准的非科班人员,我是学医的,哈哈)都不可以绕过数据结构与算法这部分知识. 数据 ...
- 2018汇总数据结构算法篇
看图轻松理解数据结构和算法系列(数组) 看图轻松理解数据结构与算法系列(单向链表) 看图轻松理解数据结构与算法系列(双向链表) 看图轻松理解数据结构与算法系列(基于数组的栈) 看图轻松理解数据结构与算 ...
最新文章
- DDOS三种不同类型的攻击行为—Vecloud
- sql查table,VIEW,sp, function 及 trigger 物件
- Expdp/Impdp 并行导入导出详细测试
- 验证手机号 身份证 中文名称
- tomcat 、jsp、 servlet 、jstl版本对应
- MySQL 中事务、事务隔离级别详解
- 6000万条GitHub帖子告诉你:工作状态与表情符号强相关
- 以太坊概念知识入门篇
- 实验二线性表的链式存储结构
- SpringBoot 错误:Field userService in com.lyh.Controller.UserController required a bean of...
- android sqlite同时读写,SQLite同时读写
- 利用 confluence 打造属于自己的知识库
- Wooboo斥千万巨资 加快手机程序整合步伐
- Oracle 11g 找不到文件 D:\app\Administrator\product\11.2.0\dbhome_1\oc4j\j2ee\oc4j_appli
- Stimulsoft 仪表板.JS 2022.2.1
- Mac上面有哪些宝藏的软件
- 《编程之美》学习笔记
- matlab poly用法
- java使用set去重lit集合集合去重字符串集合去重
- java array缓存_有java数组