title: LC101の2. 双指针
urlname: bnq65f
date: ‘2021-05-13 14:06:0’
tags: [双指针]
categories: [算法刷题]
算法解释
顾名思义,通过两个指针遍历数组,协同完成任务。
遍历方向相同且不会相交的,可称为滑动窗口。
遍历方向相反,则可以用来搜索。
Two Sum
[167] Two Sum II - Input array is sorted
题目描述:找到和为定值的两个数
输入输出:Input: numbers = [2,7,11,15], target = 9 Output: [1,2]
题解:在头尾处用两个指针往中间遍历,如果和小了,左指针右移,反之右指针左移。
代码:
vector<int> twoSum(vector<int>& numbers, int target) {int begin = 0,end = numbers.size() - 1;while(begin < end){int sum = numbers[begin] + numbers[end];if(sum == target)break;else if(sum > target)end--;else begin++;}return vector<int>{begin + 1, end + 1};}
归并两个有序数组
[88] Merge Sorted Array
题目描述:将第二个数组合并到第一个上。
输入输出:Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 Output: [1,2,2,3,5,6]
题解:从尾巴开始添加,对比 num1 和 num2 的末尾哪个更小,从后往前遍历。
代码:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int k = m + n - 1;while(m > 0 && n > 0){nums1[k--] = nums1[m - 1] > nums2[n - 1]? nums1[--m]: nums2[--n];}while(n > 0){nums1[k--] = nums2[--n];}}
快慢指针
[142] Linked List Cycle II
题目描述:给定一个链表,有环路返回开始点,否则返回空指针。
输入输出:Input: head = [3,2,0,-4], pos = 1 Output: tail connects to node index 1
题解:链表找环路通用解法-快慢指针(Floyd 判圈法):
代码:Floyd 判圈法可列数学式子推导而出。【参考链接】
ListNode *detectCycle(ListNode *head) {ListNode *slow = head, *fast = head;do{if(!fast || !fast->next)return NULL;fast = fast->next->next;slow = slow->next;}while(fast != slow);fast = head;while(fast != slow){fast = fast->next;slow = slow->next;}return fast;}
滑动窗口
[76] Minimum Window Substring
题目描述:字符串 S 和 T,求 S 中包含 T 所有字符最短连续子串长度,时间复杂度不超过 O(n)
输入输出:Input: s = “ADOBECODEBANC”, t = “ABC” Output: “BANC”
题解:
代码:(参考答案)
string minWindow(string s, string t) {int cnt = t.size(), k = 0;vector<int> num(128,0);vector<bool> flag(128,false);for(int i = 0; i < cnt; i++){flag[t[i]] = true;num[t[i]]++;}int l = 0, m_l = 0, m_len = s.size() + 1;for(int r = 0; r < s.size(); r++){if(flag[s[r]]){if(num[s[r]]-- > 0)k++;while(k == cnt){if(r - l + 1 < m_len){m_len = r - l + 1;m_l = l;}if(flag[s[l]] && ++num[s[l]] > 0){k--;}l++;}}}return m_len > s.size()? "": s.substr(m_l, m_len);}
练习
[633] Sum of Square Numbers
题目描述:输入一个数 c,是否存在 a,b 平方和为 c
输入输出:Input: c = 5 Output: true
题解:使用头尾双指针,数据过大需要使用 long
代码:
bool judgeSquareSum(int c) {long l = 0, r = (int)sqrt(c);int flag = false;while(l <= r){long sum = l * l + r * r;if(sum > c){r--;}else if(sum < c){l++;}else{flag = true;break;}}return flag;}
[680] Valid Palindrome II
题目描述:是否可以删除最多一个字符使输入串为回文串
输入输出:Input: s = “abca” Output: true
题解:双指针,遍历冲突时处理删左和删右两种情况
代码:(参考答案)
bool validPalindrome(string s) {int l = 0, r = s.size() - 1;while(l <= r){if(s[l] != s[r]){int i1 = l, j1 = r - 1,i2 = l + 1, j2 = r;while (i1 < j1 && s[i1] == s[j1]) {i1++; j1--;};while (i2 < j2 && s[i2] == s[j2]) {i2++; j2--;};return i1 >= j1 || i2 >= j2;}l++;r--;}return true;}
[524] Longest Word in Dictionary through Deleting
题目描述:字符串 s 和字符串数组 d,找出,可以由 s 删除部分字符得到的 d 中最长字符串,若一样长取字符串小的。
输入输出:Input: s = “abpcplea”, dictionary = [“ale”,”apple”,”monkey”,”plea”] Output: “apple”
题解:暴力。
代码:
string findLongestWord(string s, vector<string>& d) {int max_l = 0;string max_s = "";for(int i = 0; i < d.size(); i++){//比较s,d[i]int j = 0, k = 0;for(; k < s.size(); k++){if(d[i][j] == s[k])j++;}if(j == d[i].size()){if(d[i].size() > max_l){max_l = d[i].size();max_s = d[i];}else if(d[i].size() == max_l && max_s > d[i]){max_s = d[i];}}}return max_s;}
