博客园  :: 首页  :: 新随笔  :: 管理

9.双指针

Posted on 2021-03-29 21:34  wsg_blog  阅读(145)  评论(0编辑  收藏  举报

Index LeetCode

双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延伸到多个数组的多个指针
若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域即为当前的窗口),经常用于区间搜索;
若两个指针指向同一数组,但是遍历方向相反,则可以用来进行搜索,待搜索的数组往往是排好序的。

BM87. 合并两个有序数组(188.合并两个有序数组)[easy]

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]

void merge(vector<int>& nums1, int m, vector<int>& nums2, int n){
  int l1=m-1, l2=n-1, k=m+n-1;
  while(l1>=0 && l2>=0){
    if(nums1[l1] > nums2[l2]){
      nums1[k--]=nums1[l1--];
    }else{
      nums1[k--]=nums2[l2--];
    }
  }
  while(l2>=0){
    nums1[k--]=nums2[l2--];
  }
}
BM88. 判断是否为回文字符串(125.验证回文串)[easy]

输入:"race a car"
输出:false

bool isPalindrome(string s){
  string tmp;
  for(char c:s){
    if(islower(c) || isdigit(c)) tmp+=c;
    else if(isupper(c)) tmp+=tolower(c);
  }
  int left=0, right=tmp.size()-1;
  while(left < right){
    if(tmp[left++] != tmp[right--])
      return false;
  }
  return true;
}
BM89. 合并区间(56.合并区间)[medium]

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]

//leetcode
vector<vector<int>> merge(vector<vector<int>>& intervals){
  int n=intervals.size();
  if(n==1) return intervals;
  vector<vector<int>> res;
  sort(intervals.begin(), intervals.end());
  for(int i=0; i<n; i++){
    int start=intervals[i][0], end=intervals[i][1];
    while(i<n-1 && end>=intervals[i+1][0]){
      end=max(end, intervals[i+1][1]);
      i++;
    }
    res.push_back({start, end});
  }
  return res;
}

//牛客
static bool cmp(Interval& a, Interval& b){
  return a.start < b.start;
}
vector<Interval> merge(vector<Interval> &intervals) {
  if(intervals.size()==0) return intervals;
  vector<Interval> res;
  sort(intervals.begin(), intervals.end(), cmp);
  res.push_back(intervals[0]);
  for(int i=1; i<intervals.size(); i++){
    if(res.back().end >= intervals[i].start){
      res.back().end=max(res.back().end, intervals[i].end);
    }else{
      res.push_back(intervals[i]);
    }
  }
  return res;
}
BM90. 最小覆盖子串(76.最小覆盖子串)[hard]

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
说明:给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""。
滑动窗口,哈希匹配

string minWindow(string S, string T){
  unordered_map<int, int> hash;
  for(char c:T) hash[c]++;
  int left=0, cnt=0, minlen=s.size()+1, start=left;
  for(int i=0; i<S.size(); i++){
    if(--hash[S[i]] >= 0) cnt++;  //覆盖计数
    while(cnt == T.size()){
      if(minlen > i-left+1){  //计算最小覆盖
        minlen=i-left+1;
        start=left;
      }
      if(++hash[S[left]] > 0) cnt--;  //S[left]是否包含T中字符
      left++;
    }
  }
  return minlen==S.size()+1 ? "":S.substr(start, minlen);
}
BM91. 反转字符串(344.反转字符串)[easy]

输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]

void reverseString(vector<char>& s){
  int left=0, right=s.size()-1;
  while(left<right){
    swap(s[left], s[right]);
    left++;
    right--;
  }
}
BM92. 最长无重复子数组(3.无重复字符的最长子串)[medium]

输入:s = "abcabcbb"
输出:3
滑动窗口,哈希匹配

int lengthOfLongSubstring(string s){
  if(s.size()==0) return 0;
  unordered_map<char, int> hash;
  int maxlen=0, left=0;
  for(int i=0; i<s.size(); i++){
    hash[s[i]]++;    //窗口右移进入哈希表统计出现次数
    while(hash[s[i]] > 1){  //出现次数大于1,有重复数据
      hash[s[left++]]--;  //窗口左移,同时减去该数字出现的次数
    }
    maxlen=max(maxlen, i-left+1);  //维护最长无重复数组
  }
  return maxlen;
}
BM93. 盛水最多的容器(11.盛水最多的容器)[medium]

输入:[1,8,6,2,5,4,8,3,7]
输出:49
双指针

int maxArea(vector<int>& height){
  int left=0, right=height.size()-1,res=0;
  while(left<right){
    res=max(res, min(height[left], height[right])*(right-left));
    if(height[left] < height[right]) left++;
    else right--;
  }
  return res;
}
BM94. 接雨水问题(42.接雨水)[hard]

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)
双指针

int trap(vectro<int>& height){
  int left=0, right=height.size()-1, maxL=0, maxR=0, res=0;
  while(left < right){
    maxL=max(maxL, height[left]);  //每次维护往中间的最大边界
    maxR=max(maxR, height[right]);
    if(maxR > maxL)  //较短的边界确定该格子的水量
      res+=maxL - height[left++];
    else
      res+=maxR - height[right--];
  }
  return res;
}
BM22.比较版本号(165.比较版本号)[medium]

输入:version1="1.01",version2="1.001"
输出:0
双指针,分段比较

int compareVersion(string version1, string version2){
  int i=0,j=0;
  while(i<version1.size() || j<version2.size()){
    int a=0,b=0;
    while(i<version1.size() && version1[i]!='.') a=a*10+(version1[i++]-'0');
    while(j<version2.size() && version2[j]!='.') b=b*10+(version2[j++]-'0');
    if(a>b) return 1;
    if(b>a) return -1;
    i++,j++;  //跳过点
  }
  return 0;
}
BM54.三数之和(15.三数之和)[medium]

输入:nums=[-1,0,1,2,-1,-4] 找出三个数a,b,c;使得a+b+c=0
输出:[[-1,-1,2],[-1,0,1]]
*排序+双指针+去重

vector<vector<int>> threeSum(vector<int>& nums){
  vector<vector<int>> res;
  if(nums.size() < 3) return res;
  sort(nums.begin(), nums.end());
  for(int i=0; i<nums.size()-2; i++){
    if(nums[i]+nums[i+1]+nums[i+2] > 0) return res;
    if(i>0 && nums[i]==nums[i-1]) continue;  //去重
    int left=i+1,right=nums.size()-1;
    while(left < right){
      if(num[left]+nums[right] == -nums[i]){
          res.push_back({nums[i], nums[left], nums[right]});
          while(left<right && nums[left]==nums[left+1]) left++;
          while(left<right && nums[right]==nums[right-1]) right--;
          left++;
          right--;
      }else if(nums[left]+nums[right] > -nums[i]){
        right--;
      }else{
        left++;
      }
    } 
  }
  return res;
}