找了一些leetcode双指针系列的简单题目。
167. 两数之和 II - 输入有序数组
题解:
- 使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
- 如果两个指针指向元素的和 sum == target,那么得到要求的结果;
- 如果 sum > target,移动较大的元素,使 sum 变小一些;
- 如果 sum < target,移动较小的元素,使 sum 变大一些。
- 数组中的元素最多遍历一次,时间复杂度为 O(N)。只使用了两个额外变量,空间复杂度为 O(1)。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> ans;
int i = 0; //头指针
int j = numbers.size()-1; //尾指针
while(i < j){
while(numbers[i] + numbers[j] < target)
i++;
while(numbers[i] + numbers[j] > target)
j--;
if(numbers[i] + numbers[j] == target){
ans.push_back(i+1);
ans.push_back(j+1);
return ans;
}
}
return ans;
}
};
633. 平方数之和
- 题解:
使用双指针,由于是求平方和,所以尾指针初始值给所的值开平方跟即可, - 坑点:
指针要有long,用int会报错
循环条件是<= , 题目中没说a和b不同,所以要有等号
class Solution {
public:
bool judgeSquareSum(int c) {
long i = 0;
long j = (long)sqrt(c);
while(i <= j){
if(i * i + j * j == c )
return true;
else if (i * i + j * j < c)
i++;
else
j--;
}
return false;
}
};
345. 反转字符串中的元音字母
- 题解:
使用双指针,前后找到直接替换即可。 - 注意:
swap完后,要i++,j–; 否则会陷入死循环。
元音别忘了大写的。
class Solution {
public:
bool find(char c){
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'||
c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U'; }
string reverseVowels(string s) {
int i = 0;
int j = s.size() - 1;
while (i < j){
while( !find(s[i]) && i < j )
i++;
while( !find(s[j]) && i < j )
j--;
swap(s[i++],s[j--]);
}
return s;
}
};
680. 验证回文字符串 Ⅱ
- 题解:
- 本题的关键是处理删除一个字符。在使用双指针遍历字符串时,如果出现两个指针指向的字符不相等的情况,我们就试着删除一个字符,再判断删除完之后的字符串是否是回文字符串。
- 在试着删除字符时,我们既可以删除左指针指向的字符,也可以删除右指针指向的字符。
class Solution {
public:
bool isPalidrome(string s, int i ,int j){
while (i < j){
if(s[i++] != s[j--] )
return false;
}
return true;
}
bool validPalindrome(string s) {
for(int i = 0 , j = s.length()-1 ; i < j ; i++, j--){
if( s[i] != s[j] )
return isPalidrome(s,i+1,j) || isPalidrome(s,i,j-1);
}
return true;
}
};
88. 合并两个有序数组
注意: 需要从尾开始遍历,否则在 nums1 上归并得到的值可能会覆盖还未进行归并比较的值。
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = m - 1 ,j = n - 1;
int k = m + n - 1 ;
while(i >= 0 || j >= 0){
if(i < 0 )
nums1[k--] = nums2[j--];
else if(j < 0)
nums1[k--] = nums1[i--];
else if(nums1[i] > nums2[j])
nums1[k--] = nums1[i--];
else
nums1[k--] = nums2[j--];
}
}
};
141 给定一个链表,判断链表中是否有环。
解法一:
快慢指针:一个指针一次跳两格,一个指针一次跳一格,有环的话必定能追上。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL || head->next == NULL)
return false;
ListNode *fast = head->next;
ListNode *slow = head;
while(fast != slow){
if(fast->next==NULL || fast->next->next == NULL)
return false;
fast = fast->next->next;
slow = slow->next;
}
return true;
}
};
解法二:
新建一个END节点,将遍历过的节点指向END,如果有节点==END就是有环
class Solution {public:
bool hasCycle(ListNode *head) {
if(head == NULL ) return false;
ListNode *END =new ListNode(0);
ListNode* pre;
while(head){ //判断下一个指针是否为空
if(head==END) return true;
pre=head;
head=head->next;
pre->next=END;
}
return false;
}
};
524. 通过删除字母匹配到字典里最长单词
- 通过删除字符串 s 中的一个字符能得到字符串 t,可以认为 t 是 s 的子序列,我们可以使用双指针来判断一个字符串是否为另一个字符串的子序列。
- 找到一个满足的后,我们可以直接过滤更短的字符串或者一样长且字典顺序较大的字符串,来提高速率。
class Solution {
public:
string findLongestWord(string s, vector<string>& d) {
string str = "";
for(int i = 0 ;i < d.size();i++){
int l1 = str.length();
int l2 = d[i].length();
//直接过滤字符串更短 或者 一样长且字典顺序较大的
if(l1 > l2 || (l1 == l2 && str.compare(d[i]) < 0))
continue;
if(isSubstr(d[i],s))
str = d[i];
}
return str;
}
private:
bool isSubstr(string target, string s){
int i = 0, j = 0;
while(i < target.length() && j < s.length()){
if(target[i] == s[j])
i++;
j++;
}
return i == target.length();
}
};