算法基础 典型题(七)哈希表 与 字符串

记录算法基础题思路:

step1

最长回文长度:https://leetcode-cn.com/problems/longest-palindrome/submissions/

给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。

    int longestPalindrome(string s) {
        /* 利用hash表统计全部字符数量,然后遍历每一个字符 
            如果为偶数length+=count, 
            如果为奇数length+=count-1, 并且置位中心数flag=1,
            最终结果位length+flag*/
        int c_map[256] = { 0 };
        int center_flag = 0;
        int length = 0;
        for (int i = 0; i < s.length(); i++) {
            c_map[s[i]]++;
        }
        for (int i = 0; i < 256; i++) {
            if (c_map[i] % 2 == 0) {
                length += c_map[i];
            } else {
                length += c_map[i] - 1;
                center_flag = 1;
            }
        }
        return length + center_flag;
    }

词语模式匹配:https://leetcode-cn.com/problems/word-pattern/submissions/

给定一种规律 pattern 和一个字符串 str ,判断 str 是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。

    bool wordPattern(string pattern, string str) {
        /* 遍历字符串,建立一个str单词和pattern字符的hash表,
            并且记录pattern中字符的使用状态,
            如果出现一个表项建立过程对应字符已被使用,校验失败*/
        bool c_used[256] = { 0 };
        map <string, char> word_map;
        string word;
        int pos = 0;
        str += ' ';//追加一个尾部空格,可以简化遍历条件
        for (int i = 0; i < str.size(); i++) {
            if (str[i] != ' ') {
                word += str[i];
            } else {
                if (pos == pattern.length()) {
                    return false; //pattern长度不匹配
                }
                /* 获取到一个单词,单词表项没有就尝试建立表项 */
                if(word_map.find(word) == word_map.end()) {
                    if (c_used[pattern[pos]] == true) {
                        return false; //对应字符位已经被占用,不能再映射
                    }
                    word_map[word] = pattern[pos];
                    c_used[pattern[pos]] = true;
                } else {
                    if (word_map[word] != pattern[pos]) {
                        return false;//word已经构建hash表项,但映射的key值和当前不同
                    }
                }
                pos++;
                word = "";
            }
        }
        if (pos != pattern.length()) {
            return false; //pattern长度不匹配
        }
        return true;
    }

anagram分组:https://leetcode-cn.com/problems/group-anagrams/submissions/

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]

public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        /* 每个字符串单元排序结果作为key值,建立map字典,相同key追加到字典中 */
        map<string, vector<string>> dict;
        vector<vector<string>> res;
        for (auto s : strs) {
            string key = s;
            sort(key.begin(),key.end());
            dict[key].push_back(s);
        }
        for (auto it: dict) {
            res.push_back(it.second);
        }
        return res;
    }

无重复字符最长子串:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/submissions/

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度
示例:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
 

    int lengthOfLongestSubstring(string s) {
        /*  滑动窗口典型题
            使用双指针start/end记录窗口边界,使用一个map记录当前滑动窗口内包含的字符,
            滑动窗口右边界往后移动,比较每一个刚好要出现重复字符时,判断max_len是否要更新,
            左边界移动,使窗口重新回到不存在重复字符的场景,然后继续右边界滑动。。。
        */
        int start_pos = 0, end_pos = 0;
        int max_len = 0;
        char c_map[256] = { 0 };
        int size = s.size();
        while (end_pos < size && start_pos < size) {
            /*滑块尾部往后移动 并在map中置位, 直到遇到某个字符已经存在与map中 */
            while (end_pos < size && c_map[s[end_pos]] == 0) {
                c_map[s[end_pos]] = 1;
                end_pos++;
            }
            /* 更新当前长度 */
            if (end_pos - start_pos > max_len) {
                max_len = end_pos - start_pos;
            }
            /*移动滑块前start面,直到end_pos所在字符出块*/
            while (start_pos < size && s[start_pos] != s[end_pos]) {
                c_map[s[start_pos]] = 0;
                start_pos++;
            }
            start_pos++;
            end_pos++;
        }
        return max_len;
    }

重复DNA序列:https://leetcode-cn.com/problems/repeated-dna-sequences/solution/

所有 DNA 都由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。
编写一个函数来查找 DNA 分子中所有出现超过一次的 10 个字母长的序列(子串)。

    vector<string> findRepeatedDnaSequences(string s) {
        /* 枚举每个10字符子串,插入map表中并累加计数,
           最后遍历一次map */
        map <string , int> word_map;
        vector<string> res;
        for (int i = 0; i < s.length(); i++) {
            string word = s.substr(i, 10);
            word_map[word]++;
        }
        map <string , int> :: iterator it;
        for (it = word_map.begin(); it != word_map.end(); it++) {
            if (it->second > 1) {
                res.push_back(it->first);
            }
        }
        return res;
    }

最小覆盖子串:https://leetcode-cn.com/problems/minimum-window-substring/submissions/

给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。

public:
    string minWindow(string s, string t) {
        /* 滑动窗口 典型题
            left right表示窗口边界,map_t表示t的字符映射计数,map_s表示窗口中字符映射计数
            先right向后移动,直到s包含t,然后移动left直到s不包含t,刷新lengh_min, 记录res,
            继续right向后移动直到s包含t。。。直到right走到末尾最后一次移动left更新res */
        int map_s[128] = {0};
        int map_t[128] = {0};
        for (int i = 0; i < t.length(); i++) {
            map_t[t[i]]++;
        }
        int left = 0;
        int right = 0;
        int min_length = 0;
        string res;
        for (right = 0;right < s.size(); right++) {
            map_s[s[right]]++;
            /* 移动right找到第一个包含t的窗口 */
            while ((is_win_ok(map_s, map_t) == false) && right < s.size() - 1) {
                right++;
                map_s[s[right]]++;
            }
            if (is_win_ok(map_s, map_t) == false) {
                return res; //始终无法找到一个包含点
            }
            /* 找到包含窗口开始移动left找当前right下最小窗口 */
            while (is_win_ok(map_s, map_t) == true) {
                map_s[s[left]]--;
                left++;
            }
            /* 刷新min_length和res */
            if (min_length == 0) {
                min_length = right - left + 2;//注意left此时已经超过了满足win包含的位置
                res = s.substr(left - 1, min_length);
            } else {
                if (min_length > right - left + 2) {
                    min_length = right - left + 2;
                    res = s.substr(left - 1, min_length);
                }
            }
        }
        return res;
    }
private:
    bool is_win_ok(int map_s[128], int map_t[128]) {
        for (int i = 0; i < 128; i++) {
            if (map_t[i] > map_s[i]) {
                return false;
            }
        }
        return true;
    }

猜你喜欢

转载自blog.csdn.net/runafterhit/article/details/105896085
今日推荐