双指针
Leetcode #167 两数之和 II - 输入有序数组
题名:两数之和 II - 输入有序数组
描述:
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
具体描述请查看Leetcode相关网页:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/
方法:双指针
我们可以使用 两数之和 的解法在 O(n^2)时间 O(1) 空间暴力解决,也可以用哈希表在 O(n)时间和 O(n) 空间内解决。然而,这两种方法都没有用到输入数组已经排序的性质,我们可以做得更好。
我们使用两个指针,初始分别位于第一个元素和最后一个元素位置,比较这两个元素之和与目标值的大小。如果和等于目标值,我们发现了这个唯一解。如果比目标值小,我们将较小元素指针增加一。如果比目标值大,我们将较大指针减小一。移动指针后重复上述比较知道找到答案。
vector<int> twoSum(vector<int>& numbers, int target) {
int l = 0, r = numbers.size() - 1;
vector<int> ans;
while(l < r){
if(numbers[l] + numbers[r] == target){
ans.push_back(l + 1);
ans.push_back(r + 1);
return ans;
}
else if(numbers[l] + numbers[r] < target) l++;
else r--;
}
return ans;
}
Leetcode #345 反转字符串中的元音字母
题名:反转字符串中的元音字母
描述:
编写一个函数,以字符串作为输入,反转该字符串中的元音字母。
EXAMPLE1:
输入: "hello"
输出: "holle"
EXAMPLE2:
输入: "leetcode"
输出: "leotcede"
具体描述请查看Leetcode相关网页:https://leetcode-cn.com/problems/reverse-vowels-of-a-string/
方法一:两次遍历
如果从头往后遍历的过程中遇到了元音字母,将其压入栈中。再从头往后遍历一遍,如果遇到元音字母,用栈顶字母替换。因为栈的后进先出特性能够翻转元音字母。代码如下:
bool isYuanYin(char a){
string str = "aeiouAEIOU";
if(str.find(a) == str.npos)
return false;
return true;
}
string reverseVowels(string s) {
string::iterator it = s.begin();
stack<char> st;
while(it != s.end()){
if(isYuanYin(*it)) st.push(*it);
it++;
}
it = s.begin();
while(it != s.end()){
if(isYuanYin(*it)){
*it = st.top();
st.pop();
}
it++;
}
return s;
}
方法二:双指针
设置两个指针,p指向字符串开始处,q指向字符串结尾处。首先p相后移动,如果遇到元音字母就停止(因为我们反转),让q向前移动直到遇到元音字母,交换两个元音字母。重复上述步骤,直到 p > q 为止;
代码如下:
bool isYuanYin(char a){
string str = "aeiouAEIOU";
if(str.find(a) == str.npos)
return false;
return true;
}
string reverseVowels(string s) {
int p = 0, q = s.size() - 1;
while(p <= q){
if(isYuanYin(s[p])){
while(!isYuanYin(s[q])) q--;
char tmp = s[q];
s[q] = s[p];
s[p] = tmp;
q--;//交换好要让q-- !
}
p++;
}
return s;
}
Leetcode #680 验证回文字符串 Ⅱ
题名:验证回文字符串 Ⅱ
描述:
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
EXAMPLE1:
输入: "aba"
输出: True
EXAMPLE2:
输入: "abca"
输出: True
解释: 你可以删除c字符。
具体描述请查看Leetcode相关网页:https://leetcode-cn.com/problems/valid-palindrome-ii/
方法:双指针
设置两个指针,p指向字符串开始处,q指向字符串结尾处。移动p,q直到s[p]!=s[q],然后考虑2种情况:
1.判断从p到q - 1是否为回文;
2.判断从p + 1到q是否为回文;
代码如下:
bool validPalindrome(string s) {
int p = 0, q = s.size() - 1;
while(p <= q){
if(s[p] != s[q]){
if(dealWith(s, p, q - 1)) return true;
if(dealWith(s, p + 1, q)) return true;
return false;
}
p++;
q--;
}
return true;
}
bool dealWith(string s, int l, int r){
while(l <= r){
if(s[l] != s[r]) return false;
l++;
r--;
}
return true;
}
Leetcode #141 环形链表
题名:环形链表
描述:
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
EXAMPLE1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
EXAMPLE2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
EXAMPLE3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
具体描述请查看Leetcode相关网页:https://leetcode-cn.com/problems/linked-list-cycle/
方法:双指针
利用快慢指针,如果存在环,快慢指针最终一定会相遇;如果不存在环,则不会相遇;如何证明我还在研究,有知道的小伙伴一定要告诉我哦~~~
代码如下:
bool hasCycle(ListNode *head) {
ListNode *p = head, *q = head;
while(q && q->next && q->next->next){
p = p->next;
q = q->next->next;
if(p == q) return true;
}
return false;
}
Leetcode #142 环形链表 II
题名:环形链表 II
描述:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
EXAMPLE1:
图可以参考leetcode#141
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
具体描述请查看Leetcode相关网页:https://leetcode-cn.com/problems/linked-list-cycle-ii/
方法:双指针
1.首先利用快慢指针来判断该链是否存在环;如果不存在直接返回NULL,如果存在则执行2;
2.由1已经得到快慢指针的偶遇点h,那么h到开始入环的第一个节点的距离和链表头到开始入环的第一个节点的距离是相等的。具体证明如下:
已知快指针f和满指针l第一次相遇与h点,那么f走过 d1 = F + a + b + a
的距离,s走过 d2 = F + a
的距离,由于慢指针每次走一步,快指针每次走2步,所以 d1 = 2*d2
,即2(F + a) = F + a + b + a
,从中解出 F = b
;证明完毕
代码如下:
ListNode *detectCycle(ListNode *head){
ListNode *p = head, *q = head, *h = head;
bool haveCycle = false;
while(q && q->next){
q = q->next->next;
p = p->next;
if(q == p){
haveCycle = true;
h = p;
break;
}
}
if(!haveCycle) return NULL;
p = head;
while(p != h){
p = p->next;
h = h->next;
}
return h;
}
Leetcode #524 通过删除字母匹配到字典里最长单词
题名:通过删除字母匹配到字典里最长单词
描述:
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
EXAMPLE1:
输入:
s = "abpcplea", d = ["ale","apple","monkey","plea"]
输出:
"apple"
方法:双指针
1.先通过对d字典进行遍历,把复合要求的字符串都放入容器vi中
2.对vi进行sort排序
3.返回vi[0]
代码如下:
string findLongestWord(string s, vector<string>& d) {
vector<string> vi;
for(int i = 0;i < d.size();i++){
if(canMakeBys(s, d[i]))
vi.push_back(d[i]);
}
sort(vi.begin(),vi.end(),[](auto a, auto b){
return a.size() > b.size() || (a.size() == b.size() && a < b);
});
return vi.size() > 0 ? vi[0] : "";
}
bool canMakeBys(string a, string b){
int p = 0, q = 0, end = a.size();
while(p < end && q < b.size()){
if(a[p] == b[q]) q++;
p++;
}
if(q == b.size()) return true;
return false;
}
}
if(q == b.size()) return true;
return false;
}