当前位置: 首页 > Web前端 > JavaScript

用javascript分类刷leetcode7.双指针(图文视频讲解)

时间:2023-03-26 22:40:26 JavaScript

双指针普通指针:两个指针同向或不同方向碰撞指针:两个指针靠得更近快慢指针:一个一快一慢)给你一个链表的头节点head,判断链表是否有环。如果链表中有一个结点可以通过不断跟踪next指针再次到达,那么链表中就存在环路。为了表示给定链表中的环,评估系统内部使用整数pos表示链表尾部相连的链表中的位置(索引从0开始)。注意:pos不作为参数传递。只是为了识别链表的实际情况。如果链表中存在循环,则返回true。否则,返回false。示例1:输入:head=[3,2,0,-4],pos=1输出:true解释:链表中有一个环,其尾部连接到第二个节点。示例2:输入:head=[1,2],pos=0输出:true解释:链表中有一个环,其尾部连接到第一个节点。示例3:输入:head=[1],pos=-1输出:false解释:链表中没有循环。提示:链表中节点个数的范围是[0,104]-105<=Node.val<=105。pos为-1或链表中的有效索引。更进一步:你能用O(1)(即常量)内存解决这个问题吗?方法一、哈希表或集合:动画太大,点击查看思路:准备一张图或集合,然后循环链表。每遍历一个节点,判断当前节点是否存在于地图中,如果不存在,则将当前节点添加到地图中。如果存在,则说明这个节点之前被访问过,也就是说这个链表是有环的。复杂度分析:时间复杂度O(n),n是链表的个数,最坏情况下,每个节点都要遍历。空间复杂度O(n),n是一个map或者setjs,存储遍历的节点:varhasCycle=(head)=>{letmap=newMap();while(head){if(map.has(head))returntrue;//如果当前节点存在于map中,则说明存在循环map.set(head,true);//否则加入maphead=head.next;//迭代节点}returnfalse;//循环完成如果没有重复的节点,则表示没有循环};方法二、快慢指针动画过大,点击查看思路:准备两个快慢指针,循环链表,慢指针一开始也指向头部,每循环向前走一步,快的指针初始指向头部,每循环向前移动两步。如果没有环,则快指针到达终点。如果有环,快指针就会追上慢指针。复杂度:时间复杂度O(n),空间复杂度O(1)js:varhasCycle=function(head){//设置快慢指针letslow=head;让快=头;//如果没有循环,fast指针会到达终点,否则继续移动双指针while(fast&&fast.next){slow=slow.next;fast=fast.next.next;//快慢指针相遇,说明存在循环if(slow==fast){returntrue;}}返回假;};142.环链表II(中)给定一个链表的头节点head,返回链表的第一个开始入环的节点。如果列表是非循环的,则返回null。如果链表中有一个结点可以通过不断跟踪next指针再次到达,那么链表中就存在环路。为了表示给定链表中的环,评估系统内部使用整数pos表示链表尾部相连的链表中的位置(索引从0开始)。如果pos为-1,则列表中没有循环。注意:pos不作为参数传递,只是为了标识链表的实际情况。不允许修改链表。示例1:输入:head=[3,2,0,-4],pos=1输出:返回索引为1的链表节点解释:链表中有一个环,其尾部连接到第二个节点.示例2:输入:head=[1,2],pos=0输出:返回索引为0的链表节点解释:链表中有一个环,其尾部连接到第一个节点。示例3:输入:head=[1],pos=-1输出:returnnull解释:链表中没有循环。提示:链表的节点数在[0,104]-105<=Node.val<=105pos的值为-1或链表中的有效索引进阶:可以使用O(1)空间解决这个问题?方法一、哈希表思想:遍历链表,将节点添加到一个集合中,每次判断当前节点是否在集合中。如果有重复节点,则该节点为入口节点。复杂度:时间复杂度O(n),空间复杂度O(n)js:vardetectCycle=function(head){constvisited=newSet();while(head!==null){//终止条件,如果没有循环,则跳出循环if(visited.has(head)){//如果有重复节点,则此节点为入口返回头;}visited.add(head);//将节点添加到集合中head=head.next;}返回null;};方法二、快慢指针动画过大,点击查看思路:慢指针移动两步,快指针移动一步,相遇后快指针变成头指针,然后每次快慢指针走一步直到相遇,相遇的节点为入口链接点复杂度:时间复杂度O(n),空间复杂度O(1)js:vardetectCycle=function(head){if(head===空){返回空;}让慢=头,快=头;while(fast!==null){slow=slow.next;//慢指针移动两步,快指针移动一步if(fast.next!==null){fast=fast.next.next;}else{returnnull;//如果没有ring,returnnull}if(fast===slow){//有ringletfast=head;//fast指针指向头节点,然后fast和slow指针每走一步直到相遇,相遇的节点为入口节点while(fast!==slow){fast=fast.next;慢=慢.next;}快速返回;}}返回null;};15.三数之和(medium)给你一个整数数组nums,判断是否存在满足i!=j,i!=k的三元组[nums[i],nums[j],nums[k]]j!=k,同时满足nums[i]+nums[j]+nums[k]==0请返回所有和为0且不重复的三元组。注意:答案中不允许出现重复的三胞胎。示例1:输入:nums=[-1,0,1,2,-1,-4]输出:[[-1,-1,2],[-1,0,1]]解释:nums[0]+nums[1]+nums[2]=(-1)+0+1=0。数[1]+数[2]+数[4]=0+1+(-1)=0。数[0]+数[3]+数[4]=(-1)+2+(-1)=0。不同的三元组是[-1,0,1]和[-1,-1,2]。请注意,输出的顺序和三元组的顺序并不重要。示例2:输入:nums=[0,1,1]输出:[]解释:唯一可能的三重和不为0。示例3:输入:nums=[0,0,0]输出:[[0,0,0]]解释:唯一可能的三重和为0。提示:3<=nums.length<=3000-105<=nums[i]<=105方法1.暴力解,对于三个数,循环3次,分别求和,时间复杂度O(n^3)方法2.c=-(a+b):确定a和b后,可以认为两个数的和相同,求-(a+b)在map中,减少一层循环,时间复杂度O(n^2),空间复杂度O(n)。方法三、排序后发现动画过大,点击查看思路:先对数组排序,数组长度必须大于3,循环数组,如果当前循环到第i个索引,定义两个指针L=i+1,R=nums。length-1,如果sum=nums[i]+nums[L]+nums[R]小于0,则将左指针右移,如果sum大于0,则将右指针移至左边,如果和等于0,正好找到这3个数,然后试L++,R--,继续找中间三个数的和是否等于0。注意,在循环过程中需要删除相同的三个数字。复杂度分析:时间复杂度O(n^2),n为数组长度。空间复杂度O(logn),也就是排序需要的空间js:varthreeSum=function(nums){letans=[];constlen=nums.length;if(nums==null||len<3)returnans;//数组长度大于3nums.sort((a,b)=>a-b);//排序(leti=0;i0)break;//如果当前数大于0,则三个数之和必须大于0,所以结束循环if(i>0&&nums[i]==nums[i-1])continue;//去重让L=i+1;让R=len-1;while(L0)R--;}}返回答案;};请找到并返回返回两个单向链表相交的起始节点。如果两个链表之间没有相交节点,则返回null。如图所示,两个链表相交于节点c1:标题数据保证整个链表结构无环。注意链表在函数返回结果后必须保持原来的结构。自定义评估:评估系统有以下输入(此输入不适用于您设计的程序):intersectVal-相交起始节点的值。如果没有相交节点,则此值为0从这些输入,系统将创建一个链式数据结构并将两个头节点headA和headB传递给您的程序。如果程序正确返回相交节点,则您的解决方案将被视为正确答案。示例1:输入:intersectVal=8,listA=[4,1,8,4,5],listB=[5,6,1,8,4,5],skipA=2,skipB=3输出:相交于'8'说明:交集节点的值为8(注意如果两个链表相交则不能为0)。从各自的表头算起,链表A为[4,1,8,4,5],链表B为[5,6,1,8,4,5]。A中,相交节点之前有2个节点;在B中,相交节点之前有3个节点。—注意交集节点的值不是1,因为列表A和列表B中值为1的节点(A中的第二个节点和B中的第三个节点)是不同的节点。也就是说,它们指向内存中的两个不同位置,ListA和ListB中值为8的节点(A中的第三个节点,B中的第四个节点)指向内存中的同一个位置。示例2:输入:intersectVal=2,listA=[1,9,1,2,4],listB=[3,2,4],skipA=3,skipB=1输出:相交于'2'解释:相交节点的值为2(注意如果两个链表相交则不能为0)。从各自的表头算起,链表A为[1,9,1,2,4],链表B为[3,2,4]。A中,相交节点之前有3个节点;在B中,相交节点之前有1个节点。示例3:输入:intersectVal=0,listA=[2,6,4],listB=[1,5],skipA=3,skipB=2输出:null解释:从各自的表头开始计数,链表A是[2,6,4],链表B是[1,5]。由于两个链表不相交,intersectVal必须为0,而skipA和skipB可以是任意值。两个链表不相交,所以返回null。提示:listA的节点数为mlistB,节点数为n1<=m,n<=3*1041<=Node.val<=1050<=skipA<=m0<=skipB<=n如果有listA和listB之间没有交集,如果listA和listB有交集,则intersectVal为0,intersectVal==listA[skipA]==listB[skipB](1)内存计划?方法一:哈希表思想:集合中存储链表A,第一个相同的节点为重合节点复杂度:时间复杂度O(m+n),m和n分别为两个链表的长度。空间复杂度O(m)js:vargetIntersectionNode=function(headA,headB){constvisited=newSet();让温度=头A;while(temp!==null){//将链表A存入集合visited.add(temp);temp=temp.next;}temp=headB;while(temp!==null){if(visited.has(temp)){//第一个相同的节点为重合节点returntemp;}temp=temp.next;}returnnull;};方法二:双指动画过大,点击查看思路:用双指针pA,pB循环两个链表,链表A循环链表B,而链表A循环结束,链表B循环。当pA==pB时,就是交点,因为两个指针移动的步数是一样的复杂度:时间复杂度O(m+n),m和n分别是两个链表的长度。空间复杂度O(1)js:vargetIntersectionNode=function(headA,headB){if(headA===null||headB===null){returnnull;}让pA=headA,pB=headB;while(pA!==pB){pA=pA===null?headB:pA.next;末尾循环链表B}returnpA;//当pA==pB为交点时};11.给盛水最多的容器(介质)一个长度为n的整数数组高度。有n条垂直线,第i条线的两个端点是(i,0)和(i,height[i])。找到其中两条线,使它们与x轴一起形成一个盛水最多的容器。返回容器可以存储的最大水量。说明:您不能倾斜容器。示例1:输入:[1,8,6,2,5,4,8,3,7]输出:49解释:图中的竖线表示输入数组[1,8,6,2,5,4,8,3,7]。在这种情况下,容器可以容纳的最大水量(以蓝色显示)为49。示例2:输入:height=[1,1]输出:1提示:n==height.length2<=n<=1050<=height[i]<=104方法一:双指针动画过大,点击查看思路:用双指针i,j循环高度数,i,j对应高度小的先向内移动,不断计算面积,并更新最大面积复杂度:时间复杂度O(n),n为数组height的长度,遍历一次。空间复杂度O(1)js:varmaxArea=function(height){letmax=0;for(leti=0,j=height.length-1;i