双指针法001

数组:移除元素
字符串:反转字符串
字符串:替换空格
字符串:翻转字符串里的单词
链表:翻转链表
链表:删除链表的倒数第 N 个结点
链表:链表相交
链表:环形链表
双指针:三数之和
双指针:四数之和

三角形个数

给定一个整数数组,在该数组中,寻找三个数,分别代表三角形三条边的长度,问,可以寻找到多少组这样的三个数来组成三角形?

class Solution {
public:
    int triangleCount(vector<int>& s) {
	int lef,right;
	int ans=0;
	sort(s.begin(),s.end());
	for(int i=0;i<s.size();i++){
		left=0;
		right=i-1;
		while(left<right){
			if(s[left]+s[right]>s[i]){
				ans+=(right-left);
				right--;
			}else{
				left++;
			}
		}
	}
	return ans;
    }
};
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            int k = i;
            for (int j = i + 1; j < n; ++j) {
                while (k + 1 < n && nums[k + 1] < nums[i] + nums[j]) {
                    ++k;
                }
                ans += max(k - j, 0); //同上面的left<right;
            }
        }
        return ans;
    }
};

k数之和

1.求方案总数
动态规划
2.求具体方案
用深度优先搜素

数组划分

给出一个整数数组 nums 和一个整数 k。划分数组(即移动数组 nums 中的元素),使得:

所有小于k的元素移到左边
所有大于等于k的元素移到右边
返回数组划分的位置,即数组中第一个位置 i,满足 nums[i] 大于等于 k。

class Solution {
public:
    int partitionArray(vector<int> &nums, int k) {
        int i = 0, j = nums.size() - 1;
        while (i <= j) {
            while (i <= j && nums[i] < k) i++;
            while (i <= j && nums[j] >= k) j--;
            if (i <= j) {
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                i++;
                j--;
            }
        }
        return i;
    }
};

交错正负数

给出一个含有正整数和负整数的数组,重新排列成一个正负数交错的数组。

class Solution {
public:
    void partition(vector<int>& nums,bool start_positive){
        int flag;
        if (start_positive){
            flag=1;
        }else{
            flag=-1;
        }

        int left=0,right=nums.size()-1;
        while(left<=right){
            while(left<=right&&nums[left]*flag>0){
                left+=1;
            }
            while(left<=right&&nums[right]*flag<=0){
                right--;
            }
            if(left<=right){
                swap(nums[left],nums[right]);
                left+=1;
                right-=1;
            }
        }
    }

        void interleave(vector<int>& nums,bool has_same_length){
            int left=1,right=nums.size()-1;
            if(has_same_length) right=nums.size()-2;
            while(left<right){
                swap(nums[left],nums[right]);
                left+=2;
                right-=2;
            }
        }

        void rerange(vector<int> &nums) {
        int positive = 0;
        int negitive = 0;
        for(auto i:nums)
        {
            if(i > 0)
                positive++;
            else
                negitive++;
        }
        partition(nums,positive>negitive);
        interleave(nums,positive==negitive);
    }

};

颜色分类

给定一个包含红,白,蓝且长度为 n 的数组,将数组元素进行分类使相同颜色的元素相邻,并按照红、白、蓝的顺序进行排序。

我们使用整数 0,1 和 2 分别代表红,白,蓝。

class Solution{
public:
    void sortColors(vector<int> &nums) {
        int left = 0, right = nums.size() - 1;
        int middle = 0;
        
        // should be <= not <
        while (middle <= right) {
            if (nums[middle] == 0) {
                swap(nums[middle], nums[left]);
                left++;
                middle++;
            } else if (nums[middle] == 1) {
                middle++;
            } else {
                swap(nums[middle], nums[right]);
                right--;
            }
        }
    }
};

彩虹排序

给定一个有n个对象(包括k种不同的颜色,并按照1到k进行编号)的数组,将对象进行分类使相同颜色的对象相邻,并按照1,2,…k的顺序进行排序。


class Solution {

public:

    void sortColors2(vector<int> &colors, int k) {

        if (colors.size() < 2) {

            return;

        }

        

        sort(colors, 0, colors.size() - 1, 1, k);

    }

    

    void sort(vector<int> &colors, int start, int end, int colorFrom, int colorTo) {

        //若处理区间长度为小于等于1或颜色区间长度为1,则不需要再进行处理

        if (start >= end || colorFrom == colorTo) {

            return;

        }

        //设置左右指针以及中间的颜色

        int left = start;

        int right = end;

        int colorMid = colorFrom + (colorTo - colorFrom) / 2;

        

        while (left <= right) {

            //找到左侧大于中间颜色的位置

            while (left <= right && colors[left] <= colorMid) {

                left++;

            }

            //找到右侧小于等于中间颜色的位置

            while (left <= right && colors[right] > colorMid) {

                right--;

            }

            //交换左右指针指向的颜色

            if (left <= right) {

                int temp = colors[left];

                colors[left] = colors[right];

                colors[right] = temp;

            }

        }

        //继续递归处理左右两半序列

        sort(colors, start, right, colorFrom, colorMid);

        sort(colors, left, end, colorMid + 1, colorTo);

    }

};

移动零

给一个数组 nums 写一个函数将 0 移动到数组的最后面,非零元素保持原数组的顺序

class Solution {
public:
    /**
     * @param nums: an integer array
     * @return: nothing
     */
    void moveZeroes(vector<int> &nums) {
        // 将两个指针先指向数组头部
        int left = 0, right = 0;
        while (right < nums.size()) {
            // 遇到非0数赋值给新数组指针指向的位置
            if (nums[right] != 0) {
                nums[left] = nums[right];
                // 将left向后移动一位
                left++;
            }
            right++;
        }

        // 若新数组指针还未指向尾部,将剩余数组赋值为0
        while (left < nums.size()) {
            nums[left] = 0;
            left++;
        }
    }
};

同向双指针

两数之差

给定一个排序后的整数数组,找到两个数的 差 等于目标值。
你需要返回一个包含两个数字的列表 [num1, num2], 使得 num1 与 num2 的差为 target,同时 num1 必须小于 num2。
保证只有一个答案。
注意:要求用O(1)空间复杂度完成。

class Solution {
public:
    vector<int> twoSum7(vector<int> &nums, int target) {
       vector<int> result;
       if(nums.size()<2){
           return result;
       }
       target=abs(target);
       int right=1;
       for(int left=0;left<nums.size();left++){
           right=max(right,left+1);
           while(right<nums.size()&&nums[right]-nums[left]<target){
               right++;
           }
           if(right>nums.size()){
               break;
           }
           if(nums[right]-nums[left]==target){
               result.push_back(nums[left]);
               result.push_back(nums[right]);
               return result;
           }
       } 
       return result;
    }
};

全零子串的数量

给出一个只包含0或1的字符串str,请返回这个字符串中全为0的子字符串的个数

class Solution {
public:
    int stringCount(string &str) {
        if(str.size()==0){
            return 0;
        }
        int right=1,answer=0;
        for(int left=0;left<str.size();left++){
            if(str[left]!='0'){
                continue;
            }
            right=max(right,left+1);
            while(right<str.size()&&str[right]=='0'){
                right++;
            }
            answer+=right-left;
        }
        return answer;
    }
};

去除重复元素

给一个整数数组,去除重复的元素。

你应该做这些事

1.在原数组上操作
2.将去除重复之后的元素放在数组的开头
3.返回去除重复元素之后的元素个数

class Solution {
public:
    int deduplication(vector<int> &nums) {
        if(nums.size()==0){
            return 0;
        }
        sort(nums.begin(),nums.end());
        int left;
        int right=1;
        for(left=0;left<nums.size();left++){
            while(right<nums.size()&&nums[left]==nums[right]){
                right++;
            }
            if(right>=nums.size()){
                break;
            }
            nums[left+1]=nums[right];
        }
        return left+1;
    }
};

滑动窗口内数的和

给你一个大小为n的整型数组和一个大小为k的滑动窗口,将滑动窗口从头移到尾,输出从开始到结束每一个时刻滑动窗口内的数的和。

class Solution {
public:
    vector<int> winSum(vector<int> &nums, int k) {
        vector<int> result;
        if(nums.size()<k||k==0){
            return result;
        }
        int right=0;
        int sum=0;
        for(int left=0;left<nums.size();left++){
            while(right<nums.size()&&right-left<k){
                sum+=nums[right];
                right++;
            }
            if(right-left==k){
                result.push_back(sum);
            }
            sum-=nums[left];
        }
        return result;
    }
};

快慢指针

带环链表

给定一个链表,判断它是否有环。

class Solution{
public:
    bool hasCycle(ListNode * head) {
        if(head==nullptr||head->next==nullptr){
            return false;
        }
        ListNode* fast=head;
        ListNode* slow=head;
        while(fast!=NULL&&fast->next!=NULL){
            fast=fast->next->next;
            slow=slow->next;
            if(slow==fast){
                while(head!=slow){
                    head=head->next;
                    slow=slow->next;
                }
                return true;
            }
        }
        return false;
    }
};
class Solution {
public:
    bool hasCycle(ListNode * head) {
        if(head==nullptr||head->next==nullptr){
            return false;
        }
        ListNode* fast=head->next;
        ListNode* slow=head;
        while(fast!=slow){
            if(fast==nullptr||fast->next==nullptr){
                return false;
            }
            fast=fast->next->next;
            slow=slow->next;
        }
        while(head!=slow->next){
            head=head->next;
            slow=slow->next;
        }
        return true;
    }
};

K次替换后的最长重复字符

给定一个仅包含大写英文字母的字符串,您可以将字符串中的任何一个字母替换为的另一个字母,最多替换k次。 执行上述操作后,找到最长的,只含有同一字母的子字符串的长度。

class Solution {
public:
    /*
    int get_max_count(unordered_map<char, int> &char2count) {
        int max_count = 0;
        for (auto it : char2count) {
            if (it.second > max_count) {
                max_count = it.second;
            }
        }
        return max_count;
    }
    */
    int characterReplacement(string &s, int k) {
        if(s.size()==0){
            return 0;
        }
        int right=0;
        int maxFreq=0;
        unordered_map<char,int> counter;
        int answer=0;
        for(int left=0;left<s.size();left++){
            while(right<s.size()&&right-left-maxFreq<=k){
                counter[s[right]]++;
                maxFreq=max(maxFreq,counter[s[right]]);
                right++;
            }
            if(right-left-maxFreq>k){
                answer=max(answer,right-left-1);
            }else{
                answer=max(answer,right-left);
            }
            counter[s[left]]--;
            //maxFreq=get_max_count(counter);
        }
        return answer;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值