玩转双指针
算法解释
- 双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务
- 若两个指针指向同一数组,遍历方向相同且不会相交,也成为滑动窗口
- 若指向同一数组,但是遍历方向相反,则可用来进行搜索
指针与常量
int x;
int *p1=&x;//指针可以被修改,值也可被修改
const int*p2=&x;//值不可修改
int * const p3 =&x;//指针不可被修改
const int * const p4 =&x;//皆不可修改
*指针函数与函数指针
// addition是指针函数,一个返回类型是指针的函数
int* addition(int a, int b) {
int* sum = new int(a + b);//分配内存
return sum;
}
int subtraction(int a, int b) {
return a - b;
}
int operation(int x, int y, int (*func)(int, int)) {
return (*func)(x,y);
}
// minus是函数指针,指向函数的指针
int (*minus)(int, int) = subtraction;
int* m = addition(1, 2);
int n = operation(3, *m, minus);
合并两个数组
题目:输入两个数组及其长度m,n,第一个数组长度被扩展到m+n,多出的n位用0填补,要求将第二个数组归并到第一个数组上,不需要开辟额外空间
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int pos = m-- + n-- - 1;
while (m >= 0 && n >= 0) {
nums1[pos--] = nums1[m] > nums2[n]? nums1[m--]: nums2[n--];
}
while (n >= 0) {
nums1[pos--] = nums2[n--];
}
}
快慢指针
题目:给定一个链表,如果有环路,找出环路的起始点。
输入输出举例:
输入是一个链表,输出是链表的一个节点,如果没有环路,返回一个空指针
样例中,值为2的节点即为环路的开始点,采用如下数据结构表示链表
struct ListNode{
int val;
ListNode *next;
ListNode(int x):val(x),next(nullptr){}
};
题解;
给定两个指针,起始位置在链表开头,前进步数设为不同,若存在环路,肯定会有相遇问题,当他们第一次相遇时,将快指针重新移动到链表开头,并让快和慢每次都前进一步,当第二次相遇时,相遇节点即为环路的开始点
ListNode *detectCycle(ListNode *head){
ListNode *slow=head,*fast=head;
//判断是否存在环路
do{
if(!fastt||!fast->next) return nullptr;
fast=fast->next->next;
slow=slow->next;
}while(fast!=slow);
//如果存在,查找环路节点
fast=head;
while(fast!=slow){
slow=slow->next;
fast=->fast->next;
}
return fast;
}
滑动窗口
题目:给定两个字符串S和T,求S中包含T所有字符的最短连续子字符串的长度,同时要求时间复杂度不得超过O(n);
题解:使用滑动窗口解决,即两个指针 l 和 r 都是从最左端向最右端移动,且 l 的位置一定在r的左边或者重合,使用长度为128的数组来映射字符,也可以用哈希表替代;其中 chars 表示目前每个字符缺少的数量,flag 表示每个字符中是否在T中存在
string minWindow(string S,string T){
vector<int>chars(128,0);
vector<bool>flag(128,false);
//先统计T中字符情况
for(int i=0;i<T.size();++i){
flag[T[i]]=true;
++chars[t[i]];
}
//移动滑动窗口,不断更改统计数据
int cnt=0,l=0,min_l=0,min_size=S.size()+1;
for(int r=0;r<S.size();++r){
if(flag[S[r]]>=0){
++cnt;
}
//若目前滑动窗口已包含T中全部字符,则尝试将l右移,在不影响结果的情况下获得最短字符串
while(cnt==T.size()){
if(r-1+1<min_size){
min_l=1;
min_size=r-1+1;
}
if(flag[S[l]]&&++chars[S[l]]>0){
--cnt;
}
++l;
}
}
return min_size>S.size()?"":S.substr(min_l,min_size);