C++ 双指针汇总(快慢指针, 滑动窗口, 前后指针,左右指针)
一. 归并有序序列
LeetCode 88题
input: nums1 = {2,2,3,0,0,0}; m=3; nums2 = {1,5,6}; n=3
output: nums1 = {1,2,2,3,5,6}
require: 时间O(n) 内存O(1)
1.1 总结:
1.2 代码
#include <iostream>
#include <stdio.h>
#include <vector>
#include <map>using namespace std;// 归并两个有序数组
// 加上&参数传递的是地址, 这样就可以改变参数的值, 因为题目要求是在数组nums1上进行排序
void solution(vector<int>& nums1, int m, std::vector<int> nums2, int n){for(auto i: nums1)cout<<i<<" "; cout<<endl;int pos=nums1.size()-1;// 这里也可以是m+n-1m--;n--;while(m>=0 && n>=0){nums1[pos--] = nums1[m] <= nums2[n] ? nums2[n--]:nums1[m--];}while(n>=0){ //这里是因为如果num1还有剩余, 那么num1前面的因为已经排好序那自然是没毛病了, // 但是num2还有剩余, 就需要转移到num1中nums1[pos--] = nums2[n--];}
}int main(int argc, char const *argv[])
{std::vector<int> nums1 = {2,2,3,0,0,0};std::vector<int> nums2 = {1,5,6};solution(nums1, 3, nums2, 3);for(auto i: nums1)cout<<i<<" "; cout<<endl;printf("%s\n", "hello");return 0;
}
二. 两数之和
LeetCode 167题
input: nums1 = {1,2,3,4,5,7}; target=9
2.1 总结:
2.2 代码
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdio.h>
#include <map>using namespace std;
void print_vector(vector<int> numbers){for(auto c : numbers) cout<< c <<" ";cout<<endl;
}// 使用&, 指的是函数参数传递进来的可以被改变,引用传递, int a, func(a) func(int &a){a=100}
// 使用*, 指的是参数即为指针, int a, func(&a) func(int *a){*a=100}
int solution1(vector<int> numbers, int target){print_vector(numbers);sort(numbers.begin(), numbers.end());int sum, i=0,j=numbers.size()-1;while (i<j){sum= numbers[i]+numbers[j];if (sum>target) {j--; }else if(sum==target) {break; }else {i++;}}print_vector(numbers);printf("%d = %d+%d\n", target, numbers[i], numbers[j]);
}// 也可以做一个字典, 字典只需要遍历一遍即可, 不需要排序, 而双指针需要排序, 相当于遍历两遍
void solution2(vector<int> numbers, int target){map<int,int> personnel;for(int i=0; i<numbers.size(); i++){int sum = target-numbers[i];if (personnel.find(sum) == personnel.end()){personnel.insert(pair<int, int>(numbers[i],i));}else{printf("%d = %d+%d\n", target, numbers[i], personnel.find(sum)->first);}}
}
// python解法
// numbers = [1,2,4,5,7]
// target = 9// map1 = {}
// for i,numb in enumerate(numbers):
// if map1.get(target-numb)==None:
// map1[numb] = i
// else:
// print(numb, target-numb)int main(int argc, char const *argv[])
{vector<int>numbers = {2,7,11,15,1,2};solution1(numbers, 9);solution2(numbers, 9);cout<<"hello" <<endl;return 0;
}
三. Floyd算法
LeetCode 142题
- 给定一个链表, 判断是否存在环路, 存在则返回环路入口节点
找到2的所属节点
总结: 这题太重要了, 一个Floyd算法的数学证明和单链表的各种基础操作
3.1 总结
3.2 代码
注意: 这里包含单链表的基础操作
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(nullptr) {} // 这里默认Node的next是nullptr
};// Floyd算法, 找到环路起点
ListNode *detectCycle(ListNode *head){ListNode *slow=head;ListNode *fast=head;int i=20;// fast:slow=2:1的速度前进, 如果fast到达终点, 则没有环路, // 否则等二者相遇, fast回归起点, 1:1速度进行,二次相遇后, 为起始点while(fast && fast->next){fast = fast->next->next; //因为while入口已经确定fast->next存在, 那么fast->next的next至少至少也是nullptr格式, 因为结构体定义部分定义的, 所以这里fast->next->next;不会越界slow = slow->next;if(fast == slow){ //第一次相遇fast = head;while(fast!=slow){slow = slow->next;fast = fast->next;}cout<<"\n带环最终结果是"<<fast->val<<endl;return fast; //第二次相遇}}cout<<"没有环"<<endl;return nullptr;
}int main(int argc, char const *argv[])
{ListNode *head, *end; //创建两个节点head=(ListNode*)malloc(sizeof(ListNode)); //给头节点先开辟个空间// 创建节点,并赋值ListNode *normal=(ListNode*)malloc(sizeof(ListNode)); //创建临时节点normal->val = 28; //给临时节点赋值head->next = normal; //临时节点链接到头节点end = head->next; for(int i=0; i<11; i++){ //链表的插入ListNode *a=(ListNode*)malloc(sizeof(ListNode));a->val = i;end->next = a;end = end->next;// cout<<end->val<< endl;}cout<<"打印当前链表内容: 0 28 0 1 2 3 4 5 6 7 8 9"<<endl;detectCycle(head);end->next = normal; // 加上一个圆环ListNode *a = head;cout<<"打印一下带环链表内容,"<<endl;for(int i=0; i<20; i++){cout<<a->val<<" ";a = a->next;}detectCycle(head);cout<<"hello" <<endl;return 0;
}
四. 最长不重复子串(滑动窗口)
LeetCode 3题
input = 'acbva'
output = "acbv"或者"cbva"
output = 4最长不重复子串解题技巧:
设定左右两指针, 指向窗口找最大
如若窗口有重复, 集合删左左在进
4.1 总结
4.2 代码
注意这里使用一个字典, 集合, 列表其实都可以, 只要能判定元素是否在列表中, 能删除列表的第一位即可
#include <vector>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <set>
using namespace std;// 问题描述:
// 不重复最长子串
// 输入 'acbva'
// 找到这串里面最长的不重复的子串, 如果是acbva, 这是子序列,
// 只有不重复的才是子串, 则acbv是子串, acbv或者cbva是不重复最长子串// -----------解题关键: 就是创建一个数组, 集合, 字典, 用来装窗口内是否有重复,
// -------------如果有重复就左指针右移, 没有就右右移// 最长不重复子串解题技巧:
// 设定左右两指针, 指向窗口找最大
// 如若窗口有重复, 集合删左左在进
string solution_set(string s){ //acbvacout << "\n需要找的最长子串是"<<s<<endl;set<char> set_swap;int max_len = 0;int left=0, right=0;while(right<s.size()){// set_swap保存的是s[left, right]不重复的数据呀if(0 == set_swap.count(s[right])){ // 确定没s[right], 就是加入s[right]依然没有重复的, 则将s[right]加入到字典, set_swap.insert(s[right++]);if(max_len < right-left){for(set<char>::iterator iter = set_swap.begin(); iter!=set_swap.end(); iter++){cout<<*iter<<" ";}cout<<endl; }max_len = max(max_len, right-left);}else{ // 如果有重复的, 那就删除set_swap.erase(s[left++]);}}printf("最长子串是: %d\n", max_len);string res = "";return res;
}string solution_vector(string s){string res = "";std::vector<char> v_swap;std::vector<string> v_res;int left=0, right=0, max_len=0;while(right < s.size()){if (0 == std::count(v_swap.begin(), v_swap.end(), s[right])){v_swap.push_back(s[right++]);if (max_len<right-left){ // 打印结果for(auto i:v_swap){cout<<i<<" ";}cout<<endl;}max_len = max(max_len, right-left);}else{v_swap.erase(v_swap.begin(),v_swap.begin()+1); // 删除列表中的第一个left++;}}cout<<"输入"<<s<<" 结果是:"<<max_len<<endl;return res;
}int main(int argc, char const *argv[])
{string s = "11334566";string res = solution_set(s);// string res = solution_vector(s);cout<< "hello world" <<endl;return 0;
}
五. 最短覆盖子串(滑动窗口)
LeetCode 76题
input: S = "ADOBECODEBANC"; T = "ABC";
output: res = BANC
5.1 总结
这里需要注意的是:
创建一个能够统计目标字符的字典, 这样就可以在每次判断每一个字符是否是多余的, 对窗口去冗余极其重要
5.2 代码
a. python实现
import sys,os
# 核心思路: 找到目标窗口, 然后去除冗余, 完成
# 右指针向右, 直到遇到全部T,
# 左指针向右, 直到最短子串S1出现, 给临时最优
# 左指针在向右, 此时窗口没有目标子串, 此时右指针向右,右指针
#
# 最短目标子串解题技巧:
# 设定左右两指针, 指向窗口找目标
# 窗有冗余左进右, 无余左进等右尽
#
# 注意滑动窗口就是目标值
def solution(S, T):# print(S, T)if len(S)<len(T):return ""window = "" result = ""need = {}for _ in T:need[_] = 1 if _ not in need else need[_]+1needCnt = len(T)for c in S:if c in need:if need[c]>0:needCnt-=1need[c]-=1window+=cif needCnt == 0: # 窗口已经满足, 可以去冗余, 这个时候, need里面的值, 有可能是-2, 如AAABCwhile True:if window[0] in T: # 窗口最左是目标字符if need[window[0]] <0: # 字符没用, 左指针右移need[window[0]] += 1window = window[1:]elif need[window[0]] == 0: # 关键 表示正好, 此时左右没有冗余, 此时左指针向右移动一个后, 整个窗口就不完整了, 进行下一轮if result:if len(window)<len(result):result = window else:result = windowneed[window[0]] += 1window = window[1:]needCnt += 1breakelse: # 这里是最左的字符是垃圾, 直接去掉即可window = window[1:]print("结果是: ",result)return resultif __name__ == '__main__':solution("ADOBECODEBANC", "ABC")
# // Input: S = "ADOBECODEBANC", T = "ABC"
# // Output: "BANC"
b. C++实现
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <vector>
#include <sstream> // 为了使用stringsteam
using namespace std;// 题目描述: 给定字符串S,T, 求S中包含T所有字符的最短连续子字符串的长度, 时间复杂度不能超过O(n)
// 输入样例:
// Input: S = "ADOBECODEBANC", T = "ABC"
// Output: "BANC"// 解题思路: 双指针(前后指针)指向开始, 如果没有遇到T中的字符串,
// 双指针同时向后移动, 遇到一个以后, 后指针继续, 知道遇到全部T,
// 将当前前后指针指向子串给临时最优,
// 核心: 当窗口不满足要求的时候, 就向右拓宽边界
string solution(string S, string T){cout<<S<<"里面找"<<T<<endl;vector<int> chars(128, 0); //计数需要查找的字符个数, 比如AABBA 则需要找到三个A两个Bvector<bool> flag(128, false); //标记都有哪几个字符需要查找// 先统计T中的字符情况for(int i = 0; i < T.size(); ++i) {flag[T[i]] = true;++chars[T[i]];}// 移动滑动窗口,不断更改统计数据int cnt = 0, left = 0, min_l = 0, min_size = S.size() + 1;for (int right = 0; right < S.size(); ++right) {if (flag[S[right]]) { // 如果当前right所指字符是待查找字符if (--chars[S[right]] >= 0) { // 且当前该字符还没查完, 那就计数加++cnt;}// 若目前滑动窗口已包含T中全部字符,// 则尝试将l右移,在不影响结果的情况下获得最短子字符串while (cnt == T.size()) {if (right - left + 1 < min_size) { // 缩短长度min_l = left;min_size = right - left + 1;}if (flag[S[left]] && ++chars[S[left]] > 0) {--cnt;}++left;}}}return min_size > S.size()? "": S.substr(min_l, min_size);
}
int main(int argc, char const *argv[])
{string S = "ADOBECODEBANC";string T = "ABC";string res = solution(S,T);cout << res << endl;return 0;
}
C++ 双指针汇总(快慢指针, 滑动窗口, 前后指针,左右指针)相关推荐
- 神机百炼1.15-双指针/滑动窗口
滑动窗口 食用指南: 题目描述: 题目分析: 算法原理: 含义: 作用: 已经见过的双指针: 1. 单串双指针-快速排序: 2. 双串双指针-归并排序: 3. 双串双指针-逆序对个数: 滑动窗口模型: ...
- uiautomation遍历windows所有窗口_万字长文!滑动窗口看这篇就够了!
大家好,我是小浩.今天是小浩算法 "365刷题计划" 滑动窗口系列 - 整合篇.之前给大家讲解过一些滑动窗口的题目,但未作系统整理. 所以我就出了这个整合合集,整合工作中除了保留原 ...
- LeetCode刷题:滑动窗口模板以及典型例题
作者:fuxuemingzhu 链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/fen-xiang-hua- ...
- leetcode209. 长度最小的子数组(暴力+滑动窗口)
一:题目 二:暴力+滑动窗口 1:暴力解法 class Solution {public:int min (int a ,int b){return a < b ? a : b;}int min ...
- leetcode 滑动窗口
滑动窗口 文章目录 滑动窗口 模板框架 [76. 最小覆盖子串](https://leetcode-cn.com/problems/minimum-window-substring/) 思路分析 代码 ...
- leetcode 滑动窗口1
leetcode 滑动窗口1 leetcode159. 至多包含两个不同字符的最长子串 1. 题目 2. 解答 leetcode1151. 最少交换次数来组合所有的1 1. 题目 2. 解答 leet ...
- 【leetcode个人练习记录】 滑动窗口的问题
1.从本质上来看 ,滑窗是双指针,一根指针指向左端点,一根指针指向右端点. 2.右指针移动是可以表示扩张窗口,左指针移动表示缩小窗口. 3.如果当前元素满足需求时,可以挪动右指针尝试更优解,并且更新需 ...
- 常见面试算题题中的滑动窗口问题
LeetCode1004. 最大连续1的个数 III 题目描述 给定一个由若干 0 和 1 组成的数组 A,最多可以将数组A中的 K 个元素的值从 0 变成 1 ,返回仅包含 1 的最长(连续)子数组 ...
- 4-6:TCP协议之滑动窗口
文章目录 一:滑动窗口 二:滑动窗口格式详解 (1)发送方的滑动窗口 (2)接受方滑动窗口 本文大部分内容来自小林coding<图解网络>,感谢分享,简单整理. 一:滑动窗口 在前面的讲解 ...
最新文章
- C#String.PadLeft函数,文本对齐以及填补解决方案
- Can't call rollback when autocommit=true
- 最大输入hdu 2534 规律水题 求任意个a,b的和 不能表示的最大的数
- Linux内核探讨-- 第七章
- Node.js 极简入门Helloworld版服务器例子
- VB 金额大小写转换(两种方法)
- 【模型解读】深度学习网络之Siamese Network网络
- Vscode----热门插件超实用插件汇总(史上最全)
- 框架学习之Hibernate 第十节 事务原理与分析
- 汇编语言(十四)之判断字符串是否包含数字
- SVN使用方法及问题解决
- 群同态基本定理证明_群同态基本定理II
- 欧姆龙plc解密实例_OMRON PLC的加密和解密方法
- 用户场景法,设计测试用例
- linux中用来保存组账户的文件,Linux账户管理的几个文件
- 《Adobe Premiere Pro CS6中文版经典教程》——1.3 扩展工作流
- 计算机中ufc是什么意思中文,ufc是什么意思,ufc是什么意思中文
- 鸿蒙开发板Hi3861模拟SPI驱动JLX12864_LCD(UC1701X)_基于code-2.0
- PSO粒子群算法微电网优化调度(微电网孤岛运行优化调度)matlab程序
- Java网红10s计时器