一、 两数之和 II ——输入有序数组 Leetcode题目号:167 难度:easy
题目描述:
思路:
设置双指针low和high,分别指向两个数中的较小数和较大数,low从数组第一个元素开始,high从数组最后一个元素开始,分为以下三种情况:
- num[low] + num[high] == target 即找到了满足题目的两个元素,但由于题目要求下标从1开始,故将low和high都加1后存入答案数组,直接退出循环,返回答案即可。
- num[low] + num[high] < target 此时需要使两数之和变小,只需low指针加一,high指针不需要动
- num[low] + num[high] > target 此时需要使两数之和变大,只需high指针减一,low指针不需要动
由于只遍历了数组一次,且只用了两个额外变量,故时间复杂度为O(n),空间复杂度为O(1)
代码如下:
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> ans;
int n=numbers.size();
int low=0,right=n-1;
while(low<right){
if(numbers[low]+numbers[right]==target){
ans.push_back(low+1);
ans.push_back(right+1);
break;
} else if(numbers[low]+numbers[right]<target){
low++;
} else{
right--;
}
}
return ans;
}
};
二、平方数之和 Leetcode题号:633 难度:easy
题目描述:
思路:此题与第一题很类似,同样设置左右指针i、j,只不过需要考虑一下右指针j的初值设置,根据题设不难看出右指针最大指向sqrt(c),若用整数保存sqrt函数的结果,会向下取整。故为了剪枝,j的初值取为sqrt(c)
时间复杂度为O(sqrt(c)),空间复杂度为O(1)
代码如下:
class Solution {
public:
bool judgeSquareSum(int c) {
long i = 0, j = sqrt(c);
bool ans = false;
while(i <= j){
if(i * i + j * j == c){
ans = true;
break;
} else if(i * i + j * j < c){
i++;
} else{
j--;
}
}
return ans;
}
};
三、反转字符串中的元音字母 Leetcode题号:345 难度:easy
题目描述:
思路:首先写一个函数来穷举判断一个字母是否是元音字母,然后使用双指针前后遍历字符串,若两个指针指向的字母当中有一个不是元音字母,则i指针向右或j指针向左移动(谁不是元音谁动)。若两个都是元音字母,则交换二者之后左指针继续向右移动,右指针继续向左移动,直到i和j相遇,结束遍历
代码如下:
class Solution {
public:
bool Judge(char ch){
if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' || ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U'){
return true;
} else{
return false;
}
}
string reverseVowels(string s) {
if(s == ""){
return "";
}
int i = 0, j = s.size() - 1;
while(i <= j){
if(!Judge(s[i])){
i++;
} else if(!Judge(s[j])){
j--;
} else{
char temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
}
return s;
}
};
四、验证回文字符串II Leetcode题号:680 难度:easy
题目描述:
思路:所谓回文串就是正着读和反着读一样的串,即对称串,解决回文串问题时可考虑双指针,且由于回文串的对称特性,故只需判断双指针之间的字符是否满足对称特性。不过此题还有一个条件:可以删去一个字符,故可以在左指针和右指针指向的字符不相等时,分别考虑删去左指针和右指针指向的字符,继续判断是否满足回文串特性,只要两种情况中有一种满足条件,就可确定该串是回文串
代码如下:
class Solution {
public:
bool validPalindrome(string s) {
int len = s.size();
for(int i = 0, j = len - 1; i < j; i++, j--){
if(s[i] != s[j]){
return Judge(s, i+1, j) || Judge(s, i, j-1);
}
}
return true;
}
bool Judge(string s, int i, int j){
while(i < j){
if(s[i++] != s[j--]){
return false;
}
}
return true;
}
};
五、合并两个有序数组 Leetcode题号:88 难度:easy
题目描述:
思路:两个指针index1和index2,初始时分别指向nums1数组和nums2数组的末尾,另开辟一个指向合并后的nums1数组的指针mergeIndex,初始时指向nums1末尾,然后将两个数组都归并到第一个数组中,需要注意的是,这里的归并选取的是两个数中较大的那个,过程中可能出现如下几种情况:
1)index1<0:说明nums1中已没有可以继续归并的元素,只需将nums2中剩下的元素依次存到归并后的nums1中
2)index2<0:说明nums2中已没有可以继续归并的元素,只需将nums1中剩下的元素依次存到归并后的nums1中
3)nums1[index1] < nums2[index2]:此时需将nums2[index2]存入归并后的nums1中,并将index2与mergeIndex2减一
4)nums1[index1] >= nums2[index2]:此时需将nums1[index1]存入归并后的nums1中,并将index1与mergeIndex2减一
代码如下:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int index1 = m - 1;
int index2 = n - 1;
int mergeIndex = m + n - 1;
while(index1 >= 0 || index2 >= 0){
if(index1 < 0){
nums1[mergeIndex--] = nums2[index2--];
} else if(index2 < 0){
nums1[mergeIndex--] = nums1[index1--];
} else if(nums1[index1] < nums2[index2]){
nums1[mergeIndex--] = nums2[index2--];
} else{
nums1[mergeIndex--] = nums1[index1--];
}
}
}
};
时间复杂度:O(n) 空间复杂度:O(m+n-1)
六、判断链表是否存在环 Leetcode题号:141 难度:easy
题目描述:
思路:使用快慢指针,快指针每次走两步,慢指针每次走一步,当进入环后,重复上述过程,二者必定会重合(因为每次距离减1),若走到了头,则证明链表无环
代码如下:
/**
* 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) {
ListNode *fast=head;
ListNode *slow=head;
while(fast!=NULL&&slow!=NULL){
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
break;
}
}
if(fast==NULL||fast->next==NULL){
return false;
}
return true;
}
};
七、最长子序列 Leetcode题号:524 难度:medium
题目描述:
思路:
首先通过双指针的思想来判断一个串是否为给定串的子串,i指针初始时指向主串s的第一个字符,j指针初始时指向子串target的第一个字符,依次遍历s和target,每走一步i都加一,若s[i]==target[j],则j加一,最后若j==target.size(),则说明可以通过删除s中的字符来得到子串target
然后通过一个max_length变量来记录最长子串的长度,对字典中的串按字典序排序,依次遍历字典中的串,只有当前串是s的子串且当前串的长度大于原来的最长字串长度时,才更新最长字串和长度,这样遍历结束后,得到的就是长度最大且字典序最小的子串
代码如下:
class Solution {
public:
string findLongestWord(string s, vector<string>& d) {
sort(d.begin(),d.end());
string longestWord = "";
int max_length = 0;
for(string target : d){
if(isSubstr(s, target) && target.size() > max_length){
longestWord = target;
max_length = target.size();
}
}
return longestWord;
}
bool isSubstr(string s,string target){
int i = 0 , j = 0;
while(i < s.size() && j < target.size()){
if(s[i] == target[j]){
j++;
}
i++;
}
return j == target.size();
}
};
时间复杂度:O(mn) 空间复杂度:O(1)