双指针合集

news2024/12/23 22:22:51

87合并两个有序的数组

在这里插入图片描述

import java.util.*;
public class Solution {
    public void merge(int A[], int m, int B[], int n) {    
        int i = m-1;
        int j = n-1;
        for(int k = n+m-1;k>=0;k--){
            if(j<0) A[k] = A[i--];
            else if(i<0) A[k] = B[j--];
            else if(A[i]>B[j]) A[k] = A[i--];
            else  A[k] = B[j--];
        }
        
    }
}

88 判断是否是回文串

在这里插入图片描述

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param str string字符串 待判断的字符串
     * @return bool布尔型
     */
    public boolean judge (String str) {
        // write code here
        for(int i = 0,j=str.length()-1;i<=j;i++,j--){
            if(str.charAt(i)!=str.charAt(j)) return false;
        }
        return true;
    }
}

89 合并区间

在这里插入图片描述

import java.util.*;
/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
public class Solution {
    public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
        ArrayList<Interval> res = new ArrayList<Interval>();
        //按起点从小到大排序
        Collections.sort(intervals,new Comparator<Interval>(){
            @Override
            public int compare(Interval o1,Interval o2){
                return o1.start-o2.start;
            }
        });
        if(intervals.size()<=1) return intervals;
        Interval cur = intervals.get(0);
        for(int i=1;i<intervals.size();i++){
            Interval next = intervals.get(i);
            if(next.start<=cur.end)
                //区间有可能是完全被包含的
                cur.end = Math.max(cur.end,next.end);
            else{
                res.add(cur);
                cur = intervals.get(i);
            }
        }
        //最后一个要add
        res.add(cur);
        return res;       
    }
}

排序时间O(Nlogn)空间复杂度O(1),res为返回必要空间,没有使用额外辅助空间

90 最小覆盖子串

在这里插入图片描述

滑动窗口

设置两个指针left,right。表示S的子串tmp可由left和right表示,当需要添加元素时候,就将right++,pop元素就left++。

我们用哈希表判断left到right是否完全包含T,动态维护窗口中所有字符以及个数。具体过程如下:

如果新加入的字符是被需要的(指在T里面),那么这个字符加入到窗口中,当窗口中的字符数目和被需要的数目相等时候,匹配度加一。right右移,这里匹配度是window里面的字符与need里面字符相等的数目。

如果新加入的字符不被需要(指不在T里面),right右移

当匹配度等于被需要的字符种类数,说明left-right覆盖到了T的所有字符,并且记录当前的left和right位置,然后就开始向右移动left

如果left位置的字符是被T所需要的,windo所统计的left字符要减一,当窗口中left处的字符数目小于need的字符数目,匹配度减一

如果left位置的字符不是被T所需要的,直接右移即可。

import java.util.*;


public class Solution {
    /**
     * 
     * @param S string字符串 
     * @param T string字符串 
     * @return string字符串
     */
    public String minWindow (String S, String T) {
        // write code here
        //23
        int n = T.length();
        int match = 0;
        //need的存放字符串T的所有字符统计
        HashMap<Character,Integer> need = new HashMap<>();
        //window 存放现有的窗口中出现在need中的字符统计
        HashMap<Character,Integer> win = new HashMap<>();//窗口中已经出现的need
        for(int i=0;i<T.length();i++){
            if(need.containsKey(T.charAt(i))) need.compute(T.charAt(i),(key,value)->value+1);
            else 
                need.put(T.charAt(i),1);
        }
        int left = 0;
        int right = 0;
         //表示窗口左右位置的指针
        int start = 0;
        //start 表示最后结果字符串开始位置
        int minLen = Integer.MAX_VALUE;
        //minlen表示最后字符串长度
        while(right<S.length()){
            char c = S.charAt(right);
            if(need.containsKey(c)){
                if(win.containsKey(c))
                	win.put(c,win.get(c)+1);
                   // win.compute(c,(key,value)->value+1);两种写法都行
                else 
                    win.put(c,1);
                if(need.get(c)>=win.get(c)) match++;
            }
            right++;
            while(match==n){
                //当匹配度等于need.size(),说明这段区间可以作为候选结果,左指针右移
                if(right-left<minLen){
                    minLen = right-left;
                    start = left;
                }
                 char c2 = S.charAt(left);
                if(need.containsKey(c2)){
                    if(win.get(c2)>1) win.compute(c2,(key,value)->value-1);
                    else 
                        win.remove(c2);
                   
                    if(!win.containsKey(c2)||need.get(c2)>win.get(c2)) match--;
                }
                
                left++;
            }

        }
        return minLen == Integer.MAX_VALUE?"":S.substring(start,start+minLen);

    }
}

字符串仅包含大小写字母,则字符集是已知且有限的,那这种情况下我们可以考虑快速查找某个元素是否出现过的哈希表——只需要维护一个哈希表,将字符串T中的字符作为key值,初始化时当字符在T中出现一次则对应的value值减1:
更简洁一些:

import java.util.*;


public class Solution {
    /**
     * 
     * @param S string字符串 
     * @param T string字符串 
     * @return string字符串
     */
     public boolean isAll(int[] hash){
        //判断所有都不为负才说明包含了所有T
        for(int i=0;i<hash.length;i++){
            if(hash[i]<0) return false;
        }
        return true;
     }
    public String minWindow (String S, String T) {
        // write code here
        //A-Z 65-90 
        //a-z 97-122 60大小就够了
        int[] hash = new int[60];//存出现过的字母出现的次数,T需要的先-1一次,其他为0
        Arrays.fill(hash,0);
        for(int i=0;i<T.length();i++){
            hash[T.charAt(i)-'A'] -= 1;//以后遇上再加
        }
        int left = 0;
        int right = 0;
        int minLen = Integer.MAX_VALUE;
        int start = 0;//最后结果的位置的start
        while(right<S.length()){
            hash[S.charAt(right)-'A']++;
            right++;
            //包含了所有的T
            while(isAll(hash)){
                if(right-left<minLen){
                    minLen = right-left;
                    start = left;
                }
                hash[S.charAt(left)-'A']--;
                left++;                  
            }
        }
        return minLen == Integer.MAX_VALUE?"":S.substring(start,start+minLen);
    }
}

92 最长无重复子数组

在这里插入图片描述

用双指针/滑动窗口,用set判断只要没出现过就右指针右移,出现重复就记录长度,然后左指针右移

import java.util.*;


public class Solution {
    /**
     * 
     * @param arr int整型一维数组 the array
     * @return int整型
     */
    public int maxLength (int[] arr) {
        // write code here
        int max = Integer.MIN_VALUE;
        int left = 0;
        int right = 0;
        HashSet<Integer> set = new HashSet<>();
        while(right<arr.length){
            if(!set.contains(arr[right])){
                //没重复就右指针右移
                set.add(arr[right]);
                right++;
            }else{
                //遇到重复的就记录,左指针右移
                max = Math.max(max,right-left);
                set.remove(arr[left]);
                left++;
            }
        }
        return max==Integer.MIN_VALUE?arr.length:max;
    }
}

HashSet中的contains在O(1)(恒定时间)中执行,所以整体的时间复杂度还是O(n)

93 盛水最多的容器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以利用贪心思想:我们都知道容积与最短边长和底边长有关,与长的底边一定以首尾为边,但是首尾不一定够高,中间可能会出现更高但是底边更短的情况,因此我们可以使用对撞双指针向中间靠,这样底边长会缩短,因此还想要有更大容积只能是增加最短变长,此时我们每次指针移动就移动较短的一边,因为贪心思想下较长的一边比较短的一边更可能出现更大容积。

每次移动较短的那个指针,从两边往中间移动

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param height int整型一维数组 
     * @return int整型
     */
    public int maxArea (int[] height) {
        // write code here
        //20
        if(height.length<2) return 0;
        int left = 0;
        int right = height.length-1;
        int max = -1;
        while(left<right){
            max = Math.max(max,Math.min(height[left],height[right])*(right-left));
            //移动较短的一边
            if(height[left]<height[right]) left++;
            else right--;
        }
        return max;
    }
}

step 1:优先排除不能形成容器的特殊情况。
step 2:初始化双指针指向数组首尾,每次利用上述公式计算当前的容积,维护一个最大容积作为返回值。
step 3:对撞双指针向中间靠,但是依据贪心思想,每次指向较短边的指针向中间靠,另一指针不变。

时间复杂度:O(n),双指针共同遍历一次数组
空间复杂度:O(1),常数级变量,没有额外辅助空间

94 接雨水问题

在这里插入图片描述
将整个图看成一个水桶,两边就是水桶的板,中间比较低的部分就是水桶的底,由较短的边控制水桶的最高水量。但是水桶中可能出现更高的边,比如上图第四列,它比水桶边还要高,那这种情况下它是不是将一个水桶分割成了两个水桶,而中间的那条边就是两个水桶的边。

有了这个思想,解决这道题就容易了,因为我们这里的水桶有两个边,因此可以考虑使用对撞双指针往中间靠。
具体做法:
step 1:检查数组是否为空的特殊情况
step 2:准备双指针,分别指向数组首尾元素,代表最初的两个边界
step 3:指针往中间遍历,遇到更低柱子就是底,用较短的边界减去底就是这一列的接水量,遇到更高的柱子就是新的边界,更新边界大小。

import java.util.*;


public class Solution {
    /**
     * max water
     * @param arr int整型一维数组 the array
     * @return long长整型
     */
    public long maxWater (int[] arr) {
        // write code here
        int res = 0;
        int left = 0;
        int right = arr.length-1;
        if(arr.length<3) return 0;
        int height = Math.min(arr[left],arr[right]);
        while(left<right){
            //每次都要更新        
            if(arr[left]<arr[right]){
                left++; 
                res += Math.max(height-arr[left],0);  
                //取第二大的是更新后的height 
                //height是左右较小的那个height<arr[right],现在新出现的是arr[left]
                if(height<arr[left]&&arr[left]<arr[right]) height = arr[left];
                else if(arr[left]>=arr[right]) height = arr[right];
                
            }else{
                right--;  
                res+= Math.max(height-arr[right],0); 
                //height是左右较小的那个height<arr[left],现在新出现的是arr[right]
                if(height<arr[right]&&arr[right]<arr[left]) height = arr[right];
                else if(arr[right]>=arr[left]) height = arr [left];                         
            }

        }
        return res;

    }
}

height就是左右和新出现的边三者中第二大的,关于height的更新debug了很久

题解的写法更简洁一些,只是看题的时候不容易想到:用双指针从两边往中间,同时存左右两边出现过的最大值,二者较小的就是高

import java.util.*;
public class Solution {
    public long maxWater (int[] arr) {
        //排除空数组
        if(arr.length == 0) 
            return 0;
        long res = 0;
        //左右双指针
        int left = 0; 
        int right = arr.length - 1; 
        //中间区域的边界高度
        int maxL = 0; 
        int maxR = 0;
        //直到左右指针相遇
        while(left < right){ 
            //每次维护往中间的最大边界
            maxL = Math.max(maxL, arr[left]); 
            maxR = Math.max(maxR, arr[right]);
            //较短的边界确定该格子的水量
            if(maxR > maxL) 
                res += maxL - arr[left++]; 
            else
                res += maxR - arr[right--];
        }
        return res;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

六道数据结构算法题详解

目录 1.力扣350题. 两个数组的交集 II 2.力扣121题. 买卖股票的最佳时机 3.力扣566题. 重塑矩阵 4.力扣118题. 杨辉三角 5.牛客BM13 判断一个链表是否为回文结构 6.牛客BM14 链表的奇偶重排 1.力扣350题. 两个数组的交集 II 题目&#xff1a;给你两个整数数组 nums1 和 n…

2022年终总结---权衡好工作和生活

2022总结 【校园】2022年6月研究生顺利毕业&#xff0c;让下文的一切才变的有机会。感谢师弟送学长毕业&#xff0c;感谢在最后时刻各位舍友帮忙送材料&#xff0c;怀念最后一个月一起打球的时光。 【工作】2022年6月入职阿里&#xff0c;成为打工人。在这个大的平台&#xf…

Goland项目使用gomod配置

Goland 项目创建 goland2020.3 及以上 IDE&#xff0c;默认创建的 go 项目 就是使用 gomod 管理&#xff01; goland2020.3 及以下的 IDE&#xff0c;创建项目时需要选择 带小括号 vgo 的才是 gomod 管理模式 下图为使用 goland2021.3 版本创建使用 gomod 管理的 go 项目&…

14种可用于时间序列预测的损失函数

在处理时间序列预测问任务时&#xff0c;损失函数的选择非常重要&#xff0c;因为它会驱动算法的学习过程。以往的工作提出了不同的损失函数&#xff0c;以解决数据存在偏差、需要长期预测、存在多重共线性特征等问题。本文工作总结了常用的的 14 个损失函数并对它们的优缺点进…

线段树(Segment tree)

线段树 线段树是一种二叉树形数据结构,用以储存区间或线段,并且允许快速查询结构内包含某一点的所有区间。 视频讲解 线段树主要实现两个方法:「求区间和」&「修改区间」,且时间复杂度均为 O(logn)。 nums = [1, 2, 3, 4, 5] 对应的线段树如下所示: 使用数组表示线段…

【阶段三】Python机器学习33篇:机器学习项目实战:医学病症关联规则分析

本篇的思维导图: 医学病症关联规则分析 项目背景 本项目演示一个医学领域的有趣应用——病症关联规则分析,同时利用apyori库和mlxtend库来编写代码,从数据分析的角度去研究病症背后的关联规则。假设有一种医学理论认为,五脏和一些病症之间存在关联关系,见下表。例…

4.线性神经网络

4.线性神经网络 目录 线性回归 线性回归的基本元素 线性模型损失函数解析解随机梯度下降 矢量化加速正态分布与平方损失 优化方法 梯度下降选择学习率小批量随机梯度下降选择批量大小总结 线性回归的从零开始实现 生成数据集读取数据集初始化模型参数定义模型定义损失函数定义…

磨金石教育摄影技能干货分享|优秀摄影作品欣赏——世界掠影

这世上很多地方都在发生着有趣的事&#xff0c;很多地方不同的人与物&#xff0c;都在不同的时间和环境下展现着不同的状态。让我们跟随摄影师的镜头去欣赏这些精彩的画面吧。1 悬而未定想象一下这张照片是什么角度拍的&#xff1f;是不是看上去很像俯拍&#xff1f;无论怎么看…

【Python】groupby操作后不把列作为索引单独提出

这是一个困了我几天的问题。 一开始的搜索方向错了&#xff0c;按照groupby的key column搜索&#xff0c;没有搜到。 最近悟出的一个技巧是&#xff0c;没有头绪时看看数据类型和数据内容。如果思路是没问题的情况下。 问题描述 date_date.groupby([XXXX]) poi_date.groupby(…

可视化工具,Java 应用性能分析、调优

JVisualVM 简介 VisualVM 是Netbeans的profile子项目&#xff0c;已在JDK6.0 update 7 中自带&#xff0c;能够监控线程&#xff0c;内存情况&#xff0c;查看方法的CPU时间和内存中的对 象&#xff0c;已被GC的对象&#xff0c;反向查看分配的堆栈(如100个String对象分别由哪…

动态规划 —— 最长上升子序列全解

题目链接&#xff1a;300. 最长递增子序列 - 力扣&#xff08;LeetCode&#xff09; 朴素做法 设元素数组为arr&#xff0c;定义一维数组dp&#xff0c;dp[i]表示以i位置结尾的子序列中&#xff0c;最长的上升子序列的长度 这些子序列可以被划分成哪些子集合呢&#xff1f; …

ArcGIS10.8保姆式安装教程,超详细;附安装包

安装前请关闭杀毒软件&#xff0c;系统防火墙&#xff0c;断开网络连接 参考链接&#xff1a;请点击 下载链接&#xff1a; 通过百度网盘分享的文件&#xff1a;ArcGIS10.8zip 链接:https://pan.baidu.com/s/1023fbyQpt6r6U6wtgBuReg 提取码:820w 复制这段内容打开「百度网盘A…

设计模式——解释器模式

解释器模式一、基本思想二、应用场景三、结构图四、代码五、优缺点优点缺点一、基本思想 给分析对象定义一个语言&#xff0c;并定义该语言的文法表示&#xff0c;再设计一个解析器来解释语言中的句子。 二、应用场景 当对象间存在一对多关系&#xff0c;一个对象的状态发生…

ESP32蓝牙+EC11旋转编码器实现对电脑音量控制

ESP32蓝牙EC11旋转编码器实现对电脑音量控制✨本项目基于Arduino开发框架下功能实现。 &#x1f6e0;蓝牙设备添加和连接 ⚡需要有带蓝牙硬件支持的电脑才能实现连接并控制&#xff0c;当然手机也可以连接但是不能实现对手机音量控制&#xff0c; &#x1f33f;以Win10系统电脑…

java 语法基础看这一篇文章就够了

第一章 关键字 关键字的概念1被Java语言赋予了特殊含义&#xff0c;用作专门用途的字符串(单词)关键字特点1关键字中所有字母都是小写常见关键字 classinterfaceenumbyteshortintfloatlongdoublecharbooleanvoidtruefalsenullifelseswitchcasedefaultwhiledoforbreakcontinuer…

数字信号处理音频FIR去噪滤波器(基于MATLAB GUI的开发)

1、内容简介利用MATLAB GUI设计平台&#xff0c;用窗函数法设计FIR数字滤波器&#xff0c;对所给出的含有噪声的声音信号进行数字滤波处理&#xff0c;得到降噪的声音信号&#xff0c;进行时域频域分析&#xff0c;同时分析不同窗函数的效果。将文件解压至一个目录下&#xff0…

第6章 ESP32-Kconfig配置

ESP32-Kconfig配置 1. 新建Kconfig.projbuild文件 2. 写入配置项 新建menu menu "点灯配置"endmenu运行 idf.py menuconfig&#xff0c;结果如下 powershel vscode 可以看到&#xff0c;power shell中文支持上有乱码&#xff0c;所以接下来选择英文 2. 配置menu…

开发实践:一份复杂业务系统的 RESTFul 接口规范

1. 从需求入手 对象&#xff1a;增删改查 对象列表&#xff1a;获取 对象的复杂处理&#xff1a;挖掘、整理、汇总 2. 资源分类 对象型&#xff1a;**/project/1 列表型&#xff1a;**/projects 算法型&#xff1a;**/project/search?input** 3. 设计 URI 3.1. URI 命名…

游戏盾如何防护

什么是游戏盾呢游戏盾是DDoS高防IP产品系列中针对游戏行业的安全解决方案。 游戏盾专为游戏行业定制&#xff0c;针对性解决游戏行业中复杂的DDoS攻击、游戏CC攻击等问题。目前以对抗的形式存在的高防产品形态&#xff0c;也就是防御带宽要大于攻击者的流量。如果你是做运营商商…

设计模式学习(六):Template Method模板方法模式

一、什么是Template Method模式 模板的原意是指带有镂空文字的薄薄的塑料板。只要用笔在模板的镂空处进行临摹&#xff0c;即使是手写也能写出整齐的文字&#xff0c;但是具体写出的文字是什么感觉则依赖于所用的笔。如果使用签字笔来临摹&#xff0c;则可以写出签字似的文字&a…