一起学算法(双指针篇)

news2024/9/25 7:15:36

概念:

        通过两个指针,不断的调整区间,从而求出问题最优解的算法就叫“尺取法”,由于利用的是两个双指针,所以也叫作“双指针”算法,这里的“尺”的含义,主要是因为这类问题,最终要求解的都是连续的序列(子串),就好比一把尺子,故而得名

1.最长不重复子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

 1.初步分析

  • n<=10^7;
  • 最长
  • 所有的字符不重复
  • 子串

       根据上面的几个关键词,我们可以得出一些结论,首先,根据n的范围已经能大致确认这是一个需要O(n)或者O(nlongn)的算法才能解决这个问题;其次,“最长”这个词告诉我们,可能是一个动态规划问题或者是贪心问题,判断字符是否重复可以用hash表在O(1)的时间内进行判断,最后枚举所有的子串是O(n^2)的

2.朴素算法

用max记录我们所需要的最大不重复子串的长度,用一个hash表代表某个字符是否出现过,算法的描述如下:

1.枚举子串的右端点i=0~n-1;

2.当hash表中出现hash[i]>1的时候,相当于双指针指向的区域范围内出现了重复字符,然后移动左指针,直到移出重复字符的时候,对指针区域长度求值,不断的移动,直到找到最大的无重复子串

     public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int left=0;
        int max=0;
        //将字符串转换为char
        char[] str=s.toCharArray();
        int[] hash=new int[128];
        for(int right=0;right<s.length();right++){
            char c=str[right];
            hash[c]++;
            while(hash[c]>1){
                hash[str[left++]]--;
            }
            int val=right-left+1;
            max=Math.max(val,max);
        }
        return max;
    } 

       下面附一张不断枚举左端点的动态图,方便大家理解记忆(如果枚举左端点的话,最后还有额外的去判断是否越界,枚举右端点则不需要)

       当区间内[i,j]中存在重复(红色)字符时,左指针i自增;否则右指针j自增,这部分大家可以自行下去尝试

2.算法描述

算法描述如下:

1.初始化i=0   j=i-1  代表一开始“尺子”的长度为0;

2.增长“尺子”的长度,即j=i+1;

3.判断当前这把“尺子”[i,j]是否满足题目给出的条件

   1.如果满足,记录最优解

   2.如果不满足,则减少“尺子”长度,缩小左端点 i=i+1 再次判断是否符合条件

满足条件时,j++,不满足条件时,i++;

 双指针满足的前提条件:

  • 单调性

      举个栗子:[2 6 9 5 12 5] 这种数组可以用双指正解决么?每次移动它的情况是不确定的

任意一个指指针的增加,条件满足与否只会出现两种情况,即:

满足—>不满足或者是不满足—>满足不会出现 满足—>不满足—>满足

  • 时效性

       必须要在O(1)或者O(log2n)的时间内,求出当前区间[i,j]是否满足既定条件,否则无法用这种算法进行求解

leetcode题单:

反转字符串

    public void reverseString(char[] s) {
        int i=0;
        int j=s.length-1;
        while(i<j){
            char temp=s[i];
            s[i]=s[j];
            s[j]=temp;
            i++;
            j--;
        }
    }

判断子序列

    public boolean isSubsequence(String s, String t) {
      if(s==null||t==null){
          return false;
      }
      int i=0;
      int j=0;
      while(i<s.length()&&j<t.length()){
            if(s.charAt(i)==t.charAt(j)){
                i++;
                j++;
            }else{
                j++;
            }
      }
      return i==s.length();
    }

两数之和

       public int[] twoSum(int[] nums, int target) {
        int[] num = new int[2];
        if (nums == null || nums.length == 0) return num;
        int left=0;
        int right=nums.length-1;
        Arrays.sort(nums);
         while(left<right){
             if(nums[right]+nums[left]==target){
                num[0]=left;
                num[1]=right;
                return num;
            }else if(nums[right]+nums[left]<target){
                  left++;
            }else{
                right--;
            }
            }
        return num;
    }

无重复字符的最长子数组

     public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int left=0;
        int max=0;
        //将字符串转换为char
        char[] str=s.toCharArray();
        int[] hash=new int[128];
        for(int right=0;right<s.length();right++){
            char c=str[right];
            hash[c]++;
            while(hash[c]>1){
                hash[str[left++]]--;
            }
            int val=right-left+1;
            max=Math.max(val,max);
        }
        return max;
    } 

统计公平对的数目

public long countFairPairs(int[] nums, int lower, int upper) {
    //同向双指针
    Arrays.sort(nums);
    long count = 0;
    for (int i = 0; i < nums.length; i++) {
        int num = nums[i];
        //upper-num+1意思就是大于这个目标值的最左侧,右端是不包含
        int m = nearIndex(nums, 0, i, upper - num + 1);
        //lower-num意思就是大于lower-num的最左侧,左端是包含的
        int n = nearIndex(nums, 0, i, lower - num);
        count += m - n;//左闭右开
    }
    return count;
}

//二分搜索最左侧
public int nearIndex(int[] nums, int left, int right, int target) {
    if (left >= right) {
        return left;
    }
    int i = left;
    int j = right;
    while (i < j) {
        int mid = i + (j - i) / 2;
        if (nums[mid] >= target) {
            j = mid;
        } else {
            i = mid + 1;
        }
    }
    return i;
}

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

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

相关文章

刷题笔记 day2

力扣 1089 复写零 思路&#xff1a;双指针 第一步&#xff1a;利用指针 cur 去记录最后一位要复写的数 &#xff0c; 利用指针 dest 指向最后一位数所要复写的位置&#xff1b; 实现过程&#xff1a;最开始 cur 指向0&#xff0c;dest 指向 -1 &#xff0c; 当arr[cur] ! …

高并发与性能优化的神奇之旅

作为公司的架构师或者程序员&#xff0c;你是否曾经为公司的系统在面对高并发和性能瓶颈时感到手足无措或者焦头烂额呢&#xff1f;笔者在出道那会为此是吃尽了苦头的&#xff0c;不过也得感谢这段苦&#xff0c;让笔者从头到尾去探索&#xff0c;找寻解决之法。 目录 第一站&…

深入理解设计模式之模板方法模式

深入理解设计模式之模板方法模式 什么是模板方法模式&#xff1f; 模板方法模式是一种行为型设计模式&#xff0c;它定义了一个算法的骨架&#xff0c;将一些步骤的具体实现延迟到子类中。模板方法模式通过将算法的通用部分抽象出来&#xff0c;以模板方法的形式提供给子类&am…

express学习笔记7 - docker跟mysql篇

安装Docker和Navicat Docker 进官⽹https://docs.docker.com/get-docker/ 选择机型安装即可。 Navicat&#xff08;也可以在网上找个破解版本&#xff09; 进官⽹https://www.navicat.com/en/products/navicat-premium 安装完之后连接新建⼀个数据库连接 然后再⾥⾯新建⼀个数…

【编程语言 · C语言 · 通讯录管理系统】

【编程语言 C语言 通讯录管理系统】https://mp.weixin.qq.com/s?__bizMzg4NTE5MDAzOA&mid2247491539&idx1&sn02173f15bbff6d5f01a3426a1ecf7120&chksmcfade32af8da6a3cb187ecde99fe0519c4d67ef05488754ab2196fab0915262c260ccc68b304&payreadticketHEsQ…

MacOS使用brew如何下载Nginx

首先&#xff0c;第一步切换源&#xff1a; 切换 brew.git 仓库地址&#xff1a; cd "$(brew --repo)" git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git 替换 homebrew-core.git 仓库地址: cd "$(brew --repo)/Library/Taps/home…

无线蓝牙耳机有什么值得耳机买的?几款值得买的口碑品牌盘点

蓝牙耳机是一种无线耳机&#xff0c;其通过蓝牙技术与其他设备进行连接&#xff0c;例如手机、电脑、平板电脑等。蓝牙耳机使得用户可以在不受线缆限制的情况下享受音频体验&#xff0c;而且还可以方便地进行通话&#xff0c;目前市场上有许多不同种类和品牌的蓝牙耳机&#xf…

大厂原来都这么使用IDEA远程调试的!

远程调试是一项重要的技术&#xff0c;特别是对于使用IDEA开发的开发者来说。在本篇技术博客中&#xff0c;我们将探讨如何使用IDEA进行远程调试。 1 IDEA 配置 首先&#xff0c;我们需要确保我们的开发环境已经准备就绪。我们需要在远程服务器上安装并配置好调试器&#xff…

【福建事业单位-语言理解】02 细节判断-标题填入-词句理解

【福建事业单位-语言理解】02 细节判断-标题填入-词句理解 一、细节判断题细节判断优先验证原则总结 二、标题填入题总结 三、词句理解题3.1 代词指代实词理解句子理解总结 一、细节判断题 如果文段长难怪绕&#xff0c;就先看选项&#xff0c;反之一样。 面对温和的可能性表述…

java集成短信服务 测试版 qq邮箱简单思路

java集成短信服务 注册一个帐号 使用的是容联云&#xff0c;百度搜一下官网 用手机注册一个帐号就行&#xff0c;免费体验不需要认证 注册后会有八块钱送&#xff0c;可以使用免费的给自己设置三个固定手机号发送短信&#xff0c;不需要认证。 此页面的 三个信息需要在代码中…

免驱触摸屏为啥在我的Linux上驱动不起来

背景&#xff1a; 某宝上买了个HDMI接口的触摸屏&#xff0c;用树莓派驱动没啥问题&#xff0c;但是用在我自己定制的Linux系统上&#xff0c;咋都不好使&#xff0c;咨询商家&#xff0c;商家说触摸屏的芯片是GT911&#xff0c;芯片是I2c协议&#xff0c;触摸屏上是usb接口的…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(19)-Fiddler精选插件扩展安装,将你的Fiddler武装到牙齿

1.简介 Fiddler本身的功能其实也已经很强大了&#xff0c;但是Fiddler官方还有很多其他扩展插件功能&#xff0c;可以更好地辅助Fiddler去帮助用户去开发、测试和管理项目上的任务。Fiddler已有的功能已经够我们日常工作中使用了&#xff0c;为了更好的扩展Fiddler&#xff0c…

这9个UI设计工具一定码住!非常好用

对于设计师来说&#xff0c;好用的UI设计工具无疑会对设计工作起到事半功倍的作用&#xff0c;今天本文与大家分享9个好用的UI设计工具&#xff0c;一起来看看吧&#xff01; 1、即时设计 即时设计是一个能在网页中直接使用&#xff0c;且支持团队协作的国产UI设计工具&#…

你的shell脚本存在安全问题吗?

更多技术资料&#xff0c;请关注微信公众号“运维之美” 信息安全对于线上环境显得尤为重要&#xff0c;shell脚本的代码中可能经常会引用到密码等变量进行赋值等场景&#xff0c;但是在使用的过程中可能会导致环境的登录信息泄露&#xff0c;导致安全隐患&#xff0c;那么如何…

ISO 7637-2 5a/5b抛负载测试保护用TVS二极管,如何选型号?

在国际标准ISO 16750-2颁布之前&#xff0c;全球各大汽车零部件制造商一直采用的是ISO 7637-2标准。ISO 16750-2国际标准发行之后&#xff0c;汽车抛负载浪涌测试中ISO 7637-2 5A和5B测试标准被ISO 16750-2测试标准取代。查看ISO 16750-2和ISO 7637-2国际标准文档资料对比会发现…

matlab编程实践16、17

捕食者与猎物模型 人口增长 在人口增长或衰减的最简单模型中&#xff0c;增长速度或衰减速度与人口本身的数目成正比。增加或减少人口规模会导致出生和死亡数量成比例地增加或减少。在数学上&#xff0c;可以由以下微分方程描述。 可以得出&#xff1a;&#xff0c;其中。 该简…

【mysql】Win10安装配置MySQL8.0简要

下载 MySQL官网下载安装包 安装

SpringBoot复习:(8)SpringBoot中是怎么判断应用类型是Servlet应用还是WebFlux应用?

在SpringApplication的构造方法里&#xff1a; 调用了WebApplicationType类的静态方法deduceFromClasspath, 该方法调用了ClassUtils类的isPresent方法来判断某个类是否能加载成功&#xff0c;首先判断&#xff0c;如果WebFlux相关的类能加载成功&#xff0c;就说明是WebFlux…

VGN N75pro说明书

VGN N75pro说明书 1、封面和最后一页 2、第01、02、03 3、第04 4、第05

可靠性工程师是做什么的?需要哪些能力?

一、可靠性工程师是做什么的&#xff1f; 官方解释&#xff0c;可靠性工程师是通过产品可靠性试验&#xff0c;进行性能评估&#xff0c;并预测如何改进产品或体系的安全性、可靠性、可维护性。 简单来说&#xff0c;客户在使用产品的过程中&#xff0c;会出现各种各样的质量…