专题复习:双指针(1) 滑动窗口(前提是:有序数组)

leetcode 1423. 可获得的最大点数

 

思路:由于必须包含数组的首元素或者尾部元素。可以采用在数组的两端来滑动。

1423.gif

 代码如下,首先,sum为数组中前k个元素之和,然后,窗右边往左划,tempsum - 出窗的元素,窗左边往左滑,到数组的末尾,tempSum + 进窗的元素,一直到窗中不包含首位元素或者末尾元素。

class Solution {
public:
    int maxScore(vector<int>& cardPoints, int k) {
        int sum = 0;
        int size = cardPoints.size();
        for(int i = 0; i < k; i++)
        {
            sum += cardPoints[i];
        }
        int tempSum = sum;
        for(int i = k - 1; i >= 0; i--)
        {
            tempSum -= cardPoints[i];
            tempSum += cardPoints[size - (k - i)];
            sum = max(sum, tempSum);
        }
        return sum;

    }
};

leetcode26. 删除有序数组中的重复项

注意:不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成

思路:将数组中出现的元素按顺序放在数组的首部,效果如下:

原数组 nums = [0,0,1,1,1,2,2,3,3,4]

效果后:nums =[0,1,2,3,4,2,2,3,3,4] 

双指针:left = 0, right = 1,如果nums[right] != nums[left]    { left++; nums[left] = nums[right];}

如果 nums[right] == nums[left]  right++; 最后,return left+1;

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int size = nums.size();
        if(size == 0) return 0;
        int left = 0, right = 1;
        for(right = 1; right < size; right++)
        {
            if(nums[right] != nums[left])
            {
                nums[++left] = nums[right];
            }
        }
        return left+1;
        
    }
};

剑指 Offer 57 - II. 和为s的连续正数序列

利用滑窗, left和right 表示连续数组的范围

class Solution {
public:
    vector<vector<int>> findContinuousSequence(int target) {
        if(target == 1) return {{1}};
        vector<vector<int>> res;
        if(target == 2) return res;
        int left = 1, right = 2;
        int sum = left + right;
        while(left <= target/2)
        {
            if(sum == target)
            {
                vector<int> temp;
                for(int i = left; i <= right; i++) 
                {
                    temp.push_back(i);
                }
                res.push_back(temp);
            }
            if(sum >= target)
            {
                sum -= left;
                left++;
            }
            else
            {
                right++;
                sum += right;
            }
        }
        return res;

    }
};

leetcode 349. 两个数组的交集

跟下一题一致,只不过 做了去重复操作

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        int size1 = nums1.size(), size2 = nums2.size();
        vector<int> res;
        if(size1 == 0 || size2 == 0)  return res;
        sort(nums1.begin(), nums1.end());
        sort(nums2.begin(), nums2.end());
        int left = 0, right = 0;
        while(left < size1 && right < size2)
        {
            if(nums1[left] < nums2[right]) left++;
            else if(nums1[left] > nums2[right]) right++;
            else
            {
                res.push_back(nums1[left]);
                left++;
                while(left < size1 && nums1[left] == nums1[left-1]) left++;
                right++;
                while(right < size2 && nums2[right] == nums2[right-1]) right++;
            }
        }
        return res;
    }
};

leetcode350. 两个数组的交集 II

首先,将两个数组排序,然后,利用双指针,分别遍历两个数组。

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        sort(nums1.begin(), nums1.end());
        sort(nums2.begin(), nums2.end());
        vector<int> res;
        int size1 = nums1.size();
        int size2 = nums2.size();
        if(size1 == 0 || size2 == 0) return res;
        int i = 0, j =0;//用i作为索引遍历nums1 用j作为索引遍历nums2
        while(i < size1 && j < size2)
        {
            if(nums1[i] > nums2[j]) j++;
            else if(nums1[i] < nums2[j]) i++;
            else
            {
                res.push_back(nums1[i]);
                i++;
                j++;
            }
        }
        return res;
    }
};

 leetcode 424. 替换后的最长重复字符

比较难想到,利用map记录出现次数最多的字符及次数

class Solution {
public:
    int characterReplacement(string s, int k) {
        int size = s.length();
        if(size <= 1) return size;

        unordered_map<char ,int> a;
        int maxSameCount = 0;
        int maxWindow = 0;
        int left = 0, right = 1;
        a[s[left]]++;
        for(;right < size; right++)
        {
            a[s[right]]++;
            maxSameCount = max(maxSameCount, a[s[right]]);
            if(maxSameCount + k < right - left + 1)
            {
                a[s[left]]--;
                left++;
            }
            else
            {
                maxWindow = max(maxWindow, right -left + 1);
            }
        }
        return maxWindow;

    }
};

leetcode125. 验证回文串

大写字符转换为小写字符 调用函数tolower   小写字符转换为大写字符 调用函数toupper

class Solution {
    bool isValid(char a)
    {
        if( a >='0'&& a <= '9' || a >= 'a'&& a <= 'z' || a >= 'A'&&a <= 'Z' )
        {
            return true;
        }
        return false;
    }
public:
    bool isPalindrome(string s) {
        int len = s.length();
        if(len <= 1) return true;

        int left = 0; int right = len - 1;
        while(left <= right)
        {
            if( isValid(s[left]) && isValid(s[right]))
            {

                if( tolower(s[left]) == tolower(s[right]))
                {
                    left++;
                    right--;
                }
                else
                {
                    return false;
                }
            }
            else if(!isValid(s[left]) && isValid(s[right])) left++;
            else if(isValid(s[left]) && !isValid(s[right])) right--;
            else
            {
                left++;
                right--;
            }
        }
        return true;
    }
};

leetcode109. 有序链表转换二叉搜索树

思路:将链表从中间分隔成两段,然后利用递归

利用快慢指针,找到链表中间节点

class Solution {
public:
    TreeNode* sortedListToBST(ListNode* head) {
        if(!head) return nullptr;
        if(!head->next) return new TreeNode(head->val);
        ListNode* slow = head, *fast = head, *pre = nullptr;
        //这里通过快慢指针找到链表的中间结点slow,pre就是中间
       //结点slow的前一个结点
        while(fast && fast->next)
        {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        pre->next = nullptr;//将链表分隔为两部分
        //slow是链表的中间节点
        TreeNode* root = new TreeNode(slow->val);
        root->left = sortedListToBST(head);
        root->right = sortedListToBST(slow->next);
        return root;
    }
};

leetcode61. 旋转链表

思路:先把链表整成环, 另外,由于k可能大于链表的长度,因此有必要计算出链表的长度。

当k > len时,即相当于往右移动k%len个位置。最后,需要将之前的环形链表截断。

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(!head) return head;
        ListNode *fast = head, *slow = head;
        int len = 1;
        //计算链表的长度
        while(fast->next)
        {
            len++;
            fast = fast->next;
        }
        fast->next = head;//将链表构成环

        //还需要将环形链表截断
        int step = k%len; //当k大于len时,实际上相当于向右移动k%len个位置
        //向右移step个位置,即需要在链表的第len - step个节点之前截断,因此,需要找到
        // 第len - step - 1个节点
        int k1 = len - step - 1;
        while((k1--)>0)
        {
            slow = slow->next;
        }
        ListNode *newHead = slow->next;
        slow->next =nullptr;
        return newHead;
    }
};

leetcode 3. 无重复字符的最长子串

思路:利用set set.insert(3)   erase(3)     set.find(3) != set.end()

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = s.length();
        if(len <= 1) return len;
        int maxLen = 0;
        set<char> a;
        int left = 0;
        a.insert(s[left]);
        for(int i = 1; i < len; i++)
        {
            while(a.find(s[i]) != a.end())
            {
                a.erase(s[left]);
                left++;
            }
            a.insert(s[i]);
            maxLen= max(maxLen, i - left + 1);
        }
        return maxLen;
    }
};

方法二:直接利用数组m 记录一个字母如果后面出现重复时,left 应该调整到的新位置

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        vector<int> m(128,0);//m 记录一个字母如果后面出现重复时,left 应该调整到的新位置
        int left = 0;
        int maxLen = 0;
        for(int right = 0; right < s.length();right++)
        {
            if(m[s[right]] > 0)
            {
                left = max(left, m[s[right]]);//注意,此时要取最大的left 
                                              //比如"abba" 当取到第二个a时,此时的left是为2 不应该是 m[a]即1
            }
            m[s[right]] = right + 1; 
            maxLen = max(maxLen, right - left + 1);
        }
        return maxLen;
    }
};

leetcode11: 11. 盛最多水的容器

左指针left为0 右指针left为len -1

遍历方式:nums[left] < nums[right] left++; 否则,right++

class Solution {
public:
    int maxArea(vector<int>& height) {
        int len = height.size();
        int left = 0, right = len - 1;
        int maxArea = 0;
        while(left < right)
        {
            int areaTemp = (right - left)*min(height[right] , height[left]);
            maxArea = max(maxArea, areaTemp);
            if(height[left] < height[right]) left++;
            else right--;
        }
        return maxArea;
    }
};

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值