双指针

一、 两数之和 II ——输入有序数组                Leetcode题目号:167   难度:easy

题目描述:

思路:

设置双指针low和high,分别指向两个数中的较小数和较大数,low从数组第一个元素开始,high从数组最后一个元素开始,分为以下三种情况:

  1. num[low] + num[high] == target  即找到了满足题目的两个元素,但由于题目要求下标从1开始,故将low和high都加1后存入答案数组,直接退出循环,返回答案即可。
  2. num[low] + num[high] < target    此时需要使两数之和变小,只需low指针加一,high指针不需要动
  3. 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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值