栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【算法】双指针

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【算法】双指针

双指针

 双指针算法,是一种非常常见的 O(n) 时间复杂度的算法,也正因时间复杂度的优势常见于中等难度的算法题目中。

 其特点为:两个下标通常为i和j 。

 其算法又可细分为:相向型指针、背向型指针和同向型指针。

相向指针

 相向型双指针题目即:两个下标从两端往中间趋近。

  • 判断回文串

    bool isPalidrome(string s)
    {
        int l = 0, r = s.length() - 1;
        while(l < r)
        {
            if(s[l++] != s[r--])
                return false;
        }
        return true;
    }
    
  • 两数之和

    给定一个数组求对应元素之和为sum的两个元素的下标(双指针入门题目)。

    pair towSum(vector a, int sum)
    {
        sort(a.begin(), a.end());
        int i = 0, j = a.size() - 1;
        pairp;
        while(i < j)
        {
            if(a[i] + a[j] > sum) { // 和大于sum右指针自减
                j--;
            }
            else if(a[i] + a[j] < sum) { // 和小于sum左指针自增
                i++;
            }
            else {
                p.first = i;
                p.second = j;
                return p;
            }
        }
        return p;
    }
    
背向指针

 背向型指针即基于中心线向左右展开,与相向型指针刚好相反。最典型的题目是最长对称子串。

int longestPalidrome(string s)
{
    int len = s.length(), max_l = 1, l, r, ans;
    for(int i = 0; i < len; i++)
    {
        //串长为奇数
        l = i - 1, r = i + 1, ans = 1;
        while(l >= 0 && r < len && s[l--] == s[r++]) ans += 2;
        max_l = max(max_l, ans);
        
        //串长为偶数
        l = i, r = i + 1, ans = 0;
        while(l >= 0 && r < len && s[l--] == s[r++]) ans += 2;
        max_l = max(max_l, ans);
    }
    
    return max_l;
}
同向指针

 快慢指针在动态维护一个窗口
 标签:动态解窗口 连续子段 最短最长

  • 剑指Offer II 008. 和大于等于 target 的最短子数组

    题意描述:给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和≥target的长度最小的连续子数组返回其长度。如果不存在符合条件的子数组,返回 0 。

    int minSubArrayLen(int target, vector nums) {
            int l = 0, r = 0, len = INT_MAX, n = nums.size();
            int sum = 0;
            while(l <= r && l < n)
            {
                while(r < n && sum < target){
                    sum += nums[r++];
                }
                if(sum >= target) len = min(len, r - l);
                sum -= nums[l++];
            }
            if(len == INT_MAX) return 0;
            return len;
    }
    
  • 1375 · 至少K个不同字符的子串

    题意描述:给定一个仅包含小写字母的字符串 S。返回 S 中至少包含 k 个不同字符的子串的数量。

    long long kDistinctCharacters(string s, int k)
    {
        int l = 0, r = 0, sum = 0, index;
        int n = s.length(), cnt[26] = {0};
        long long ans = 0;
        while(l <= r && l < n)
        {
            // 统计当前不同的字符数
            while(r < n && sum != k) {
                index = s[r++] - 'a';
                if(!cnt[index]) sum++;
                cnt[index]++;
            }
            //统计字串个数
            if(sum == k) ans += n - r + 1;
    
            index = s[l++] - 'a';
            cnt[index]--;
            if(!cnt[index]) sum--;
        }
        return ans;
    }
    
  • 剑指 Offer 48. 最长不含重复字符的子字符串

    请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

    int lengthOfLongestSubstring(string s) {
            int l = 0, r = 0, n = s.length(), cnt[300] = {0}, ind = 0;
            int ans = 0;
            while(l <= r && l < n)
            {
                while(r < n){
                    ind = s[r];
                    if(cnt[ind]) break;
                    cnt[ind]++;
                    r++;
                }
                ans = max(ans, r - l);
    
                ind = s[l++];
                cnt[ind]--;
            }
    
            return ans;
    }
    
  • 386 · 最多有k个不同字符的最长子字符串

    题意描述:给定字符串S,找到最多有k个不同字符的最长子串T。

    int lengthOfLongestSubstringKDistinct(string s, int k) {
            int l = 0, r = 0, n = s.length(), sum = 0, indx = 0;
            int cnt[300] = {0}, ans = 0;
    
            while(l <= r && l < n)
            {
                while(r < n && sum <= k) {
                    indx = s[r++];
                    if(!cnt[indx]) sum++;
                    cnt[indx]++;
            	}
    
                if(sum > k)
                    ans = max(ans, r - l -1);
                else
                    ans = max(ans, r - l);
    
                indx = s[l++];
                cnt[indx]--;
                if(!cnt[indx]) sum--;
         	}
    
            return ans;
    }
    
  • leet code 76. 最小覆盖子串

    提议描述:给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。注意t中字符可能重复,要求字符种类及个数均被涵盖。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

    // 判断是否个数和种类完全覆盖
    bool check(set &s, int cnt_t[], int cnt_sub[])
    {
        for(auto item : s) {
            if(cnt_sub[item] < cnt_t[item])
                return 0;
        }
        return 1;
    }
    
    string minWindow(string s, string t) {
        set set_t(t.begin(), t.end());
    
        int l = 0, r = 0, ans = INT_MAX, n = s.length(), indx;
        int cnt_t[300] = {0}, cnt_sub[300] = {0};
        //统计t串字符
        for(auto item : t) cnt_t[item]++;
    
        string str = "";
    
        while(l <= r && l < n)
        {
            // 维护了一个包含t中所有字符的子串
            while(r < n && !check(set_t, cnt_t, cnt_sub) ) {
                indx = r++;
                cnt_sub[s[indx]]++;
            }
    
            if(check(set_t, cnt_t, cnt_sub) && r - l < ans) {
                ans = r - l;
                str = s.substr(r - ans, ans);
            }
    
            indx = l++;
            cnt_sub[s[indx]]--;
        }
        return str;
    }
    
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/935273.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号