【算法】双指针-OJ题详解1

双指针-OJ题

    • 移动零(点击跳转)
      • 原理讲解
      • 代码实现
    • 复写零(点击跳转)
      • 原理讲解
      • 代码实现
    • 快乐数(点击跳转)
      • 原理讲解
      • 代码实现
    • 盛最多水的容器(点击跳转)
      • 原理讲解
      • 代码实现
    • 有效三角形的个数(点击跳转)
      • 原理讲解
      • 代码实现
    • 查找总价值为目标值的两个商品(点击跳转)
      • 原理讲解
      • 代码实现
    • 三数之和(点击跳转)
      • 原理讲解
      • 代码实现
    • 四数之和(点击跳转)
      • 原理讲解
      • 代码实现

移动零(点击跳转)

在这里插入图片描述

原理讲解

在这里插入图片描述在这里插入图片描述

因此我们定义两个指针:

  • cur:遍历数组
  • dest:已处理的区间内,最后一个非零元素的位置

这样就把数组划分成三块区间:
[0 , dest] 、[dest+1 , cur-1] 、[cur , size-1]
分别对应:
非零元素、零、待处理

具体操作:
cur遍历过程中

  • 遇到0元素
    cur++;
  • 遇到非0元素
    swap(dest+1,cur); //swap数组中下标为dest+1和cur的元素
    dest++;cur++;

代码实现

void moveZeroes(vector<int>& nums) {int dest = -1;int cur = 0;while (cur < nums.size()){if (nums[cur])swap(nums[++dest], nums[cur]);cur++;}
}

复写零(点击跳转)

在这里插入图片描述

原理讲解

这道题首先要想到从后向前遍历,因为如果从前向后遍历,会覆盖掉后面的值,较难操作,因此:
在这里插入图片描述在这里插入图片描述
第一步找到最后一个数,可以用快慢指针来实现:cur指针、dest指针。前者从前向后遍历,后者根据前者位置的值走1步或2步,具体如下:

  • 先判断cur位置的值
  • 若cur位置的值非0,dest向后移动一步;若cur位置的值为0,dest向后移动2步
  • 判断dest位置是否到了结束的位置
  • cur++

代码实现

void duplicateZeros(vector<int>& arr) {int dest = -1;int cur = 0;//找到最后一个数while (cur < arr.size()){if (arr[cur])dest++;elsedest += 2;if (dest >= arr.size() - 1)break;cur++;}
//处理特殊情况:cur指向的最后一个数是0,dest越界if (dest == arr.size()){arr[dest - 1] = 0;cur--;dest -= 2;}
//复写while (cur >= 0){if (arr[cur])arr[dest--] = arr[cur--];else{arr[dest--] = 0;arr[dest--] = 0;cur--;}}
}

快乐数(点击跳转)

在这里插入图片描述

原理讲解

在这里插入图片描述
最后一定会成环(可以证明,用鸽巢原理)
因此可以通过判断环的起点是否为1,决定返回true还是false

→ 快慢指针
快慢指针有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的,也就是说他们总会相遇在⼀个位置上。就本题而言,如果相遇位置的值是 1 ,那么这个数⼀定是快乐数;如果相遇位置不是 1 ,那么就不是快乐数。

代码实现

//求x每一位数的平方和int SqSum(int x){int ret = 0;while(x){int n = x%10;ret += n*n;x/=10;}return ret;}bool isHappy(int n) {int slow = n,fast = SqSum(n);//fast不能设成n,否则进不了循环while(slow != fast){slow = SqSum(slow);fast = SqSum(SqSum(fast));}return slow==1;}

盛最多水的容器(点击跳转)

在这里插入图片描述

原理讲解

我们首先想到的大概率是两层循环暴力枚举,但是复杂度高,这道题不能通关

那应该如何解这题呢?
首先,容器的容积(这道题只考虑面积)是S = h * w
h表示高度,即height[?]
w表示宽度,即两条垂线间隔的距离

为了方便叙述,我们假设左边边界height[left]小于右边边界height[right]

如果此时我们固定⼀个边界,改变另⼀个边界,水的容积会有如下变化形式:

  • 容器的宽度w一定变小。
  • 由于左边界较小,决定了水的高度。①如果改变左边界,新的水面高度不确定,但是一定不会超过右边的柱子高度,因此容器的容积可能会改变(可能变大、变小、不变)。
  • ②如果改变右边界,无论右边界移动到哪里,新的水面的高度一定不会超过左边界,也就是不会超过现在的水面高度,但由于容器的宽度减小,因此容器的容积⼀定会变小的。

所以我们可以舍去情况②,只需要讨论情况①(因为我们的目的是求最大的容积)

因此,我们定义两个指针left和right,然后比较height[left]height[right],移动height小的位置的指针,循环这个过程,期间产生的所有的容积里的最大值,就是要return的最终答案

代码实现

    int maxArea(vector<int>& height) {int left = 0;int right = height.size()-1;int _max = 0;while(left < right){int tmp = (right-left)*min(height[right],height[left]);_max = max(_max,tmp);if(height[left] < height[right])left++;elseright--; }return _max;}

有效三角形的个数(点击跳转)

在这里插入图片描述

原理讲解

我们小学五年级都学过,三角形的三条边必须满足:任意两边之和大于第三边、任意两边之差小于第三边~

假设三角形三条边长度分别为:a, b, c

  • 方法① a+b < c ; a+c < b ; b+c < a

  • 方法② 在①的基础上优化:先排序,a ≤ b ≤ c,只需要判断 a+b > c即可

解法一:三层循环暴力枚举 → O(n3)

解法二:利用(排序后)单调性,用双指针算法来解决。 → O(n2)

  • 先固定最大的数
  • 在最大数的左边区间内,用双指针算法,快速统计出符合要求的另外两个数:
    • 如果 nums[left] + nums[right] > nums[max],说明 [left, right - 1] 区间上的所有元素均可以与 nums[right] 构成比nums[max] 大的二元组,此时满足条件的有 right - left 种;此时 right 位置的元素的所有情况相当于全部考虑完毕, right-- ,进入下一轮判断
    • 如果 nums[left] + nums[right] <= nums[max],说明 left 位置的元素是不可能与 [left + 1, right] 位置上的任意元素构成满足条件的二元组,left++ 进入下一轮循环
  • 向左移动最大数,循环上面的过程

代码实现

    int triangleNumber(vector<int>& nums) {int left,right;int cmax = nums.size() - 1;int ret = 0;sort(nums.begin(),nums.end());while (cmax > 1) {left = 0;right = cmax-1;while (left < right) {if (nums[left] + nums[right] > nums[cmax]) {ret+=(right-left);right--;     } else {left++;}}cmax--;//向左移动最大数}return ret;}

查找总价值为目标值的两个商品(点击跳转)

在这里插入图片描述

原理讲解

类比上面《有效三角形的个数》,会发现利用单调性同样很香:利用对撞指针优化时间复杂度

  • 初始化 leftright 分别指向数组的左右两端
  • 接下来无非三种情况:
    • price[left] + price[right] == target,说明找到了,跳出循环返回即可
    • price[left] + price[right] > target,说明两数之和大了,right–
    • price[left] + price[right] < target,说明两数之和小了,left++

代码实现

    vector<int> twoSum(vector<int>& price, int target) {int left = 0,right = price.size()-1;vector<int> ret;while(left < right){if(price[left] + price[right] == target){ret.push_back(price[left]);ret.push_back(price[right]);break;}else if(price[left] + price[right] > target)right--;elseleft++;}return ret;}

或者不需创建vector直接返回:

    vector<int> twoSum(vector<int>& price, int target) {int left = 0,right = price.size()-1;while(left < right){if(price[left] + price[right] == target)return {price[left] , price[right]};else if(price[left] + price[right] > target)right--;elseleft++;}return {-1};//注意这里必须return一个数组,目的是照顾编译器,否则编译不通过}

三数之和(点击跳转)

在这里插入图片描述

原理讲解

我们可以利用在两数之和那道题的双指针思想,来对暴力枚举做优化:

  • 先排序
  • 然后固定一个数 a
  • 在这个数后面的区间内,利用双指针快速找到两个数之和等于 -a 即可

但是要注意的是,这道题需要有去重操作~
(除了用set,我们可以自己实现)

  • 找到一个结果之后, left 和 right 指针要跳过重复的元素;
  • 当用完⼀次双指针算法之后,固定的 a 也要跳过重复的元素。

代码实现

    vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(),nums.end());int i =0,left,right;vector<vector<int>> vv;while(i < nums.size()-2){if(nums[i] > 0)break;//left+rightleft = i+1;right = nums.size()-1;while(left < right && right < nums.size()){if(nums[left] + nums[right] == -nums[i]){vv.push_back({nums[i],nums[left],nums[right]});left++;right--;while(left < right && right < nums.size()&&nums[left] == nums[left-1])left++;//left跳过重复元素while(left < right && right < nums.size()&&nums[right] == nums[right+1])right--;//right跳过重复元素}else if(nums[left] + nums[right] > -nums[i])right--;elseleft++;}i++;while(nums[i] == nums[i-1] && i<nums.size()-2)++i;//“固定”的数跳过重复元素}return vv;  }

四数之和(点击跳转)

在这里插入图片描述

原理讲解

这道题和上面的《三数之和》几乎一模一样,区别在于多了一层

  • 固定一个数a
  • 在这个数 a 的后面区间上,利用「三数之和」找到三个数,使这三个数的和等于 target - a 即可

代码实现

    vector<vector<int>> fourSum(vector<int>& nums, int target) {sort(nums.begin(),nums.end());vector<vector<int>> vv;int i=0,j,left,right;while(i<nums.size()){j = i+1;while(j<nums.size()){left = j+1;right = nums.size()-1;long long aim =  (long long)target-nums[i]-nums[j];//有些用例不强转会越界while(left<right){int sum =nums[left]+nums[right];if(sum == aim){vv.push_back({nums[i],nums[j],nums[left],nums[right]});left++;right--;while(left<right && nums[left] == nums[left-1])left++;while(left<right && nums[right] == nums[right+1])right--;}else if(sum < aim)left++;elseright--;}++j;while(j < nums.size() && nums[j] == nums[j-1])++j;}++i;while(i<nums.size() && nums[i] == nums[i-1])++i;}return vv;}

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

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

相关文章

C语言自定义类型结构体与位段超详解

文章目录 1. 结构体类型的声明1. 1 结构体声明1. 2 结构体变量的创建和初始化1. 3 结构体的特殊声明1. 3 结构体的自引用 2. 结构体内存对齐2. 1 对齐规则2. 2 为什么存在内存对齐2. 3 修改默认对齐数 3. 结构体传参4. 结构体实现位段4. 1 什么是位段4. 2 位段成员的内存分配4.…

吴恩达老师机器学习作业-ex7

导入库&#xff0c;读取数据&#xff0c;查看数据类型等进行分析&#xff0c;可视化数据 import matplotlib.pyplot as plt import numpy as np import scipy.io as sio#读取数据 path "./ex7data2.mat" data sio.loadmat(path) # print(type(data)) # print(data…

Java | Leetcode Java题解之第316题去除重复字母

题目&#xff1a; 题解&#xff1a; class Solution {public String removeDuplicateLetters(String s) {boolean[] vis new boolean[26];int[] num new int[26];for (int i 0; i < s.length(); i) {num[s.charAt(i) - a];}StringBuffer sb new StringBuffer();for (in…

nginx续1:

八、虚拟主机配置 基于域名的虚拟主机 [rootserver2 ~]# ps -au|grep nginx //查看进程 修改Nginx服务配置&#xff0c;添加相关虚拟主机配置如下 1. [rootproxy ~]# vim /usr/local/nginx/conf/nginx.conf 2. .. .. 3. server { 4. listen …

第15课 Scratch少儿编程 入门篇:师生问候

师生问候 故事背景&#xff1a; 魔法学院的期末考核刚刚考完&#xff0c;魔法老师在教室里碰到小明&#xff0c;老师问小明考的怎么样&#xff1f; 程序原理&#xff1a; 找一个教室的背景&#xff0c;小精灵角色和魔法师的角色&#xff0c;将魔法师的角色造型左右反转&…

MyBatis 源码学习 | Day 1 | 了解 MyBatis

什么是 MyBatis 在对一项技术进行深入学习前&#xff0c;我们应该先对它有个初步的认识。MyBatis 是一个 Java 持久层框架&#xff0c;用于简化数据库的操作。它通过 XML 或注解的方式配置和映射原始类型、接口和 Java POJO&#xff08;Plain Old Java Objects&#xff0c;普通…

如何理解复信号z的傅里叶变换在频率v<0的时候恒为0,是解析信号

考虑例子2.12.1的说法。 首先我尝试解释第二个说法。需要注意一个事实是 实函数f的傅里叶变换F的实部是偶函数&#xff0c;虚部是奇函数。如图所示&#xff1a; 注意的是这个图中虽然是离散傅里叶变换的性质&#xff0c;但是对于一般的傅里叶变换的性质是适用的。 推导过程如下…

5款免费写作生成软件,自动生成原创文章很简单

在人工智能时代的今天&#xff0c;创作者面对写作不再是一件令人望而生畏的事情。随着AI技术的不断发展&#xff0c;涌现出了许多优秀的免费写作生成软件&#xff0c;让自动生成原创文章变得轻松简单。以下为大家详细介绍5款备受赞誉的免费写作生成软件&#xff0c;下面跟随小编…

深度学习DeepLearning Inference 学习笔记

神经网络预测 术语 隐藏层神经元多层感知器 神经网络概述 应当选择正确的隐藏层数和每层隐藏神经元的数量&#xff0c;以达到这一层的输出是下一层的输入&#xff0c;逐层变得清晰&#xff0c;最终输出数据的目的。 在人脸识别的应用中&#xff0c;我们将图片视作连续的像…

pytest测试框架之http协议接口测试

1 接口测试 日常测试中接口测试是一项重要的工作&#xff0c;尤其是http协议的接口测试更加普遍,比如一些常用的测试框架或者工具&#xff08;robotframework框架&#xff0c;testng框架&#xff0c;postman等&#xff09;都支持http接口的测试&#xff0c;而这节内容主要介绍…

【PythonCode】力扣Leetcode36~40题Python版

【PythonCode】力扣Leetcode36~40题Python版 前言 力扣Leetcode是一个集学习、刷题、竞赛等功能于一体的编程学习平台&#xff0c;很多计算机相关专业的学生、编程自学者、IT从业者在上面学习和刷题。 在Leetcode上刷题&#xff0c;可以选择各种主流的编程语言&#xff0c;如C…

使用 Python 确保结构在被释放后被垃圾回收

在 Python 中&#xff0c;确保对象在不再使用时被垃圾回收是很重要的。Python 的垃圾回收机制基于引用计数&#xff0c;并配有一个循环垃圾回收器&#xff0c;以处理引用循环。 以下就是一些确保对象被正确垃圾回收的技巧和方法&#xff1a; 1、问题背景 在 Python 中&#x…

“八股文”:程序员的福音还是梦魇?

——一场关于面试题的“代码战争” 在程序员的世界里&#xff0c;“八股文”这个词儿可谓是“如雷贯耳”。不&#xff0c;咱们可不是说古代科举考试中的那种八股文&#xff0c;而是指程序员面试中的那些固定套路的题目。如今&#xff0c;各大中小企业在招聘程序员时&#xff0…

59在Linux中加docker中加mysql,tomcat,redis

一、引言 1.1 环境不一致 我本地运行没问题啊&#xff1a;由于环境不一致&#xff0c;导致相同的程序&#xff0c;运行结果却不一致。 1.2 隔离性 哪个哥们又写死循环了&#xff0c;怎么这么卡&#xff1a;在多用户的操作系统下&#xff0c;会因为其他用户的操作失误影响到你自…

Logistic回归

Logistic回归模型&#xff1a; 适用于二分类或多分类问题&#xff0c;样本特征是数值型&#xff08;否则需要转换为数值型&#xff09; 策略&#xff1a;极大似然估计 算法&#xff1a;随机梯度 或 BFGS算法&#xff08;改进的拟牛顿法&#xff09; 线性回归表达式&#xf…

队列的基本运算(顺序,环形,链式)

以下分别介绍了顺序队列&#xff0c;环形队列&#xff0c;链式队列的基本运算。主要有五种基本运算&#xff1a;1.初始化队列&#xff0c;2.销毁队列&#xff0c;3.判断队列是否为空&#xff0c;4.进队列&#xff0c;5.出队。 目录 顺序队列 环形队列 链式队列 顺序队列与环…

upload-labs靶场练习

文件上传函数的常见函数&#xff1a; 在PHP中&#xff0c;‌文件上传涉及的主要函数包括move_uploaded_file(), is_uploaded_file(), get_file_extension(), 和 mkdir()。‌这些函数共同协作&#xff0c;‌使得用户可以通过HTTP POST方法上传文件&#xff0c;‌并在服务器上保存…

pycharm安装与配置Pyqt5

pycharm安装与配置Pyqt5 1、创建项目、虚拟环境 打开pycharm&#xff0c;File->New Project 2、安装pyqt5库 在pycharm下方Terminal终端窗口输入&#xff1a; pip install PyQt5 -i https://pypi.douban.com/simple pip install PyQt5-tools -i https://pypi.douban.c…

模拟实现strcmp,判断二个字符串是否相等

1.判断二个字符串是否相等&#xff0c;可以模仿strcmp.当二个字符串相等的时候ruturn 0.,当二个字符串小于时返回为小于0&#xff0c;当二个字符串大于时返回为大于0。const为不可以更改。 //方法一 int my_strcmp(const char* arr1, const char* arr2) {assert(arr1 &&…

CFA FRM原創講義和視頻等備考全部資料內容,順便征求建議

大家好&#xff0c;我是小伯&#xff0c; 曾經我也很喜歡上這個壇子查資料&#xff0c;好多年過去&#xff0c;現在論壇蠻雕零的很感慨。我和幾個朋友原創作了一些CFA一級二級三級和FRM一級二級雙語中英文的課件、視頻、資料&#xff0c; 是我們從2024年起一起合作的一個以自學…