双指针法(leetcode分类解题,C++代码详细注释)

双指针法

  • 前言
  • 167.两数之和 II - 输入有序数组
  • 88.合并两个有序数组
  • 142. 环形链表 II
  • 633.平方数之和
  • 680. 验证回文字符串 Ⅱ
  • 27. 移除元素
  • 344. 反转字符串
  • 剑指 Offer 05. 替换空格
  • 151. 翻转字符串里的单词
  • 206.反转链表
  • 125. 验证回文串
  • 19. 删除链表的倒数第 N 个结点
  • 面试题 02.02. 返回倒数第 k 个节点

前言

双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延伸到多个数组的多个指针。

若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域即为当前的窗口),经常用于区间搜索。

若两个指针指向同一数组,但是遍历方向相反,则可以用来进行搜索,待搜索的数组往往是排好序的。

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

在这里插入图片描述

题解

这道题还是比较简单的,因为数组已经排好序了,所以我们很容易就想到一个方法:

我们可以使用两个指针s,ls,ls,l,其中sss指向最小值,lll指向最大值。当两指针的和小于目标值时,sss指针向右移动,当两指针的和大于目标值时,lll指针向左移动,这样一定可以得到最优解,就是这样。

代码

//过于简单,我就不写注释了。
vector<int> twoSum(vector<int>& numbers, int target) 
{int l = 0, r = numbers.size() - 1, sum;while (l < r) {sum = numbers[l] + numbers[r];if (sum == target) break;if (sum < target) ++l;else --r;}return vector<int>{l + 1, r + 1};
}

88.合并两个有序数组

在这里插入图片描述

题解
因为这两个数组已经排好序,我们可以把两个指针分别放在两个数组的末尾,即 nums1 的 m m 1 位和 nums2 的 n n 1 位。每次将较大的那个数字复制到 nums1 的后边,然后向前移动一位。
因为我们也要定位 nums1 的末尾,所以我们还需要第三个指针,以便复制。
在以下的代码里,我们直接利用 m 和 n 当作两个数组的指针,再额外创立一个 ppp 指针,起
始位置为 m+n,n1m +n ,n 1m+n,n1。每次向前移动 mmmnnn 的时候,也要向前移动 ppp。这里需要注意,如果 numnumnum
的数字已经复制完,不要忘记把 nums2 的数字继续复制;如果 nums2 的数字已经复制完,剩余
nums1 的数字不需要改变,因为它们已经被排好序。

这道题用图更好理解,所以推荐查看:leetcode官方解题

注意: a++ 和 ++a都是a+1,但是a++ 返回a,然后再将a+1;
++a返回a+1。

代码

class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int p = m-- + n-- -1;  //这里厨初始化p = m + n -1,就指向nums1的最后一位,然后n--,m--。while(m>=0 && n>=0){nums1[p--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--];//三目运算符        }while(n >= 0){nums1[p--] = nums2[n--];       }}
};

142. 环形链表 II

在这里插入图片描述

题解
这道题可以使用快慢指针解决,快指针fastfastfast,慢指针slowslowslow,快指针每次走两步,满指针每次走一步,如果链表中存在环路,那么快指针和慢指针一定会相遇。
当 slow 和 fast 第一次相遇时,我们将 fast 重新移动到链表开头,并让 slow 和 fast 每次都前进一步。当 slow 和 fast 第二次相遇时,相遇的节点即为环路的开始点。

代码

class Solution {
public:ListNode *detectCycle(ListNode *head) {if (head == NULL || head->next == NULL)//这种情况下一定没环{return NULL;}ListNode* fast=head;ListNode* slow=head;//初始哈快慢指针while (fast->next !=NULL && fast->next->next != NULL)//确保环存在{fast=fast->next->next;//快指针一次走两步slow=slow->next;//慢指针一次走一步。if (fast==slow)//如果快慢指针相遇{slow=head;//慢指针移到链表头while (slow != fast){slow=slow->next;fast=fast->next;}//指针再次相遇即为环路开始点。return slow;}}return NULL;//如果不存在环路,返回NULL。}
};

633.平方数之和

在这里插入图片描述

题解
因为CCC为两个数的平方值和,所以这两个数都小于sqrt(C)sqrt(C)sqrt(C),我们初始化两个指针,一个初始化为0,另一个初始化为sqrt(C)+1sqrt(C)+1sqrt(C)+1,因为sqrt()sqrt()sqrt()向下取整,所以要加1。如果两数平方值的和大于CCC,右指针向左移动;如果小于,左指针向右移。

代码


class Solution {
public:bool judgeSquareSum(int c) {unsigned int left =0,right = sqrt(c)+1;//初始化左右指针unsigned int powSum;//两数平方的和while(right>=left){powSum = left*left+right*right;if(powSum==c) return true;else if(powSum>c) --right;else if(powSum<c) ++left;}return false;}
};

680. 验证回文字符串 Ⅱ

在这里插入图片描述

题解

代码

//太简单,不写注释
class Solution {
public:bool checkPalindrome(const string& s, int low, int high) {for (int i = low, j = high; i < j; ++i, --j) {if (s[i] != s[j]) {return false;}}return true;}bool validPalindrome(string s) {int low = 0, high = s.size() - 1;while (low < high) {char c1 = s[low], c2 = s[high];if (c1 == c2) {++low;--high;} else {return checkPalindrome(s, low, high - 1) || checkPalindrome(s, low + 1, high);}}return true;}
};

27. 移除元素

在这里插入图片描述
题解

先来个暴力解法:

class Solution {
public:int removeElement(vector<int>& nums, int val) {int size =nums.size();for(int i =0;i <size;++i){if(nums[i]==val){for(int j = i+1;j<size;++j){nums[j-1] =nums[j];}--i;--size;}}return size;}
};

暴力解法是可以通过的,但是你能满足吗?你不能满足!!!
下面是双指针法:

代码

class Solution {
public:int removeElement(vector<int>& nums, int val) {int slowIndex = 0;for(int fastIndex =0;fastIndex<nums.size();++fastIndex){if(val != nums[fastIndex])//如果快指针指向val的值,慢指针就会停止,直到快指针指向不同的值。{nums[slowIndex++] = nums[fastIndex];}}return slowIndex;}
};

344. 反转字符串

题解

其实这道题可以直接用C++的库函数解决,但这样没有什么意义。

我们定义两个指针(也可以说是索引下表),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。

代码

class Solution {
public:void swap(char& i,char &j){//这是一种不常见的交换元素方式,根据^(异或)的性质:a ^ a = 0。(参见《深入理解计算机系统》)i ^= j;j ^= i;i ^= j;}void reverseString(vector<char>& s) {for(int i =0,j=s.size()-1;i<s.size()/2;++i,--j){swap(s[i],s[j]);}        }
};

剑指 Offer 05. 替换空格

题解
如果想把这道题目做到极致,就不要只用额外的辅助空间了!

首先扩充数组到每个空格替换成 “%20” 之后的大小。

然后从后向前替换空格,也就是双指针法,过程如下:

iii指向新长度的末尾,jjj指向旧长度的末尾。
代码

class Solution {
public:string replaceSpace(string s) {int count = 0; // 统计空格的个数int sOldSize = s.size();for (int i = 0; i < s.size(); i++) {if (s[i] == ' ') {count++;}}// 扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小s.resize(s.size() + count * 2);int sNewSize = s.size();// 从后先前将空格替换为"%20"for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {if (s[j] != ' ') {s[i] = s[j];} else {s[i] = '0';s[i - 1] = '2';s[i - 2] = '%';i -= 2;}}return s;}
};

151. 翻转字符串里的单词

在这里插入图片描述

206.反转链表

在这里插入图片描述
代码

class Solution {
public:ListNode* reverseList(ListNode* head) {ListNode* temp; // 保存cur的下一个节点ListNode* cur = head;ListNode* pre = NULL;while(cur) {temp = cur->next;  // 保存一下 cur的下一个节点,因为接下来要改变cur->nextcur->next = pre; // 翻转操作// 更新pre 和 cur指针pre = cur;cur = temp;}return pre;}
};

125. 验证回文串

在这里插入图片描述
代码

class Solution {
public:bool isPalindrome(string s) {string str;for(auto i : s){if(isalnum(i))//先除了字母和数字之外的其他字符//isalnum()函数用来判断是否是字母或者是数字{str +=tolower(i);}}for(int i = 0,j =str.size()-1; i<j; ++i,--j)//通过前后两个指针,判断是否对称。{if(str[i] !=  str[j]){return false;}}return true;}
};

19. 删除链表的倒数第 N 个结点

在这里插入图片描述
代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {if(!head->next) return nullptr;//如果链表就一个元素,那也只能去掉一个,所以就返回nullptr。ListNode* fast = head;ListNode* slow = head;//初始化快指针//快指针先走n步,然后慢指针在和快指针同步走,这样的话,当快指针走到链表结尾时,慢指针刚好到达我们要去掉的元素之前的一个元素//这样slow->next =slow -> next ->next就可以从链表中去掉要除去的元素了。for(int i =0; i<n;--n){fast=fast->next;if(!fast)//如果快指针为nullptr说明点前题目要去除的元素为第一个元素,那么,直接返回链表的第二个元素就可以了。{return head->next;}}while(fast->next){slow = slow->next;fast = fast->next;}slow->next =slow->next->next;return head;}
};

面试题 02.02. 返回倒数第 k 个节点

在这里插入图片描述
题解
这种题的双指针解法大同小异,没有什么新意…
代码

 * Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:int kthToLast(ListNode* head, int k) {ListNode* fast =head;ListNode* slow =head;for(int i =0;i<k;--k){fast =fast->next;if(!fast){return head -> val;}}while(fast){fast =fast->next;if(!fast){return slow->next->val;}slow =slow->next;}return -1;//这块有一点不完美//因为程序不可能运行到这,所以返回啥都可以。}
};

持续更新中…

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

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

相关文章

ADSL技术的系统结构

ADSL技术的系统结构 1. ADSL原理和技术性能 现存的用户环路主要由UTP&#xff08;非屏蔽双绞线&#xff09;组成。UTP对信号的衰减主要与传输距离和信号的频率有关&#xff0c;如果信号传输超过一定距离&#xff0c;信号的传输质量将难以保证。此外&#xff0c;线路上的桥接抽头…

DiskSim

1.使用笔记 http://feifei432.blog.163.com/blog/static/140253361201022211949152/ http://feifei432.blog.163.com/blog/static/140253361201022212253597/ 2.安装 http://blog.sina.com.cn/s/blog_448574810101bb65.html转载于:https://www.cnblogs.com/yaolei/p/3487598.ht…

二分法(leetcode分类解题,C++代码详细注释)

二分法前言69. x 的平方根35. 搜索插入位置前言 二分查找也常被称为二分法或者折半查找&#xff0c;每次查找时通过将待查找区间分成两部分并只取一部分继续查找&#xff0c;将查找的复杂度大大减少。对于一个长度为 O(n) 的数组&#xff0c;二分查找的时间复杂度为 O(log n)。…

kernel module required key not available

UEFI主板中禁用Secure Boot转载于:https://www.cnblogs.com/jhaohai/p/3489818.html

我自横刀向天笑,我命由我不由天

那么豪放不羁,慷慨如歌.虽然江湖再来,翠山远逝,肝胆乾坤有去留, 可人生至此,交友如斯,生复何恨,死有何悲呢?我一直在想&#xff0c;“向天笑”的这个笑是怎样的笑&#xff0c;怎样的心情&#xff1f;不有行者&#xff0c;无以图将来&#xff1b;不有死者&#xff0c;无以酬圣猪…

UNIX网络编程学习笔记(代码超详细解析)(持续更新)

1. 其他函数准备 1. TCP 回射服务器程序&#xff1a; str_echo 函数 #include “unp.h”void str_echo(int sockfd) {ssize_t n;char buf[MAXLINE];again:/*write() 函数定义&#xff1a;ssize_t write (int fd, const void * buf, size_t count); 函数说明&#xff1a;w…

oracle数据库中函数和存储过程中的区别

一、函数必须有返回值&#xff0c;过程没有返回值&#xff1b; 二、函数可以单独执行&#xff0c;过程必须通过execute执行&#xff1b; 三、函数可以嵌入SQL中执行&#xff0c;过程不能。 可以将比较复杂的查询写成函数&#xff0c;然后在过程中调用。转载于:https://www.cnbl…

百川2大模型微调问题解决

之前用https://github.com/FlagAlpha/Llama2-Chinese微调过几个模型&#xff0c;总体来说llama2的生态还是比较好的&#xff0c;过程很顺利。微调百川2就没那么顺利了&#xff0c;所以简单做个记录 1. 数据准备&#xff0c;我的数据是单轮对话&#xff0c;之前微调llama2已经按…

Aspx页面javascript的几个trick

1、一般而言&#xff0c;如果想给aspx页面上的web form control加上一些javascript的特性&#xff0c;可以用Attributes.Add来实现。例如&#xff0c;对TextBox txt&#xff0c;可以&#xff1a;txt.Attributes.Add("onclick", "fcn0();");那么&#xff0c…

ArcGIS 10——地理数据库管理GIS数据

写本文的最初意向是当前正在进行的项目中有实现ESRI版本化数据管理的功能模块&#xff0c;碰到一些棘手的问题&#xff0c;几经周折还是决定系统学习ArcGIS10的帮助文档。&#xff08;文章摘抄的比较多&#xff09; 地理数据库是用于保存数据集集合的“容器”。首先了解一下Arc…

阿特拉斯神(一)

Atlas出来很久了&#xff0c;因为用不上&#xff0c;所以没有学习过&#xff0c;今天准备学了&#xff0c;却发现资料虽不少&#xff0c;但是觉得有点乱&#xff0c;还是自己从英文资料循序渐进学吧。说真的没有扎实学过什么&#xff0c;那么就从Atlas开始吧&#xff0c;希望也…

Qt学习笔记(持续更新)

第一个应用程序 #include "widget.h" #include <QApplication> #include<QLabel> int main(int argc, char *argv[]) {//创建qt应用程序对象QApplication a(argc, argv);//创建标签控件QLabel label("你好");//来吧&#xff0c;展示label.sho…

文本框宽度自动适应文本宽度

<html> <head> <title>文本框宽度自动适应文本宽度 </title> </head> <script type"text/javascript"> function changeInputlength(cursor) { var getTextdocument.getElementById("text"); cursor.sizegetText.valu…

安装了一次Linux,哈哈

昨天在宿舍里&#xff0c;舍友在她的机子上装了Redhat&#xff0c;自己在旁边和另一舍友做参谋&#xff0c;哈哈&#xff0c;虽然中间几多挫折&#xff0c;但最终还是把系统装好了&#xff0c;第一次完整的安装Linux&#xff0c;在此记录一下&#xff0c;哈哈…… 现在想…