【双指针】算法例题

目录

 二、双指针

25. 验证回文数 ①

26. 判断子序列 ①

27. 两数之和II - 输入有序数组 ②

28. 盛最多水的容器 ②

29. 三数之和 ②


 二、双指针

25. 验证回文数 ①

 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 

示例 1:

输入: s = "A man, a plan, a canal: Panama"
输出:true
解释:"amanaplanacanalpanama" 是回文串。

示例 2:

输入:s = "race a car"
输出:false
解释:"raceacar" 不是回文串。

示例 3:

输入:s = " "
输出:true
解释:在移除非字母数字字符之后,s 是一个空字符串 "" 。
由于空字符串正着反着读都一样,所以是回文串。

提示:

  • 1 <= s.length <= 2 * 105
  • s 仅由可打印的 ASCII 字符组成

方法1:

    public static boolean isPalindrome(String s) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (Character.isUpperCase(c)){
                c = Character.toLowerCase(c);
            }
            if (Character.isLowerCase(c) || Character.isDigit(c)){
                stringBuilder.append(c);
            }
        }
//        比较的时候要把stringBuilder放左边
//        因为stringBuilder.reverse()会改变stringBuilder的值
        if (stringBuilder.toString().equals("") || stringBuilder.toString().equals(stringBuilder.reverse().toString())){
            return true;
        }else {
            return false;
        }
    }

方法2:

    public boolean isPalindrome(String s) {
        int first = 0;
        int last = s.length() - 1;
        char[] chars = s.toCharArray();
        while (first < last) {
            if(chars[first] < 48 || (chars[first] > 57 && chars[first] < 65) || (chars[first] > 90 && chars[first] < 97) || chars[first] > 122) {
                first++;
                continue;
            }
            if(chars[last] < 48 || (chars[last] > 57 && chars[last] < 65) || (chars[last] > 90 && chars[last] < 97) || chars[last] > 122) {
                last--;
                continue;
            }
            if(chars[first] < 97) chars[first] += 32;
            if(chars[last] < 97) chars[last] += 32;
            if(chars[first] != chars[last]) return false;
            first++;
            last--;
        }
        return true;
    }

26. 判断子序列 ①

 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

进阶:

如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

致谢:

特别感谢 @pbrother 添加此问题并且创建所有测试用例。

示例 1:

输入:s = "abc", t = "ahbgdc"
输出:true

示例 2:

输入:s = "axc", t = "ahbgdc"
输出:false

提示:

  • 0 <= s.length <= 100
  • 0 <= t.length <= 10^4
  • 两个字符串都只由小写字符组成。

方法1(2ms)

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

方法2:(0ms)

    public boolean isSubsequence(String s, String t) {//运用数组和String API
        int index=-1;
        for(char ch:s.toCharArray()){
            index=t.indexOf(ch,index+1);
            if(index==-1){
                return false;
            }
        }
        return true;
    }

27. 两数之和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] 。

提示:

  • 2 <= numbers.length <= 3 * 104
  • -1000 <= numbers[i] <= 1000
  • numbers 按 非递减顺序 排列
  • -1000 <= target <= 1000
  • 仅存在一个有效答案

方法1:(447ms)

    public int[] twoSum(int[] numbers, int target) {
        int[] result = new int[2];
        for (int i = 0; i < numbers.length; i++) {
            for (int j = numbers.length - 1; j > i; j--) {
                if (numbers[j] == target - numbers[i]){
                     result[0] = i + 1;
                     result[1] = j + 1;
                     return result;
                }
            }
        }
        return result;
    }

(1ms)

    public int[] twoSum(int[] numbers, int target) {
        int[] result = new int[2];
        int left = 0;
        int right = numbers.length - 1;
        while (true){
            if (numbers[left] + numbers[right] > target){
                right--;
            }else if (numbers[left] + numbers[right] < target){
                left++;
            }else {
                result[0] = left + 1;
                result[1] = right + 1;
                return result;
            }
        }
    }

28. 盛最多水的容器 ②

 给定一个长度为 n 的整数数组 height 。有 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.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

方法1:(3ms)

    public static int maxArea(int[] height) {
        int left = 0;
        int right = height.length - 1;
        int area = 0;
        while (left < right){
            int min = Math.min(height[left], height[right]);
            if (min * (right - left) > area){
                area = min * (right - left);
            }
            if (min == height[left]){
                left++;
            }else {
                right--;
            }
        }
        return area;
    }

方法2:(1ms)

    public int maxArea(int[] height) {
        int l = 0;
        int r = height.length-1;
        int max = 0;
        int minH;
        while(l<r){
            minH = Math.min(height[l],height[r]);
            max = Math.max(max,minH*(r-l));
           while(l<r&&height[l]<=minH) ++l;
           while(l<r&&height[r]<=minH) --r;
        }
        return max;
    }

29. 三数之和 ②

 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != 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 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

方法1:(通过311/312)

    public static List<List<Integer>> threeSum(int[] nums) {
        ArrayList<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            int left = i;
            int right = nums.length - 1;
            int mid = left + 1;
            while (mid < right){

                if (nums[mid] + nums[right] + nums[left] < 0){
                    mid++;
                }else if (nums[mid] + nums[right] + nums[left] > 0){
                    right--;
                }else {
                    ArrayList<Integer> list = new ArrayList<>();
                    list.add(nums[left]);
                    list.add(nums[mid]);
                    list.add(nums[right]);
                    mid++;
                    right--;
                    if (!result.contains(list)){
                        result.add(list);
                    }
                }

            }
        }
        return result;
    }

对以上代码的修改,使得通过所有用例:(38ms)

    public static List<List<Integer>> threeSum(int[] nums) {
        ArrayList<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            int left = i;
            if (i > 0 && nums[i] == nums[i - 1]){
                continue;
            }
            int right = nums.length - 1;
            int mid = left + 1;
            while (mid < right){

                if (nums[mid] + nums[right] + nums[left] < 0){
                    mid++;
                }else if (nums[mid] + nums[right] + nums[left] > 0){
                    right--;
                }else {
                    result.add(Arrays.asList(nums[left], nums[mid], nums[right]));
                    while (mid < right && nums[mid +1] == nums[mid]){
                        mid++;
                    }
                    while (mid < right && nums[right] == nums[right - 1]){
                        right--;
                    }
                    mid++;
                    right--;
                }
            }
        }
        return result;
    }

方法2:

    public List<List<Integer>> threeSum(int[] nums) {
        //定义一个结果集
        List<List<Integer>> res = new ArrayList<>();
        //数组的长度
        int len = nums.length;
        //当前数组的长度为空,或者长度小于3时,直接退出
        if(nums == null || len <3){
            return res;
        }
        //将数组进行排序
        Arrays.sort(nums);
        //遍历数组中的每一个元素
        for(int i = 0; i<len;i++){
            //如果遍历的起始元素大于0,就直接退出
            //原因,此时数组为有序的数组,最小的数都大于0了,三数之和肯定大于0
            if(nums[i]>0){
                break;
            }
            //去重,当起始的值等于前一个元素,那么得到的结果将会和前一次相同
            if(i > 0 && nums[i] == nums[i-1]) continue;
            int l = i +1;
            int r = len-1;
            //当 l 不等于 r时就继续遍历
            while(l<r){
                //将三数进行相加
                int sum = nums[i] + nums[l] + nums[r];
                //如果等于0,将结果对应的索引位置的值加入结果集中
                if(sum==0){
                    // 将三数的结果集加入到结果集中
                    res.add(Arrays.asList(nums[i], nums[l], nums[r]));
                    //在将左指针和右指针移动的时候,先对左右指针的值,进行判断
                    //如果重复,直接跳过。
                    //去重,因为 i 不变,当此时 l取的数的值与前一个数相同,所以不用在计算,直接跳
                    while(l < r && nums[l] == nums[l+1]) {
                        l++;
                    }
                    //去重,因为 i不变,当此时 r 取的数的值与前一个相同,所以不用在计算
                    while(l< r && nums[r] == nums[r-1]){
                        r--;
                    } 
                    //将 左指针右移,将右指针左移。
                    l++;
                    r--;
                    //如果结果小于0,将左指针右移
                }else if(sum < 0){
                    l++;
                    //如果结果大于0,将右指针左移
                }else if(sum > 0){
                    r--;
                }
            }
        }
        return res;
    }

方法3:(9ms)

    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if (nums == null || nums.length < 3) return res;
        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 2; i++) {
            if (i != 0 && nums[i] == nums[i - 1]) continue;
            int low = i + 1;
            int high = nums.length - 1;
            while (low < high) {
                int sum = nums[low] + nums[high] + nums[i];
                if (sum == 0) {
                    List<Integer> item = new ArrayList<Integer>();
                    item.add(nums[i]);
                    item.add(nums[low]);
                    item.add(nums[high]);
                    res.add(item);
                    low++;
                    high--;
                    while (low < high && nums[low] == nums[low - 1]) low++;
                    while (low < high && nums[high] == nums[high + 1]) high--;
                } else if (sum > 0) {
                    high--;
                } else {
                    low++;
                }
            }
        }
        return res;
    }

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

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

相关文章

面试六分钟,难题显真章

职场&#xff0c;这个充满机遇与挑战的舞台&#xff0c;总会在不经意间上演着意想不到的转折。我从一家小公司转投到另一家&#xff0c;原本期待着新的工作环境和更多的发展机会&#xff0c;然而现实却给了我一个不小的打击。 新公司的加班文化&#xff0c;如同一个巨大的漩涡…

服务器端(Debian 12)配置jupyter与R 语言的融合

融合前&#xff1a; 服务器端Debian 12,域名&#xff1a;www.leyuxy.online 1.安装r-base #apt install r-base 2.进入R并安装IRkernel #R >install.packages(“IRkernel”) 3.通过jupyter notebook的Terminal执行&#xff1a; R >IRkernel::installspec() 报错 解决办…

leetcode 303

leetcode 303 题目 例子 思路 使用数组存储[0, i] 的vals 值之和&#xff0c; sum[i] 表示 第0个元素到第(i-1)个元素之和。 代码 class NumArray {vector<int> sum; public:NumArray(vector<int>& nums) {int n nums.size();sum.resize(n1);for(int i0; …

springboot项目讲解

技术栈 vue(前端) springboot(后端主框架) mybatis&#xff08;ORM&#xff0c;用于后端和数据库的映射&#xff0c;即java对象转换成表&#xff09; mysql (关系型数据库) 顶层结构 .idea&#xff1a; idea缓存文件(不需要管) src&#xff1a;代码核心文件夹 —main&#xf…

进程间通信 之 共享内存

目录 什么是共享内存&#xff1f; 共享内存的系统调用接口 共享内存 进程间通信的本质及前提&#xff1a;让不同的进程看到同一份资源&#xff01; 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间&#xff0c;这些进程间数据传递不再涉及到内核&a…

知识学习app

管理端&#xff1a; &#xff08;1&#xff09;登录 &#xff08;2&#xff09;首页数据报表&#xff1a;1.数据概括2.一周数据走势 &#xff08;3&#xff09;内容管理&#xff1a; 1.分类管理&#xff1a;新增&#xff0c;修改&#xff0c;删除&#xff0c;排序 2.八股文&…

基础监控理论

文章目录 监控流程架构体系监控分类 监控发展和技术企业中监控发展阶段通用技术和工具 监控流程架构体系 监控流程架构体系是确保信息系统健康、稳定运行的重要组成部分&#xff0c;它包括监控系统的设计、搭建、数据分析、数据采集、稳定性测试、自动化集成、部署上线以及图形…

LAMP 世界上使用最广泛的框架(安装LAMP框架)快照

说是框架就不只是一个东西。L:Linux&#xff0c;一种操作系统类型&#xff0c;专为服务器领域服务. A:Apache&#xff0c;web 服务器。 M:MySQL&#xff0c;数据库&#xff0c;存储项目的元数据&#xff0c;真实数据会存放在硬盘中。 P:PHP&#xff0c;一种编程语言&#xff0…

mongoDB7.0.6版安装与使用(最新版踩坑记录)

这里写自定义目录标题 0.前言1.MongoDB下载与安装2.启动服务及验证3.命令行访问4.navicat访问5.停止服务 0.前言 本文总结了最近版mongoDB下载安装的过程及简单的应用&#xff0c;整个过程不涉及修改配置文件&#xff0c;甚至不用设置用户名密码也不用登录认证&#xff0c;在进…

Knife4j的相关知识点!!

一、基础概念 knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名kni4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍! Knif4j&#xff08;原名为 Swagger-Bootstrap-UI&#xff09;是一款基于 Swagger 实现的文档管理工具&am…

Linux命令之Tmux

1. Tmux是什么&#xff1f; Tmux是一个终端复用器&#xff08;terminal multiplexer&#xff09;&#xff0c;属于常用的开发工具&#xff0c;学会了之后可以大大的提高工作效率。 1.1 基本概念 在使用tmux之前我们先了解关于tmux的几个名词&#xff1a; session&#xff0c…

[Qt] 点击QTableWidget item项后键盘输入导致崩溃

复现场景 Qt版本 5.9.8 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);ui->tableWidget->setRowCount(1);ui->tableWidget->setColumnCount(2);Q…

【数据结构取经之路】栈

目录 引言 栈的性质 顺序栈 栈的基本操作 初始化 销毁 插入 删除 判空 取栈顶元素 栈的大小 完整代码&#xff1a; 引言 栈(stack)&#xff0c;可以用数组实现&#xff0c;也可以用链表实现。用数组实现的栈叫顺序栈&#xff0c;用链表实现的栈叫链式栈&#…

PriorityQueue集合源码分析

PriorityQueue集合源码分析 文章目录 PriorityQueue集合源码分析前置知识一、字段分析二、构造函数分析三、方法分析四、总结 PriorityQueue 优先级队列&#xff0c;是基于堆的结构来构建的。而堆是基于完全二叉树来实现的&#xff0c;而二叉树除了可以用节点来实现也可以用数组…

移动WEB开发之流式布局

一、移动端基础 1、浏览器 总结&#xff1a;兼容移动端主流浏览器&#xff0c;处理webkit内核浏览器即可。 2、移动端调试方法 Chrome devtools&#xff08;谷歌浏览器&#xff09;的模拟手机调试 搭建本地web服务器&#xff0c;手机和服务器一个区域网内&#xff0c;通过手机…

SCI一区 | Matlab实现GWO-TCN-BiGRU-Attention灰狼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测

SCI一区 | Matlab实现GWO-TCN-BiGRU-Attention灰狼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现GWO-TCN-BiGRU-Attention灰狼算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测预测效果基本介绍模型描述程序…

框架篇常见面试题

1、Spring框架的单例bean是线程安全的吗&#xff1f; 2、什么是AOP&#xff1f; 3、Spring的事务是如何实现的&#xff1f; 4、Spring事务失效的场景 5、SpringBean的声明周期 6、Spring的循环依赖 7、SpringMVC的执行流程 8、SpringBoot自动配置原理 9、Spring常见注解

解决MySQL “Lock wait timeout exceeded; try restarting transaction“ 错误

在处理MySQL数据库时&#xff0c;我们偶尔会遇到一个棘手的错误消息&#xff1a;“Lock wait timeout exceeded; try restarting transaction”。这通常表明我们的一个事务在尝试获取资源时被阻塞了太长时间。在并发环境中&#xff0c;多个事务同时竞争相同的资源可能会导致这种…

安卓手机切换国内IP地址的几种方法详解

随着互联网的普及和移动设备的广泛使用&#xff0c;IP地址已经成为了日常生活中不可或缺的一部分。IP地址不仅可以帮助大家在互联网上找到目标设备&#xff0c;还可以为网络安全提供一定的保障。然而&#xff0c;在某些情况下&#xff0c;可能需要切换国内IP地址&#xff0c;例…

SpringCloud Bus 消息总线

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第八篇&#xff0c;即介绍 Bus 消息总线。 二、概述 2.1 遗留的问题 在上一篇文章的最后&#xff0c;我…