【算法】【优选算法】双指针(下)

目录

  • 一、611.有效三⻆形的个数
    • 1.1 左右指针解法
    • 1.2 暴力解法
  • 二、LCR 179.查找总价格为目标值的两个商品
    • 2.1 左右指针解法
    • 2.2 暴力解法
  • 三、15.三数之和
    • 3.1 左右指针解法
    • 3.2 暴力解法
  • 四、18.四数之和
    • 4.1 左右指针解法
    • 4.2 暴力解法

一、611.有效三⻆形的个数

题目链接:611.有效三⻆形的个数
题目描述:

题目解析:

  • 返回能够成三角形的三元组合的个数;
  • 三元组合内容相同,但是是原数组中不同的下标的元素,这样的三元组在这道题中是不相同的,要计数。

1.1 左右指针解法

解题思路:

  • 因为我们能构成三角形的证明是两条最小边的和大于最大边,所以我们先将数组排序。
  • 排序后,我们只需要固定一条边,然后使用左右指针在[0, 最大边)区间中去搜索符合条件的边即可。
  • 固定的一条边必须是最大边,因为固定最大边的时候,要让另两边之和变大和变小只有一种走法(即变大左指针向后,变小右指针向前),如果固定最小边,让两边之差变小有两种走法(变小左指针向后和右指针向前都行)。
  • 当左右指针元素和小于最大边,我们只需要将左指针向后走,让元素和更大即可。
  • 当左右指针元素和大于最大边,现在[左指针,右指针) 中的元素和右指针的元素都可以构成三角形了。直接将其中元素个数添加到ret结果中,然后让右指针向前走,让元素和减小即可。

解题代码:

//时间复杂度O(n^2)
//空间复杂度O(logn)
import java.util.*;
class Solution {public int triangleNumber(int[] nums) {Arrays.sort(nums);int ret = 0;for(int i = nums.length - 1; i > 0; i--) {int left = 0;int right = i - 1;while(left < right) {if(nums[right] + nums[left] > nums[i]) {ret += right - left;right--;} else {left++;}}}return ret;}
}

1.2 暴力解法

解题思路:
直接使用三次for循环,将每一种构成三角形的可能都枚举出来,然后一一判断是否符合构成三角形的条件即可。但是这种方法时间复杂度过大,会超时。

解题代码:

//时间复杂度O(n^3)
//空间复杂度O(1)
import java.util.*;
class Solution {public int triangleNumber(int[] nums) {int ret = 0;int n = nums.length;for(int i = 0; i < n; i++) {for(int j = i +1 ; j < n; j++) {for(int k = j+1; k < n; k++) {if(nums[i] + nums[j] + nums[k] > 2 * Math.max(nums[i],Math.max(nums[j],nums[k]))) {ret++;}}}}return ret;}
}

二、LCR 179.查找总价格为目标值的两个商品

题目链接:LCR 179.查找总价格为目标值的两个商品
题目描述:

题目解析:

  • 数组是有序的,只需要找到一组数组中下标不同的两个数的和为target的返回该组合即可。

2.1 左右指针解法

解题思路:

  • 因为数组是有序的,我们可以利用两数的和的单调性来解题。
  • 我们初始左指针指向第一个元素,右指针指向最后一个元素。两个元素的和的单调性具有规律,让和变大让左指针向后移动,让和变小让右指针向前。

解题代码:

//时间复杂度O(n)
//空间复杂度O(1)
import java.util.*;
class Solution {public int[] twoSum(int[] price, int target) {int left = 0, right = price.length-1; while(left < right) {if(price[left] + price[right] > target) right--;else if(price[left] + price[right] < target) left++;else return new int[]{price[left],price[right]};}return null;}
}

2.2 暴力解法

解题思路:

  • 我们直接使用两层for循环将不同的下标的两个元素的和枚举出来比较即可。
  • 但是时间复杂度过大,会超出时间限制。
    解题代码:
//时间复杂度O(n^2)
//空间复杂度O(1)
import java.util.*;
class Solution {public int[] twoSum(int[] price, int target) {for(int i = 0; i < price.length; i++) {for(int j = 0; j < price.length; j++) {if(price[i] + price[j] == target) {return new int[]{price[i],price[j]};}}}return null;   }
}

三、15.三数之和

题目链接:15.三数之和
题目描述:

题目解析:

  • 数组中三个元素和为0,并且要求其中的元素不能重合,对三元组中先后顺序也没有要求。

3.1 左右指针解法

解题思路:

  • 当我们固定了一个数之后,是不是就是求另两个数的和等于这个固定的数的相反值,这就跟上一道题的思路差不多了,其实也跟第一题三角形思路也相似。
  • 这道题给我们的数组是无序的,这样我们固定一个数之后,我们来求另两个数和时,单调性的控制就不是唯一的,所以我们要将数组排序。
  • 我们使用一个for-i循环先固定一个数,然后使用左右指针在[i+1,nums.length-1] 区间中去三数之和等于0的数,然后将三元组放进结果集,并且左右指针同时移动一步;比0小就左指针向后走让和变大;比0大就右指针向前走。
  • 去重思路:
    • 思路一:
      • 在判断元素和前去重,由于我们数组是有序的,那么相同数值的元素肯定是在一起的,那么我们只要判断移动后的元素与前一步每移动时的值是否相同即可,当相同再次移动到不同即可。
      • 但是这里面有细节问题:当我们使用这样的方法的时候,我们是直接将所有相同的直接跳过,所以我们有可能跳过初始值(也就是i == 0 left == i+1 right == nums.length-1),就如数组是这样[2, 2, 3 ,2],当i = 0 时会跳过直接到第三个元素。所有在while循环条件要加上判断是初始值的条件
      • 还有越界风险:所以在while判断的循环中还要将越界风险排除。
      • 还有我们不知道出判断循环的原因是上面是哪个原因哪一个,所以我们在出来判断循环之后,还要判断是否已经越界或者不符合条件,也就是i >= nums.length 和 left >= right。
    • 思路二:
      • 我们在判断和之后去重,只需要考虑越界风险,和相等即可。但是由于在判断和之中,我们要先将i++ 再去去重,去重后已经到了下一个要进循环的元素了, 所以我们for循环中就不要i++了。
  • 小优化:在这道题中是判断和为0,所以我们当nums[i] > 0,后续[i+1,nums.length-1]空间都是正数,不可能还有结果了,直接出循环。

解题代码

//时间复杂度O(n^2)
//空间复杂度O(logn)
写法一:
import java.util.*;
class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> ret = new ArrayList<>();Arrays.sort(nums);int len = nums.length;for(int i = 0; i < len; i++) {if(nums[i] > 0) break;//对i去重while(i != 0 && i < len && nums[i] == nums[i - 1]) i++;if(i >= len) break;int left = i + 1;int right = len - 1;while(left < right) {while(left < right && left != i+1 && nums[left] == nums[left-1]) left++;//对left去重while(left < right && right != len-1 && nums[right] == nums[right+1]) right--;//对right去重if(left >= right) break;if(nums[left] + nums[right] < -nums[i]) left++;else if(nums[left] + nums[right] > -nums[i]) right--; else ret.add(Arrays.asList(nums[i],nums[left++],nums[right--]));}}return ret;}
}写法二:
import java.util.*;
class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> ret = new ArrayList<>();Arrays.sort(nums);int len = nums.length;for(int i = 0; i < len; ) {if(nums[i] > 0) break;int left = i + 1;int right = len - 1;while(left < right) {if(nums[left] + nums[right] < -nums[i]) left++;else if(nums[left] + nums[right] > -nums[i]) right--; else { ret.add(Arrays.asList(nums[i],nums[left++],nums[right--]));while(left < right && nums[left] == nums[left-1]) left++;//对left去重while(left < right && nums[right] == nums[right+1]) right--;//对right去重}}//对i去重i++;while(i < len && nums[i] == nums[i - 1]) i++;}return ret;}
}

3.2 暴力解法

解题思路:

  • 我们直接使用三层for循环将每一个三元组枚举出来即可。
  • 去重时我们直接使用HashSet这个集合类即可,所以我们要先将nums排序。
  • 但是会超时。
    解题代码:
//时间复杂度O(n^3)
//空间复杂度O(logn)
import java.util.*;
class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> ret = new ArrayList<>();Set<List<Integer>> set = new HashSet<>();int len = nums.length;for(int i = 0; i < len; i++) {for(int j = i+1; j < len; j++) {for(int k = j+1; k < len; k++) {if(nums[i] + nums[j] + nums[k] == 0) {set.add(Arrays.asList(nums[i],nums[j],nums[k]));}}}}ret.addAll(set);return ret;}
}

四、18.四数之和

题目链接:18.四数之和
题目描述:

题目分析:
跟上面的三数之和,思路一样,代码雷同,只是需要固定两个数即可。

4.1 左右指针解法

解题思路:

  • 思路参考上一道三数之和,两个细节:
  • 这道题有例子是会超过int的最大值的,所以我们需要在计算和的时候使用long来储存。

    解题代码:
//时间复杂度O(n^3)
//空间复杂度O(logn)
写法一:
import java.util.*;
class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {Arrays.sort(nums);List<List<Integer>> ret = new ArrayList<>();int len = nums.length;for(int i = 0; i < len; i++) {//对i去重while(i < len && i != 0 && nums[i] == nums[i-1]) i++;if(i >= len ) break;for(int j = i+1; j < len; j++) {//对j去重while(j < len && j != i+1 && nums[j] == nums[j-1]) j++;if(j >= len ) break;long newTarget = (long)target - nums[i] - nums[j];int left = j + 1;int right = len - 1;while(left < right) {while(left < right && left != j+1 && nums[left] == nums[left-1]) left++;//对left去重while(left < right && right != len-1 && nums[right] == nums[right+1]) right--;//对right去重if(left >= right) break;long sum = (long)nums[left] + nums[right];if(sum > newTarget) right--;else if(sum < newTarget) left++;else ret.add(Arrays.asList(nums[i],nums[j],nums[left++],nums[right--]));}}}return ret;}
}
写法二:
import java.util.*;
class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {Arrays.sort(nums);List<List<Integer>> ret = new ArrayList<>();int len = nums.length;for(int i = 0; i < len;) {for(int j = i+1; j < len;) {long newTarget = (long)target - nums[i] - nums[j];int left = j + 1;int right = len - 1;while(left < right) {long sum = (long)nums[left] + nums[right];if(sum > newTarget) right--;else if(sum < newTarget) left++;else {ret.add(Arrays.asList(nums[i],nums[j],nums[left++],nums[right--]));while(left < right && nums[left] == nums[left-1]) left++;//对left去重while(left < right && nums[right] == nums[right+1]) right--;//对right去重}}//对j去重j++;while(j < len && nums[j] == nums[j-1]) j++;}i++;//对i去重while(i < len && nums[i] == nums[i-1]) i++;}return ret;}
}

4.2 暴力解法

解题思路:

  • 4层for循环,HashSet去重。
  • 会超时。

解题代码:

//时间复杂度O(n^4)
//空间复杂度O(logn)
import java.util.*;
class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {Arrays.sort(nums);List<List<Integer>> ret = new ArrayList<>();Set<List<Integer>> set = new HashSet<>();int len = nums.length;for(int i = 0; i < len; i++) {for(int j = i+1; j < len; j++) {for(int k = j+1; k < len; k++) {for(int n = k+1; n < len; n++){if((long)nums[i] + nums[j] + nums[k] + nums[n] == target) {set.add(Arrays.asList(nums[i],nums[j],nums[k],nums[n]));}}}}}ret.addAll(set);return ret;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker 镜像体积优化实践:从基础镜像重建到层压缩的全流程指南

​ 由于最近在发布的时候发现docker镜像体积变得越来越大&#xff0c;导致整个打包发布流程变得非常耗时了。所以又接到一个差事&#xff0c;优化最终镜像体积。顺便也记录一下docker镜像体积优化的一些步骤。 大概步骤可以分为以下几个步骤&#xff1a; 重做基础镜像&#x…

路径规划 | ROS中多个路径规划算法可视化与性能对比分析

目录 0 专栏介绍1 引言2 禁用局部规划器3 路径规划定性对比实验3.1 加载路径规划器和可视化插件3.2 设置起点和终点3.3 选择规划器规划3.4 不同规划器对比3.5 路径保存和加载 4 路径规划定量对比实验4.1 计算规划耗时4.2 计算规划长度4.3 计算拓展节点数4.4 计算路径曲率4.5 计…

十四届蓝桥杯STEMA考试Python真题试卷第二套第五题

来源:十四届蓝桥杯STEMA考试Python真题试卷第二套编程第五题 本题属于迷宫类问题,适合用DFS算法解决,解析中给出了Python中 map() 和列表推导式的应用技巧。最后介绍了DFS算法的两种常见实现方式——递归实现、栈实现,应用场景——迷宫类问题、图的连通性、树的遍历、拓朴排…

【CSS】——基础入门常见操作

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;CSS引入 二&#xff1a;CSS对元素进行美化 1&#xff1a;style修饰 2&#xff1a;选…

RV1126-SDK学习之OSD实现原理

RV1126-SDK学习之OSD实现原理 前言 本文简单记录一下我在学习RV1126的SDK当中OSD绘制的原理的过程。 在学习OSD的过程当中&#xff0c;可能需要补充的基础知识&#xff1a; OSD是什么&#xff1f; BMP图像文件格式大致组成&#xff1f; 图像调色&#xff08;Palette&#…

Vehicle OS软件平台解决方案

在智能汽车快速迭代的趋势之下&#xff0c;广义操作系统Vehicle OS应运而生&#xff0c;针对应用软件开发周期缩短和底层硬件迭代速度加快的背景&#xff0c;Vehicle OS将应用软件开发和底层硬件迭代解耦。它降低了迭代工作量并节约成本&#xff0c;用标准化的接口来助力软件定…

Chromium Mojo(IPC)进程通信演示 c++(1)

网上搜索关于mojo教程 多数都是理论 加上翻译谷歌mojo文档的&#xff0c;但是如何自定义两个进程使用mojo通信呢&#xff1f;看下面的完整例子介绍&#xff1a;&#xff08;本人也是参考谷歌代码例子改编而成&#xff09; 本文演示了client.exe和service.exe 通过mojo::Incomin…

sparkSQL面试题

一、查询所有数学课程成绩大于语文课程成绩的学生学号 数据 1,yuwen,43 1,shuxue,55 2,yuwen,77 2,shuxue,88 3,yuwen,98 3,shuxue,65 3,yingyu,88 基本步骤&#xff1a; 进行行转列比较语文与数学的成绩 SQL代码&#xff1a; with t1 as(SELECT id,sum(if(name yuwen,sc…

算法|牛客网华为机试21-30C++

牛客网华为机试 上篇&#xff1a;算法|牛客网华为机试10-20C 文章目录 HJ21 简单密码HJ22 汽水瓶HJ23 删除字符串中出现次数最少的字符HJ24 合唱队HJ25 数据分类处理HJ26 字符串排序HJ27 查找兄弟单词HJ28 素数伴侣HJ29 字符串加解密HJ30 字符串合并处理 HJ21 简单密码 题目描…

浅谈QT中Tab键的切换逻辑

浅谈QT中Tab键的切换逻辑 无意中发现在输入界面中按下Tab键时&#xff0c;没有按照预想的顺序切换焦点事件&#xff0c;如下图所示 这个现象还是很有趣&#xff0c;仔细观察了下&#xff0c;默认的切换顺序是按照控件拖入顺序&#xff0c;那么知道了这个问题想要解决起来就很简…

科研绘图系列:R语言组合连线图和箱线图(linechart+boxplot)

文章目录 介绍加载R包数据数据预处理画图1画图2系统信息介绍 连线图(Line Chart)是一种常用的数据可视化图表,它通过将一系列数据点用直线段连接起来来展示数据随时间或有序类别变化的趋势。以下是连线图可以表示的一些内容: 时间序列数据:展示数据随时间变化的趋势,例如…

PKG_CHECK_MODULES(FUSE,fuse)

运行 ./configure 命令报错如下&#xff1a; ./configure: line 13934: syntax error near unexpected token FUSE,fuse ./configure: line 13934: PKG_CHECK_MODULES(FUSE,fuse)解决方案&#xff1a; 命令窗口运行如下命令&#xff0c;安装 pkg-config&#xff1a; sudo …

react18中redux-promise搭配redux-thunk完美简化异步数据操作

用过redux-thunk的应该知道&#xff0c;操作相对繁琐一点&#xff0c;dispatch本只可以出发plain object。redux-thunk让dispatch可以返回一个函数。而redux-promise在此基础上大大简化了操作。 实现效果 关键逻辑代码 store/index.js import { createStore, applyMiddlewar…

Lucene分析器的详细使用(5)

文章目录 第5章 分析器5.1 分析器的组成5.1.1 字符过滤器1&#xff09;HTMLStripCharFilter2&#xff09;PatternReplaceCharFilter3&#xff09;MappingCharFilter4&#xff09;Luke使用字符过滤器 5.1.2 分词器1&#xff09;StandardTokenzier2&#xff09;keywordTokenizer3…

selinux和防火墙

SElinux 1、selinux代表的什么&#xff1f; SELinux是Security-Enhanced Linux的缩写&#xff0c;意思是安全强化的linux。 SELinux 主要由美国国家安全局&#xff08;NSA&#xff09;开发&#xff0c;当初开发的目的是为了避免资源的误用。 SELinux是对程序、文件等权限设置依…

CentOS 7 安装 ntp,自动校准系统时间

1、安装 ntp yum install ntp 安装好后&#xff0c;ntp 会自动注册成为服务&#xff0c;服务名称为 ntpd 2、查看当前 ntpd 服务的状态 systemctl status ntpd 3、启动 ntpd 服务、查看 ntpd 服务的状态 systemctl start ntpdsystemctl status ntpd 4、设置 ntpd 服务开机启…

Oracle OCP认证考试考点详解082系列11

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 51. 第51题&#xff1a; 题目 51.View the Exhibit and examine the description of the tables You execute this SQL statement Whi…

C#属性 Property

属性Property不是变量。 它们是由名为访问器方法来实现的一种方法。 实例属性表示的是实例的某个数据&#xff0c;通过这个数据反映实例当前的状态 静态属性表示的是类型的某个数据&#xff0c;通过这个数据反映类型当前的状态 意义&#xff1a; 防止恶意赋值(通过属性间接访问…

Spring框架的事务管理

目录 一、spring框架事务管理相关的类 1.PlatformTransactionManager接口 2.TransactionDefinition接口 二、spring框架声明式事务管理 1.配置文件的方式 &#xff08;1&#xff09;配置文件 &#xff08;2&#xff09;业务层 &#xff08;3&#xff09;持久层 &#…

angular实现list列表和翻页效果

说明&#xff1a;angular实现list列表和翻页效果 上一页 当前页面 下一页 效果图&#xff1a; step1: E:\projectgood\ajnine\untitled4\src\app\car\car.component.css .example-form-fields {display: flex;align-items: flex-start; }mat-list-item{background: antiquew…