【双指针】经典数组双指针题LeetCode

文章目录

      • 27. 移除元素 简单
      • 283. 移动零 简单🔥
      • 167. 两数之和 II - 输入有序数组 中等
      • 11. 盛最多水的容器 中等🔥
      • 15. 三数之和 中等(N数之和)中等🔥
      • 42. 接雨水 困难 🔥
      • 26. 删除有序数组中的重复项 简单
      • 5. 最长回文子串 中等

27. 移除元素 简单

题目链接

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

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

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

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。


思路:双指针

  • right指针不是val就赋值给left,right++,left++
  • right指针是val就跳过,right++

代码:

class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0,right = 0;
        while(right<nums.length){
            if(nums[right]!=val){
                nums[left] = nums[right];
                left++;
            }
            right++;
        }
        return left;
    }
}

283. 移动零 简单🔥

题目链接

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

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

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:

输入: nums = [0]
输出: [0]


思路: 前后双指针,将每一个不是0的元素赋值给前面的指针,对未重新赋值的部分赋值0。
代码:

class Solution {
    public void moveZeroes(int[] nums) {
        int left = 0;
        int right = 0;
        // 依次将right指针指向的非0元素赋值给left指针
        while(right<nums.length){
            if(nums[right]!=0){
                nums[left] =  nums[right];
                left++;
            }
            right++;
        }
        // 从 left 开始 赋值0
        for(int i = left; i < nums.length;i++){
            nums[i] = 0;
        }

    }
}

167. 两数之和 II - 输入有序数组 中等

题目链接

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
示例 2:

输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。
示例 3:

输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

思路:在已排序数组(非递减)的前提条件下,Left指针指向第一个元素,Right指针指向最后一个元素。当两者大于目标值时,移动Left指针(left++),小于目标值时,移动Right指针(right–),直到找到目标答案。

代码:

class Solution {
    public int[] twoSum(int[] numbers, int target) {

        int left = 0;
        int right = numbers.length-1;
        
        while(left!=right){
            if(numbers[left]+numbers[right]==target){ // 等于目标值
                return new int[]{left+1,right+1};
            }
            if(numbers[left]+numbers[right]>target){ // 大于目标值,通过right-- 以缩小两者的和
                right--;
            }else{                                  //  小于目标值,通过left++ 以扩大两者的和
                left++;
            }
        }
        return new int[]{-1,-1};
    }
}

11. 盛最多水的容器 中等🔥

题目链接

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。
在这里插入图片描述


思路:该题首先想到的思路就是暴力搜索,两个For循环寻找最大值,但是时间复杂度过高。我们知道计算机两条线中间容器所盛水的容量取决于两条线中的短边,为了计算容量的最大值,我们只需要更改短边即可。因此,采用左右双指针法,每次移动短边所在的指针,以寻找最大容量。

代码:

class Solution {
    public int maxArea(int[] height) {
        // 左右指针
        int left = 0;
        int right = height.length - 1;

        int result = 0;

        while(left<right){
            // 计算当前盛水量
            int currentResult = Math.min(height[left],height[right]) * (right-left);

            // 更新结果
            result = Math.max(result,currentResult);

            // 左右指针所在的两条线谁矮谁移动,以求最大值
            if(height[left]<height[right]){
                left++;
            }else{
                right--;
            }
        }
        return result;
    }
}

15. 三数之和 中等(N数之和)中等🔥

题目链接

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != 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 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[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 。

思路:

  • 先将数组排序,将三数之和化简为二数之和问题;先固定一个值,寻找另外两个值。
  • 二数问题依旧采用双指针法解决,但需要考虑答案重复问题,每次移动指针,比如left和left++所在的值一样,则会重复寻找,因此继续++,直到不同。
  • 在数组中,从第一个值开始依次选取一个值进行固定,在其后面的数组中继续寻找另外两个值。(不用再寻找固定值前面的值,否则依旧会重复查找)。
  • 可以将三数之和问题扩展为N数之和问题,将目标和为0改为target。通过递归法将问题不断缩小。
  • 5数之和->就是把每一个4数之和的答案加上固定的那个值,就是5数之和的答案。

代码(N数之和):

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums); // 先排序 
        return nSumTarget(nums,0,0,3); // 3数之和等于0
    }

    /**
        nSumTarget:可以解决N sum问题
        参数:
        - nums:数组
        - target:目标值
        - start:只在[start,nums.length-1]区间寻找
        - needNum:需要几个数,两数之和就是2,三数之和就是3
     */
    public List<List<Integer>> nSumTarget(int[] nums,int target,int start,int needNum){
        List<List<Integer>> res = new ArrayList<>();
        
        if(needNum<2 || nums.length<needNum) return res;

        
        if( needNum == 2){ // 同理 二数之和

                int left = start,right = nums.length-1;
                while(left<right){
                    int leftnum = nums[left];
                    int rightnum = nums[right];
                    if(leftnum+rightnum == target){
                        res.add(new ArrayList<Integer>(Arrays.asList(leftnum,rightnum)));
                        while(left<right && nums[right]==rightnum)right--; // right-- 所在的值如果和right一样,则重复寻找了,因此寻找一个和原来right不一样的,即去重
                        while(left<right && nums[left] == leftnum)left++;  // 同理,去重
                    }
                    else if(leftnum+rightnum < target){
                        while(left<right && nums[left] == leftnum)left++; // 同理,去重
                    } 
                    else if(leftnum+rightnum > target){
                        while(left<right && nums[right]==rightnum)right--;// 同理,去重
                    }
                }
                return res;
        }else{ // 先定下一个数,将问题规模缩小
            
            for(int i = start; i < nums.length;i++){
                int cur = nums[i]; 
                List<List<Integer>> re = nSumTarget(nums,target-cur,i+1,needNum-1); // 递归调用
                
                for(List<Integer> r:re){
                    r.add(cur);// 将定下的数加入到每个字问题的答案中
                    res.add(r);// 将r加入到最终答案中
                }
                while(i+1 < nums.length && nums[i]==nums[i+1])  i++; // 同理,去重
            }
            return res; // 最终答案
            
        }
    }
}

42. 接雨水 困难 🔥

题目链接

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

在这里插入图片描述


思路:
在这里插入图片描述
除了最两边的位置不可能盛水以外,中间位置的盛水量受左右两边高度的影响,主要取决于较小的一边的最大高度。

代码:

class Solution {
    public int trap(int[] height) {


        int len = height.length;

        if(len<=2)return 0; // base case 

        int[] leftMaxHeight = new int[len]; // 计算每个节点左侧出现过的最大高度(包括当前节点)
        int[] rightMaxHeight = new int[len];// 计算每个节点右侧出现过的最大高度(包括当前节点)

        int leftMax = 0;
        for(int i = 0; i < len;i++){
            leftMax = Math.max(leftMax,height[i]);
            leftMaxHeight[i] = leftMax;
        }
        int rightMax = 0;
        for(int i = len-1; i >= 0; i--){
            rightMax = Math.max(rightMax,height[i]);
            rightMaxHeight[i] = rightMax;
        }
        
        int res = 0;
        for(int i = 1;i< len-1;i++){
            res += Math.min(leftMaxHeight[i],rightMaxHeight[i]) - height[i];
        }
        return res;
    }
}

是否可以再次简化?

通过定义左右双指针,left = 0right = length-1,同时求出leftMaxHeight和rightMaxHeight。并在这个过程中,求出每个位置的盛水量。
在这里插入图片描述

class Solution {
    public int trap(int[] height) {


        int len = height.length;

        if(len<=2)return 0; // base case 

        // 左右指针
        int left = 0,right = len - 1;

        // 记录左/右指针的左/右边的最大值(包括左/右节点)
        int leftMax = 0;
        int rightMax = 0;

        int res = 0;

        while(left<=right){
            leftMax = Math.max(leftMax,height[left]);
            rightMax = Math.max(rightMax,height[right]);

            if(leftMax < rightMax){
                // 此时,left位置的 Min(左边最大,右边最大)已经确定,就是【左边最大】,即leftMax
                res += leftMax - height[left];
                left++;
            }else{
                // 同理
                res += rightMax - height[right];
                 right--;
            }
        }

        return res;
    }
}

26. 删除有序数组中的重复项 简单

题目链接

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
返回 k 。

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。


思路:快慢指针,快指针如果不等于慢指针,就将快指针的值赋给慢指针的下一个。

代码:

class Solution {
    public int removeDuplicates(int[] nums) {
        int left = 0;
        int right = 0;
        while(right<=nums.length-1){
            if(nums[right]!=nums[left]){
                nums[++left] = nums[right];
                right++;
            }else{
                right++;
            }
        }
        return left+1;

    }
}

5. 最长回文子串 中等

题目链接

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

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。

示例 2:
输入:s = “cbbd”
输出:“bb”


思路:

  • 通过双指针从中间向外扩,判断回文
  • 依次选择原字符串的中间节点
  • 注意奇数数量和偶数数量的回文串中间节点个数不一样

代码:

class Solution {
    public String longestPalindrome(String s) {
		String result = null;

		result = s.substring(0,1);

		String r;
		// 遍历每一个字符,将其作为回文串的中心向外扩展
		for(int i = 1; i < s.length(); i++) {
			r = Palindrome(s,i,i);// 寻找奇数个的回文子串
			if(r.length()>result.length())result = r;
			r = Palindrome(s,i-1,i);// 寻找偶数个的回文子串
			if(r.length()>result.length())result = r;
		}
		return result;
	}

	/**
	 * 返回以s[a]与s[a]为中心的最大回文字串,a可以等于b 或者 a+1 = b
	 * ps:一种回文串为偶数个,中心两个字母、另一种为奇数个,中心一个字母
	 * @param s
	 * @param a
	 * @param b
	 * @return
	 */
	public String Palindrome(String s,int a,int b) {

		// 若s[a]!=s[b] return ""
		if(s.charAt(a) != s.charAt(b))return "";

		while (a >= 0 && b<s.length() ){

			if(s.charAt(a) == s.charAt(b)){
				a--;b++;
			}else break;
		}
		a = a+1;
		b = b-1;
		return s.substring(a,b+1);
	}
}

参考:
1.《labuladong的算法小抄》
2. https://labuladong.github.io/algo/di-yi-zhan-da78c/shou-ba-sh-48c1d/shuang-zhi-fa4bd/
3. LeetCode Hot 100 🔥

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/87754.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python并发编程

一、程序提速的方法 二、python对并发编程的支持 多线程&#xff1a;threading&#xff0c;利用CPU和IO可以同时执行的原理&#xff0c;让CPU不会干巴巴等待IO完成&#xff1b;多进程&#xff1a;multiprocess&#xff0c;利用多核CPU的能力&#xff0c;真正的并行执行任务&am…

PyTorch学习笔记(十六)——利用GPU训练

一、方式一 网络模型、损失函数、数据&#xff08;包括输入、标注&#xff09; 找到以上三种变量&#xff0c;调用它们的.cuda()&#xff0c;再返回即可 if torch.cuda.is_available():mynn mynn.cuda() if torch.cuda.is_available():loss_function loss_function.cuda(…

App Tamer for Mac CPU智能控制管理

App Tamer是一款针对 macOS 平台的软件&#xff0c;它可以帮助用户有效地管理和控制正在运行的应用程序。通过优化 CPU 使用率&#xff0c;减少电池消耗和降低系统负载&#xff0c;App Tamer 提供了更加流畅和高效的计算体验。 App Tamer 的主要特点包括&#xff1a; 智能控制&…

GAN:对抗生成网络,前向传播和后巷传播的区别

目录 GAN&#xff1a;对抗生成网络 损失函数 判别器开始波动很大&#xff0c;先调整判别器 生成样本和真实样本的统一&#xff1a;真假难辨​编辑 文字专图片​编辑 头像转表情包​编辑 头像转3D​编辑 后向传播 1. 前向传播&#xff08;forward&#xff09; 2. 反向传播&…

Linux下彻底卸载jenkins

文章目录 1、停服务进程2、查找安装目录3、删掉相关目录4、确认已完全删除 1、停服务进程 查看jenkins服务是否在运行&#xff0c;如果在运行&#xff0c;停掉 ps -ef|grep jenkins kill -9 XXX2、查找安装目录 find / -name "jenkins*"3、删掉相关目录 # 删掉相…

数字的画笔:数据可视化的魅力与实用性

数据可视化是一种强大的工具&#xff0c;用于将复杂的数据和信息以图形化的方式呈现&#xff0c;以便人们更容易理解、分析和发现其中的模式和趋势。通过图表、图形和其他可视元素&#xff0c;数据可视化可以帮助我们将抽象的数字转化为有意义的视觉呈现&#xff0c;从而提升了…

基于Spark+django的国漫推荐系统--计算机毕业设计项目

近年来&#xff0c;随着互联网的蓬勃发展&#xff0c;企事业单位对信息的管理提出了更高的要求。以传统的管理方式已无法满足现代人们的需求。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;随着各行业的不断发展&#xff0c;基…

计算机网络——OSI与TCP/IP各层的结构与功能,都有哪些协议?

文章目录 一 OSI与TCP/IP各层的结构与功能,都有哪些协议?1.1 应用层1.2 运输层1.3 网络层1.4 数据链路层1.5 物理层1.6 总结一下 二 ⭐TCP 三次握手和四次挥手(面试常客)2.1 TCP 三次握手漫画图解2.2 为什么要三次握手⭐2.3 第2次握手传回了ACK&#xff0c;为什么还要传回SYN&…

面试热题(复原ip地址)

有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址&#xff0c;但是 "0.011.255.24…

五家项目进度管理工具,哪家好?

项目进度管理十分依赖项目经理对于项目信息的掌握程度&#xff0c;数字化工具可以很好的解决项目信息不统一的问题。一款好用的项目进度十分重要。目前市面上项目进度管理工具哪家好&#xff1f; 1、Zoho Projects&#xff1b;2、Microsoft Project&#xff1b;3、Trello&#…

【jsthreeJS】入门three,并实现3D汽车展示厅,附带全码

首先放个最终效果图&#xff1a; 三维&#xff08;3D&#xff09;概念&#xff1a; 三维&#xff08;3D&#xff09;是一个描述物体在三个空间坐标轴上的位置和形态的概念。相比于二维&#xff08;2D&#xff09;只有长度和宽度的平面&#xff0c;三维增加了高度或深度这一维度…

15.树与二叉树基础

目录 一. 树&#xff0c;基本术语 二. 二叉树 &#xff08;1&#xff09;二叉树 &#xff08;2&#xff09;满二叉树 &#xff08;3&#xff09;完全二叉树 三. 二叉树的性质 四. 二叉树的存储结构 &#xff08;1&#xff09;顺序存储结构 &#xff08;2&#xff09;链…

电视盒子哪个好?花4K测评16款电视盒子,谁才是性价比天花板?

大家好&#xff0c;欢迎来到小白的数码频道&#xff0c;我花费4000多元购入了目前市面上销量最火爆的16款电视盒子&#xff0c;其中包含9个品牌&#xff0c;通过两周各个维度的对比后&#xff0c;整理了实测结果。电视盒子品牌产品让人眼花缭乱&#xff0c;跟着我一起看看究竟电…

凉而不冷 柔而不弱 三菱重工海尔舒适风科技助您整夜安眠

古人云&#xff1a;安寝乃人生乐事。可随着夏天的到来&#xff0c;昼长夜短&#xff0c;家里的老人、儿童、父母都存在不同的入睡苦恼。对于儿童来说&#xff0c;空调温度调的太低容易踢被子着凉&#xff0c;温度调的高又怕孩子满头大汗&#xff1b;父母自身也会因为半夜帮孩子…

代码随想录算法训练营第四十四天 | 完全背包,518. 零钱兑换 II,377. 组合总和 Ⅳ

代码随想录算法训练营第四十四天 | 完全背包&#xff0c;518. 零钱兑换 II&#xff0c;377. 组合总和 Ⅳ 完全背包518. 零钱兑换 II377. 组合总和 Ⅳ 完全背包 视频讲解 有N件物品和一个最多能背重量为W的背包&#xff0c;第i件物品的重量weight[i]&#xff0c;得到的价值是va…

使用Python搭建服务器公网展示本地电脑文件

文章目录 1.前言2.本地http服务器搭建2.1.Python的安装和设置2.2.Python服务器设置和测试 3.cpolar的安装和注册3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 Python作为热度比较高的编程语言&#xff0c;其语法简单且语句清晰&#xff0c;而且python有…

数据结构(7)

B树 B树中允许一个节点拥有多个key。设定参数M&#xff0c;构造B树 1.每个结点最多右M-1个key&#xff0c;并且以升序排列 2.每个结点最多右M个子结点 3.根节点至少右两个子结点 通过磁盘预读&#xff0c;将数据放到B树中&#xff0c;3层B树可容纳1024*1024*1024差不多10亿…

从其他地方复制的内容无法粘贴到idea中

问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 使用 idea 开发的时候&#xff0c;从其他地方复制的内容无法粘贴到 idea中&#xff0c;idea的版本是 2023.2 解决方案&#xff1a; 提示&#xff1a;这里填写该问题的具体解决方案&#xff1a; 网上查找资料…

JVM——类加载与字节码技术—编译期处理+类加载阶段

3.编译期处理 编译期优化称为语法糖 3.1 默认构造器 3.2 自动拆装箱 java基本类型和包装类型之间的自动转换。 3.3泛型集合取值 在字节码中可以看见&#xff0c;泛型擦除就是字节码中的执行代码不区分是String还是Integer了&#xff0c;统一用Object. 对于取出的Object&…

骨传导耳机适合运动时佩戴吗?精选五款适合运动时佩戴的耳机

当专业运动耳机已经成了运动新贵们的常用穿戴拍档&#xff0c;给夜跑、骑行、撸铁增添了更多期待和振奋。而骨传导耳机凭借自身健康、舒适、安全的聆听方式,迅速脱颖而出成为运动健身中最健康的黑科技耳机&#xff0c;但由于市面上的骨传导耳机技术参差不齐&#xff0c;一不留神…