赞
踩
双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延伸到多个数组的多个指针。
若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域即为当前的窗口),经常用于区间搜索。
若两个指针指向同一数组,但是遍历方向相反,则可以用来进行搜索,待搜索的数组往往是排好序的。
题解
这道题还是比较简单的,因为数组已经排好序了,所以我们很容易就想到一个方法:
我们可以使用两个指针 s , l s,l s,l,其中 s s s指向最小值, l l l指向最大值。当两指针的和小于目标值时, s s s指针向右移动,当两指针的和大于目标值时, l l l指针向左移动,这样一定可以得到最优解,就是这样。
代码
//过于简单,我就不写注释了。
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};
}
题解
因为这两个数组已经排好序,我们可以把两个指针分别放在两个数组的末尾,即 nums1 的 m m 1 位和 nums2 的 n n 1 位。每次将较大的那个数字复制到 nums1 的后边,然后向前移动一位。
因为我们也要定位 nums1 的末尾,所以我们还需要第三个指针,以便复制。
在以下的代码里,我们直接利用 m 和 n 当作两个数组的指针,再额外创立一个
p
p
p 指针,起
始位置为
m
+
n
,
n
1
m +n ,n 1
m+n,n1。每次向前移动
m
m
m 或
n
n
n 的时候,也要向前移动
p
p
p。这里需要注意,如果
n
u
m
num
num
的数字已经复制完,不要忘记把 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--]; } } };
题解
这道题可以使用快慢指针解决,快指针
f
a
s
t
fast
fast,慢指针
s
l
o
w
slow
slow,快指针每次走两步,满指针每次走一步,如果链表中存在环路,那么快指针和慢指针一定会相遇。
当 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。 } };
题解
因为
C
C
C为两个数的平方值和,所以这两个数都小于
s
q
r
t
(
C
)
sqrt(C)
sqrt(C),我们初始化两个指针,一个初始化为0,另一个初始化为
s
q
r
t
(
C
)
+
1
sqrt(C)+1
sqrt(C)+1,因为
s
q
r
t
(
)
sqrt()
sqrt()向下取整,所以要加1。如果两数平方值的和大于
C
C
C,右指针向左移动;如果小于,左指针向右移。
代码
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; } };
题解
代码
//太简单,不写注释 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; } };
题解
先来个暴力解法:
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; } };
题解
其实这道题可以直接用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]); } } };
题解
如果想把这道题目做到极致,就不要只用额外的辅助空间了!
首先扩充数组到每个空格替换成 “%20” 之后的大小。
然后从后向前替换空格,也就是双指针法,过程如下:
i
i
i指向新长度的末尾,
j
j
j指向旧长度的末尾。
代码
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; } };
代码
class Solution { public: ListNode* reverseList(ListNode* head) { ListNode* temp; // 保存cur的下一个节点 ListNode* cur = head; ListNode* pre = NULL; while(cur) { temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next cur->next = pre; // 翻转操作 // 更新pre 和 cur指针 pre = cur; cur = temp; } return pre; } };
代码
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; } };
代码
/** * 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; } };
题解
这种题的双指针解法大同小异,没有什么新意…
代码
* 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; //这块有一点不完美 //因为程序不可能运行到这,所以返回啥都可以。 } };
持续更新中…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。