leetCode - - - 双指针

news2024/11/24 15:03:33

目录

1.寻找重复数(LeetCode 287)

解法一:二分查找

解法二:快慢指针

2.验证回文串(LeetCode 125)

3.三数之和(LeetCode 15)

4.四数之和(LeetCode 18)

5.x 的平方根(LeetCode 69)

6.总结


1.寻找重复数(LeetCode 287)

https://leetcode.cn/problems/find-the-duplicate-number/description/

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

示例 1:

输入:nums = [1,3,4,2,2]
输出:2

示例 2:

输入:nums = [3,1,3,4,2]
输出:3

示例 3 :

输入:nums = [3,3,3,3,3]
输出:3

提示:

  • 1 <= n <= 105
  • nums.length == n + 1
  • 1 <= nums[i] <= n
  • nums 中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次

进阶:

如何证明 nums 中至少存在一个重复的数字?

你可以设计一个线性级时间复杂度 O(n) 的解决方案吗?

解题思路:

题目要求:常量级 O(1) 的额外空间,so~用不了哈希表啦~,so~缩小范围找~,那就二分查找~

所以,先按照二分查找解题。

解法一:二分查找

class Solution {
    public int findDuplicate(int[] nums) {
        int left=1;
        int right=nums.length-1;
        
        while(left<right){
            int count=0;
            int mid=(left+right)/2;
            for(int num:nums){
                if(num<=mid){
                    count++;
                }
            }
            if(count>mid){
                right=mid;
            }else{
                left=mid+1;
            }
        }
        return left;
    }
}

二分查找时间复杂度为:n(logn)

人家题目还想让你设计一个线性级时间复杂度 O(n) 的解决方案。

卷吧卷吧,官方给的解法是快慢指针。我真的栓Q,按照答案的意思,按照索引指向能够构造出一个有环路的链表,环闭合的位置就是重复的元素。按照求环路链表环的思路解这个数组题,逆天~

so~

解法二:快慢指针

class Solution {
    public int findDuplicate(int[] nums) {

        // 1、通过快慢指针的方式,在环中寻找它们的第一次相遇的节点位置

        // 2、定义一个慢指针,每次只会向前移动 1 步
        int slow = 0;

        slow = nums[slow];

        // 3、定义一个快指针,每次只会向前移动 2 步
        int fast = 0;

        fast = nums[nums[fast]];

        // 4、如果链表有环,那么无论怎么移动,fast 指向的节点都是有值的
        while (slow != fast) {
            // 慢指针每次只会向前移动 1 步
            slow = nums[slow];
            // 快指针每次只会向前移动 2 步
            fast = nums[nums[fast]];
        }

        // 定义两个指针,一个指向相遇节点,定义为 b,一个指向链表头节点,定义为 a
        // 一个指向相遇节点,定义为 b
        int b = fast;

        // 一个指向链表头节点,定义为 a
        int a = 0;
          
        // 让 a 、b 两个指针向前移动,每次移动一步,直到相遇位置
        // 由于有环,必然相遇
        // 当 b 走了 n(y + z) - y 时,b 到达了环形入口节点位置
        // 当 a 走了 x 步时,a 到达了环形入口节点位置
        // a 与 b 相遇
        while (a != b) {
            // a 指针每次只会向前移动 1 步
            a = nums[a];
            // b 指针每次只会向前移动 1 步
            b = nums[b];
        }
        // 6、返回 a 和 b 相遇的节点位置就是环形入口节点位置
        return a;
    }
}

2.验证回文串(LeetCode 125)

https://leetcode.cn/problems/valid-palindrome/

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

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

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

示例 1:

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

示例 2:

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

class Solution {
    public boolean isPalindrome(String s) {
        int left=0;
        int right=s.length()-1;
        while(left<right){
            while(left<right && !Character.isLetterOrDigit(s.charAt(left))){
                left++;
            }
             while(left<right && !Character.isLetterOrDigit(s.charAt(right))){
                right--;
            }
            // 来到这里时
            // 要么 left 和 right 相遇了,跳出循环
            // 要么 left 和 right 还没有相遇,并且它们都是指向字母或者数字
            if(left<right){
                if(Character.toLowerCase(s.charAt(left))!=Character.toLowerCase(s.charAt(right))) {
                   return false;
                }else{
                    left++;
                    right--;
                }
            }
        }
        return true;
    }
}

3.三数之和(LeetCode 15)

https://leetcode.cn/problems/3sum/description/

给你一个整数数组 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 。

解题思路:
1.排序数组:对输入数组进行排序,以便使用双指针方法。
2.初始化结果列表:创建一个列表来存储最终的三元组结果。
3.遍历每个元素:对于每个元素,将其作为三元组的第一个元素。
如果当前元素大于零,结束循环,因为后面的元素也大于零,不可能和为零。
跳过与前一个元素相同的元素以避免重复。
4.双指针搜索:设置两个指针,left 和 right,在当前元素后面查找其他两个元素使三数之和为零。
如果三数之和为零,记录该三元组并跳过重复元素。
根据三数之和的大小调整左右指针的位置。
 

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> list=new ArrayList<>();
        for(int i=0;i<nums.length-2;i++){
            if(nums[i]>0) break;

            if(i>0 && nums[i]==nums[i-1]) continue;

            int left=i+1;
            int right=nums.length-1;
            while(left<right){ 
            int sum=nums[i]+nums[left]+nums[right];
            if(sum==0){
                //list.add(Arrays.asList(nums[i],nums[left],nums[right]));
                  list.add(nums[i]);
                  list.add(nums[left]);
                  list.add(nums[right]);
             
               while(left<right && nums[left]==nums[left+1]){
                left++;
              }
               while(left<right && nums[right]==nums[right-1]){
                right--;
               }
               left++;
               right--; 
            }else if(sum<0){
                left++;
            }else {
                right--;
            }
        }
    }
     return list;
}
}

4.四数之和(LeetCode 18)

https://leetcode.cn/problems/4sum/description/

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abc 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

四数之和和上面的三数之和解法基本一致,只是多了一层for循环,本质还是利用双指针找到最后的两个数。

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {

        List<List<Integer>> ans = new ArrayList();

        // 边界情况判断
        if (nums == null || nums.length < 4) {
            return ans;
        }

        Arrays.sort(nums);

        // 获取数组的长度
        int len = nums.length;

        // 开始遍历整个数组
        // 1、第一层循环
        // nums[i] 作为四个元素当中最小的那个元素
        // 需要留下 nums[len - 3] 、nums[len - 2] 、nums[len - 1] 这三个元素
        // 所以 i 的范围是 [ 0  , len - 4 ]
        for (int i = 0; i <= len - 4; i++) {

            // 答案中不可以包含重复的四元组,所以需要执行一个去重的操作
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            // 如果发现当前区间中,最小的四个元素之和都大于了 target
            // 此时,剩下的三个数无论取什么值,四数之和一定大于 target,可以直接退出第一层循环
            if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
                break;
            }
            
            // 如果发现当前区间中,选择最大的三个数和 nums[i] 相加都小于了 target
            // 说明此时剩下的三个数无论取什么值,四数之和一定小于 target
            // 因此第一层循环直接进入下一轮,即执行 i++
            if ((long) nums[i] + nums[len - 3] + nums[len - 2] + nums[len - 1] < target) {
                continue;
            }

            // 来到这里时,通过第一层循环,已经确定 nums[i] 这个数
            // 在 [ i + 1 , len - 1 ] 这个区间中寻找剩下的两个数
            // 2、第二层循环
            // nums[j] 作为四个元素当中第二小的那个元素
            // 需要留下 nums[len - 2] 、nums[len - 1] 这三个元素
            // 所以 j 的范围是 [ i + 1  , len - 3 ]
            for (int j = i + 1; j <= len - 3; j++) {

                // 答案中不可以包含重复的四元组,所以需要执行一个去重的操作
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }

                // 如果发现当前区间中,最小的四个元素之和都大于了 target
                // 此时,剩下的三个数无论取什么值,四数之和一定大于 target,可以直接退出第二层循环 
                if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
                    break;
                }

                // 如果发现当前区间中,选择最大的三个数和 nums[i] 相加都小于了 target
                // 说明此时剩下的三个数无论取什么值,四数之和一定小于 target
                // 因此第二层循环直接进入下一轮,即执行 j++
                if ((long) nums[i] + nums[j] + nums[len - 2] + nums[len - 1] < target) {
                    continue;
                }

                // 否则的话,开始去寻找剩下的两个数
                //  在 [ i + 1 , len - 2 ] 这个区间
                int left = j + 1 ;

                int right = len - 1;

                // left 和 right 不断的向内移动
                // 逻辑和三数之和的逻辑一样
                while (left < right) {

                    // 计算这四个元素之和
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];

                    // 发现四者之和为 0
                    if (sum == target) {
                        // 把这个结果记录一下
                        ans.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        while (left < right && nums[left] == nums[left + 1]) {
                            left++;
                        }

                        while (left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }

                        left++;
                        right--;

                    // 如果四者之和小于 0 ,那么说明需要找更大的数
                    } else if (sum < target) {
                        // left 向右移动
                        left++;

                    // 如果四者之和大于 0 ,那么说明需要找更小的数
                    } else {
                        // right 向左移动
                        right--;
                    }
                }
            }
        }
        return ans;
    }
}

5.x 的平方根(LeetCode 69)

https://leetcode.cn/problems/sqrtx/description/

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:

输入:x = 4
输出:2

示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

class Solution {
    public int mySqrt(int x) {
        int left=0;
        int right=x;

        while(left<=right){
            int mid=left+(right-left)/2;
            
            if((long)mid*mid==x){
                return mid;
            }else if((long)mid*mid<x){
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        return right;
    }
}

6.总结

共同点和解题技巧:

1.排序和双指针:许多问题使用排序结合双指针技术来优化时间复杂度(如三数之和和四数之和)。

2.去重:在处理组合或子集问题时,常需要通过去重来避免重复结果。

3.二分查找:对某些范围的搜索问题,可以使用二分查找来提高效率。

4.边界情况:处理特殊边界情况(如数组为空、单个元素、特定条件下的快速解答)是很重要的。

5.预处理:有时候需要对数据进行预处理(如字符串的转换、过滤)以简化后续操作。

题目回顾:

1. 寻找重复数(LeetCode 287)
题目描述:给定一个包含 (n+1) 个整数的数组,其中每个整数都在 1 到 (n) 之间,找出数组中的重复数。
解题技巧:
二分查找:将问题转换为寻找一个数满足某种条件的问题。
快慢指针(Floyd 判圈算法):通过快慢指针的方式检测循环中的重复元素。
实现思路:
快慢指针:通过设置两个指针,一个快指针和一个慢指针,找出数组中存在的循环,找到重复的数。

2. 验证回文串(LeetCode 125)
题目描述:给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,并忽略大小写。
解题技巧:
双指针:使用两个指针从字符串的两端向中间移动进行比较。
预处理:将字符串转换为统一格式(小写或大写),并移除非字母数字字符。
实现思路:
使用双指针从字符串两端向中间移动,检查字符是否相等。

3. 三数之和(LeetCode 15)
题目描述:在一个整数数组中找出所有和为零的三元组。
解题技巧:
排序+双指针:先对数组进行排序,然后使用双指针技术查找符合条件的三元组。
去重:避免重复的三元组出现。
实现思路:
排序数组,然后固定一个数,使用双指针在剩下的部分查找其他两个数。

4. 四数之和(LeetCode 18)
题目描述:在一个整数数组中找出所有和为目标值的四元组。
解题技巧:
排序+双指针:先对数组进行排序,然后用两层循环固定两个数,再使用双指针查找另外两个数。
去重:避免重复的四元组出现。
实现思路:
排序数组,使用两层循环固定前两个数,使用双指针查找另外两个数。

5. x 的平方根(LeetCode 69)
题目描述:
计算非负整数 (x) 的平方根的整数部分。
解题技巧:
二分查找:在区间 [0, x] 中寻找平方根。
边界情况处理:考虑特殊情况,比如 (x = 0) 和 (x = 1)。
实现思路:
使用二分查找在区间 [0, x] 中寻找整数平方根。
 

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

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

相关文章

Unity 麦扣 x 勇士传说 全解析 之 怪物基类与野猪(附各模块知识的链接,零基础也包学会的牢弟)(案例难度:★★☆☆☆)

通过一阵子的学习&#xff0c;我是这么认为的&#xff0c;因为该教程是难度两星的教程 &#xff0c;也就是适合学了一阵子基础组件以后的学习者 &#xff08;什么都不会的学习者要是学这套课程会困难重重&#xff0c;如果你什么都不会那么需要学习一星教程&#xff09; 所以该…

基于asp.net的webform框架的校园点餐系统源码

今天给大家分享一套基于asp.net的webform框架的网页点餐系统&#xff0c;适合课程设计参考及其自己学习&#xff0c;需要的小伙伴自己参考下&#xff0c;下载链接我放在后面了 主要功功能 系统的主要功能包含&#xff1a;前端点餐页面、加入购物车、商品食物浏览、我的购 物车…

ffmpeg开发者视频剪辑器

5G 时代的来临&#xff0c;加速了视频类作品的创作&#xff0c;由于现在的流量越来越便宜&#xff0c;网速越来越快&#xff0c;特别是流量无限用套餐&#xff0c;大家更愿意去看视频作品&#xff0c;特别是抖音的兴起&#xff0c;更是加速了小视频的流量。不会剪辑的我们该如何…

windows安装android studio

下载 https://developer.android.google.cn/studio?hlzh-cn 安装 打开cmd输入如下命令 android-studio-2024.1.1.12-windows.exe /NCRC 注意 运行命令后可能还报错&#xff0c;但是会出现弹窗 如果还是报错可以选择zip 运行 不设置代理 等待下载即可&#xff0c;…

SAP LE学习笔记04 - MM与WM跨模块收货到仓库的流程中 如何既创建TR又同时立即在前台创建TO

上一章讲了在MM模块的IM(在库管理)中收货到仓库的流程,以及关联WM移动Type与IM移动Type。 SAP LE学习笔记03 - 在IM(在库管理)中收货到仓库的流程&#xff0c;关联 WM移动Type与IM移动Type-CSDN博客 本章继续将LE的其他知识。 - MM与WM跨模块收货到仓库的流程中&#xff0c;如…

深入探索Amazon EC2:解锁云端计算的无限可能

欢迎来到本次的实验教程&#xff0c;这将引导您在功能强大且充满活力的 Amazon Web Services (AWS) 云中启动并配置虚拟机。 在本次实验中&#xff0c;您将亲身体验如何利用 Amazon 机器映像 (AMI) 启动 Amazon EC2 实例&#xff0c;并掌握使用密钥对进行 SSH 认证登录实例的技…

第18 章探讨 C++新标准.可变参数模板,模板和函数参数包,展开参数包

第18 章探讨 C新标准.可变参数模板,模板和函数参数包,展开参数包 第18 章探讨 C新标准.可变参数模板,模板和函数参数包,展开参数包 文章目录 第18 章探讨 C新标准.可变参数模板,模板和函数参数包,展开参数包18.6 可变参数模板18.6.1 模板和函数参数包18.6.2 展开参数包18.6.3 …

Bootstrap个人技术博客响应式网页模板

Bootstrap个人技术博客响应式模板基于Bootstrap3.3.5制作&#xff0c;自适应分辨率&#xff0c;兼容PC端和移动端&#xff0c;全套模板&#xff0c;包括首页、关于、网页配色、内容页、友情链接、读者墙、标签云、点赞等网站模板页面。模板下载地址http://m.bokequ.com/moban/1…

我在高职教STM32——I2C通信之SHT20传感器(2)

大家好,我是老耿,高职青椒一枚,一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次,同行应该都懂的,老师在课堂上教学几乎是没什么成就感的。正是如此,才有了借助CSDN平台寻求认同感和成就感的想法。在这里,我准备陆续把自己花了很多心思设计的教学课件分…

ubuntu基于sealos搭建k8s集群,helm3安装配置自动化扩容Prometheus,grafana出图展示,以及动态web搭建

1.项目简介 大方向&#xff1a;k8s云原生方向&#xff0c;运维技术&#xff0c;配置问题解决 解决技术:ubuntu模板机安装&#xff0c;配置远程xshell连接ubuntu&#xff0c;设置静态ip&#xff0c;换ubuntu阿里云源&#xff0c;配置集群间域名解析&#xff0c;解决双IP冲突网…

I2C的10-bit地址空间

10-bit地址空间&#xff1a; I2C支持 10-bit的设备地址&#xff0c;此时的时序如下图所示&#xff1a; 在 10-bit地址的 I2C系统中&#xff0c;需要两个帧来传输 slave的地址。第一个帧的前 5个 bit固定为 b11110&#xff0c;后接 slave地址的高 2位&#xff0c;第 8位仍然是 …

牛客面经学习笔记(四)

这种拨码开关在PLC里面很是常用&#xff1a; 这种弧型线就很漂亮&#xff1a; 这个白色按键很漂亮&#xff1a; 快恢复保险丝&#xff1a; 继电器电路&#xff1a; 这里的续流二极管很重要&#xff0c;因为继电器是感性元件&#xff1a; 【【必考】5招搞清楚&#xff01;单点接…

关于pytorch后续学习需要下载的包太慢怎么办?tensorboard为例

启发&#xff1a; anaconda python3.7安装TensorFlow 1.9.0&#xff08;CPU版&#xff09; 和这个佬的 我是CPU版本&#xff08;好像是需要找anaconda对应版本&#xff0c;我不知道咋找版本&#xff0c;不知道不同版本的对应关系&#xff09; 此时&#xff0c;我们可以浅浅pip…

民航网上订票系统设计和实现--论文pf

TOC springboot427民航网上订票系统设计和实现--论文pf 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和…

【系统分析师】-综合知识-系统架构

1、设计模式 1&#xff09;观察者模式定义了对象间的一种一对多依赖关系&#xff0c;使得每当一个对象改变状态&#xff0c;则所有依赖于它的对象都会得到通知并被自动更新【消息订阅】。在该模式中&#xff0c;发生改变的对象称为观察目标&#xff0c;被通知的对象称为观察者&…

泰坦尼克号 - 从灾难中学习机器学习/Titanic - Machine Learning from Disaster(kaggle竞赛)第二集(加载数据)

此次目的&#xff1a; hello大家好&#xff0c;俺是没事爱瞎捣鼓又分享欲爆棚的叶同学&#xff01;&#xff01;&#xff01;准备出几期博客来记录我学习kaggle数据科学入门竞赛的过程&#xff0c;顺便也将其中所学习到的知识分享出来。这是第一集&#xff08;了解赛题&#x…

Ansible可视化管理之web界面集成使用探究(未完待续)

一、前言 因某集成商管理的客户资源涉及4A接入管控要求&#xff0c;其中密码必须3个月更新一次&#xff0c;随着纳管主机的数量增多&#xff0c;手动去修改密码变得不现实&#xff0c;考虑无侵入性和资源耗用&#xff0c;便捷性等因素&#xff0c;首先选用Ansible作为此需求的…

武汉君耐营销策划有限公司员工信息管理系统pf

TOC springboot428武汉君耐营销策划有限公司员工信息管理系统pf 第1章 绪论 1.1 研究背景 互联网概念的产生到如今的蓬勃发展&#xff0c;用了短短的几十年时间就风靡全球&#xff0c;使得全球各个行业都进行了互联网的改造升级&#xff0c;标志着互联网浪潮的来临。在这个…

【Harmony OS 4.0】待办列表案例

src/main/ets/example1/Models.ets // 定义class类数据模型 export class TaskDataModel {// private 私有属性&#xff0c;在类对象外不允许随意更改数据&#xff0c;必须本地初始化。private tasks: Array<string> [早起晨练, 准备早餐, 阅读名著, 学习ArkTs, 玩游戏…

答题情况和每题得分

文章目录 1.提交答题情况1.PracticeDetailController.java2.PracticeDetailService.java3.PracticeDetailServiceImpl.java4.PracticeDetailDao.java5.PracticeDetailDao.xml6.reqSubmitSubjectDetailReq.java 7.dto1.SubjectDetailDTO.java2.SubjectDTO.java3.SubjectOptionDT…