LeetCode-Hash Table

(LeetCode持續更新中…)

409. Longest Palindrome(最長迴文數)

Given a string which consists of lowercase or uppercase letters, find the length of the longest palindromes that can be built with those letters.
This is case sensitive, for example “Aa” is not considered a palindrome here.
Note:
Assume the length of given string will not exceed 1,010.

Example:

Input:
“abccccdd”
Output:
7
Explanation:
One longest palindrome that can be built is “dccaccd”, whose length is 7.

解析:

字符串中找能形成最長的迴文串,有哪些字符可以加入到迴文串?
(1)出現偶數次的字符,必然可以加入迴文串;“aaaacd”->”aaaa”
(2)出現次數大於1且不是偶數,則將該其拆分成 “偶數+1”,其中偶數字符必然可以加入迴文串,”aaabb”->”abba”; 剩下的一個字符,要加入迴文串,有一個前提條件,那就是沒有“沒有 出現過1次的字符 已經加入過迴文串”,”aaabbc”->”ababa”;
(3)只出現1次的字符,能加入迴文串的前提是“沒有 出現過1次的字符 已經加入過迴文串”,“aabbcd”->”aacbb”或者”aadbb”

C++實現:

class Solution {
public:
    int longestPalindrome(string s) {
        unordered_map<char,int> table;
        for(int i=0; i<s.length(); ++i){
            table[s[i]]++;
        }
        unordered_map<char,int>::iterator it = table.begin();
        int result = 0;
        bool isOne = false; //記錄只出現過1次的字符是否加入過迴文串
        int temp = 0;
        for( ; it!=table.end(); it++){
            temp = it->second;
            if(temp%2==0)
               result +=  temp;
             else if(temp>1){
                result += temp-1;
                if(!isOne){
                    isOne = true;
                    result += 1;
                }
             }
             else if(temp==1 && !isOne){
                 result += 1;
                 isOne = true;
             }
        }
        return result;
    }
};

349. Intersection of Two Arrays(兩個數組的交集)

Given two arrays, write a function to compute their intersection.

Example:

Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2].

Note:

Each element in the result must be unique.
The result can be in any order.

解析:

(1)第一種方法,暴力法,兩個for循環,時間複雜度爲O(m*n);
(2)第二種方法,分別對兩個數組排序,然後用兩個指針指向兩個有序數組,通過移位比對,找到兩個數組的交集,時間複雜度爲O(NlogN)+O(MlogM)+O(m+n);
(3)第三種方法,用hash,推薦使用unordered_map\unordered_set,這兩個HashTable可以在常數時間內進行查找、插入、刪除元素。具體:將array1放入map,遍歷array2,判斷元素是否在map,如果在,則將該元素放入結果集,同時在map中刪除該元素(防止同一元素重複插入結果集)。

C++實現:
(1)使用unordered_set

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> table(nums1.begin(),nums1.end());
        vector<int> result;
        for(auto a:nums2){    //auto會根據初始值自動判斷變量類型
            if(table.count(a)==1){
                result.push_back(a);
                table.erase(a);
            }
        }
        return result;
    }
};

(2)使用unordered_map

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int,int> table;
        for(auto a:nums1){
            table[a] = 1;
        }
        vector<int> result;
        for(auto a:nums2){
            if(table.count(a)==1){
                result.push_back(a);
                table.erase(a);
            }
        }
        return result;
    }
};

350. Intersection of Two Arrays II(求兩個數組的交集)

Given two arrays, write a function to compute their intersection.

Example:

Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2, 2].

Note:

Each element in the result should appear as many times as it shows in both arrays.The result can be in any order.

Follow up:

What if the given array is already sorted? How would you optimize your algorithm?
What if nums1’s size is small compared to nums2’s size? Which algorithm is better?
What if elements of nums2 are stored on disk, and the memory is limited such that you cannot load all elements into the memory at once?

c++實現:

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        unordered_multiset<int> table(nums1.begin(),nums1.end());
        vector<int> result;
        for(auto a:nums2){    //auto會根據初始值自動判斷變量類型
            if(table.count(a)>0){
                result.push_back(a);
                table.erase(table.find(a));
            }
        }
        return result;
    }
};

438. Find All Anagrams in a String

Given a string s and a non-empty string p, find all the start indices of p’s anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.
The order of output does not matter.

Example 1:

Input:
s: “cbaebabacd” p: “abc”
Output:
[0, 6]
Explanation:
The substring with start index = 0 is “cba”, which is an anagram of “abc”.
The substring with start index = 6 is “bac”, which is an anagram of “abc”.

Example 2:

Input:
s: “abab” p: “ab”
Output:
[0, 1, 2]
Explanation:
The substring with start index = 0 is “ab”, which is an anagram of “ab”.
The substring with start index = 1 is “ba”, which is an anagram of “ab”.
The substring with start index = 2 is “ab”, which is an anagram of “ab”.

解析:

(1)方法一:將字符串s切割成長度爲|p|的子串,對比子串和p中的字符,時間複雜度爲O(N*N);
(2)方法二:將字符串p的字符放入hash表,定義兩個指針left和right,初始指向s的第一個字符,count設爲p的長度,然後每次向右移動right指針,判斷s[right]是否在hash表中,如果在,則count減一,當count==0時,表明left開頭的子串是p的變形,將left加入結果集中,然後left向右移動,循環指導right指向s的末尾。

C++實現:

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
         vector<int> result;
        if(s.length()==0 || p.length()==0 || s.length()<p.length())
            return result;
        int hash[256];          //最多有256個字符
        for(int i=0; i<256; ++i)
            hash[i] = 0;
        for(auto a : p)
            hash[a]++;
        int left=0, right=0, count=p.length();
        while(right<s.length()){
            //move right everytime, if the character exists in p's hash, decrease the count
           //current hash value >= 1 means the character is existing in p
            if(hash[s[right++]]-- >0)
                count--;
            //when the count is down to 0, means we found the right anagram
            //then add window's left to result list    
            if(count==0)
                result.push_back(left);
            //if we find the window's size equals to p, then we have to move left (narrow the window) to find the new match window
            //++ to reset the hash because we kicked out the left
            //only increase the count if the character is in p
            //the count >= 0 indicate it was original in the hash, cuz it won't go below 0
            if((right-left)==p.length() && hash[s[left++]]++>=0)
                count++;
        }
        return result;
    }
};

290. Word Pattern(字符模式匹配)

Given a pattern and a string str, find if str follows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in str.

Examples:

pattern = “abba”, str = “dog cat cat dog” should return true.
pattern = “abba”, str = “dog cat cat fish” should return false.
pattern = “aaaa”, str = “dog cat cat dog” should return false.
pattern = “abba”, str = “dog dog dog dog” should return false.

Notes:

You may assume pattern contains only lowercase letters, and str contains lowercase letters separated by a single space.

解析:

需要注意一下幾個情況:
(1)pattern或str爲空
(2)pattern中的字符數,少於 str中的空格分割後字段數
(3)abba->”dog dog dog dog”

C++代碼實現:

class Solution {
public:
    bool wordPattern(string pattern, string str) {
        if(pattern.length()==0 && str.length()>0)
            return false;
        if(pattern.length()>0 && str.length()==0)
            return false;
        if(pattern.length()==0 && str.length()==0)
            return true;
        unordered_map<char,string> hash;
        unordered_map<string,int> values;

        int index = 0,begin=0;
        string temp;
        for(auto a : pattern){
            index = str.find(" ",begin);
            temp = str.substr(begin,index-begin);
            begin = index+1;
            if(!hash.count(a)){
                hash[a] = temp;
                if(!values.count(temp))     //防止出現a->dog,b->dog的情況
                    values[temp]++;
                else
                    return false;
            }else{
               if(strcmp(temp.c_str(),hash[a].c_str())!=0)
                return false;
            }
        }
        if(str[begin-1]==' ')   //防止str中字段數多於pattern的字符數量
            return false;
        return true;
    }
};

205. Isomorphic Strings

Given two strings s and t, determine if they are isomorphic.
Two strings are isomorphic if the characters in s can be replaced to get t.
All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.

For example,

Given “egg”, “add”, return true.
Given “foo”, “bar”, return false.
Given “paper”, “title”, return true.

Note:

You may assume both s and t have the same length.

C++代碼實現:

class Solution {
public:
    bool isIsomorphic(string s, string t) {
        int len1 = s.length();
        int len2 = t.length();

        if(len1==0 && len2>0)
            return false;
        if(len1>0 && len2==0)
            return false;
        if(len1==0 && len2==0)
            return true;
        if(len1!=len2)
            return false;

        unordered_map<char,char> hash;
        unordered_map<char,int> values;
        for(int i=0; i<len1; i++){
            if(!hash.count(s[i])){
                hash[s[i]] = t[i];
                if(!values.count(t[i]))
                    values[t[i]]++;
                else
                    return false;
            }else{
                if(t[i]!=hash[s[i]])
                    return false;
            }
        }

        return true;
    }
};

508. Most Frequent Subtree Sum

Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a node is defined as the sum of all the node values formed by the subtree rooted at that node (including the node itself). So what is the most frequent subtree sum value? If there is a tie, return all the values with the highest frequency in any order.

Examples 1

Input:
5
/ \
2 -3
return [2, -3, 4], since all the values happen only once, return all of them in any order.

Examples 2

Input:
5
/ \
2 -5
return [2], since 2 happens twice, however -5 only occur once.

Note: You may assume the sum of values in any subtree is in the range of 32-bit signed integer.

解析:

遞歸遍歷左右子樹,分別求出左右子樹和

C++代碼實現:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> findFrequentTreeSum(TreeNode* root) {
        unordered_map<int,int> subTreeSum;
        vector<int> result;
        if(root==NULL)
            return result;
        int rootSum = root->val;
        if(root->left!=NULL);
            rootSum += getSubTreeSum(root->left,subTreeSum);
        if(root->right!=NULL)
            rootSum += getSubTreeSum(root->right,subTreeSum);
        subTreeSum[rootSum]++;
        vector<pair<int,int> > tempVector(subTreeSum.begin(),subTreeSum.end());
        sort(tempVector.begin(),tempVector.end(),Solution::cmp_by_value);

        auto it = tempVector.begin();
        int max = it->second;
        result.push_back(it->first);
        it++;
        for( ; it!=tempVector.end(); ++it){
            if(max==it->second)
                result.push_back(it->first);
            else
                break;
        }
        return result;
    }
    int getSubTreeSum(TreeNode *node,unordered_map<int,int> &subTreeSum){
        if(node==NULL)
            return 0;
        int sum = node->val;
         if(node->left!=NULL);
            sum += getSubTreeSum(node->left,subTreeSum);
        if(node->right!=NULL)
            sum += getSubTreeSum(node->right,subTreeSum);
        subTreeSum[sum]++;
        return sum;
    }

    bool static cmp_by_value(const pair<int,int>& a, const pair<int,int>& b) {
        return a.second > b.second;
    }
};

30. Substring with Concatenation of All Words

You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.

For example, given:

s: “barfoothefoobarman”
words: [“foo”, “bar”]
You should return the indices: [0,9].
(order does not matter).

解析:

(1)方法一:統計words的單詞出現次數到map中,遍歷s,每次取長度爲wordlen*num的子串,將子串分割成單詞w,看w出現是否出現在map中及其出現次數,如果不出現或者出現次數大於map中記錄次數,則說明子串包含了不屬於words的單詞。否則,將該子串下標加入結果集。時間複雜度爲O(N*m),m爲words單詞個數。
(2)方法二:移動窗口,(來源於LeetCode)travel all the words combinations to maintain a window, there are wl(word len) times travel; each time, n/wl words, mostly 2 times travel for each word,one left side of the window, the other right side of the window;時間複雜度爲O(n*k),k爲words中單詞長度。
舉個例子:
比如s = “a1b2c3a1d4”L={“a1”,“b2”,“c3”,“d4”}
窗口最開始爲空,
a1在L中,加入窗口 【a1】b2c3a1d4
b2在L中,加入窗口 【a1b2】c3a1d4
c3在L中,加入窗口 【a1b2c3】a1d4
a1在L中了,但是前面a1已經算了一次,此時只需要把窗口向右移動一個單詞a1【b2c3a1】d4
d4在L中,加入窗口a1【b2c3a1d4】找到了一個匹配
如果把s改爲“a1b2c3kka1d4”,那麼在第四步中會碰到單詞kk,kk不在L中,此時窗口起始位置移動到kk後面a1b2c3kk【a1d4】

C++代碼實現:
方法一:

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> result;
        int len = s.length();
        int num = words.size();
        int wordlen = words[0].length();
        if(num==0 || len==0)
            return result;
       int substrLen = wordlen*num;
        if(s.length()<substrLen)
            return result;

        unordered_map<string,int> wordCount;
        for(string word : words)
            wordCount[word]++;

        for(int i=0; i<len-substrLen+1; i++){
            unordered_map<string,int> seen;
            int j = 0;
            for(; j<num; j++){
                string word = s.substr(i+j*wordlen,wordlen);
                if(wordCount.count(word)==1){
                    seen[word]++;
                    if(seen[word]>wordCount[word])
                        break;
                }
                else
                    break;
            }
            if(j==num)
                result.push_back(i);
        }
        return result;
    }
};

方法二:

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> result;
        int len = s.length();
        int num = words.size();
        int wordlen = words[0].length();
        if(num==0 || len==0)
            return result;
       int substrLen = wordlen*num;
        if(s.length()<substrLen)
            return result;

        unordered_map<string,int> wordCount;
        for(string word : words)
            wordCount[word]++;

        for (int i = 0; i < wordlen; ++i) {
            //left窗口起始位置,count當前窗口單詞個數
            int left = i, count = 0;
            //tdict當前窗口中單詞出現次數
            unordered_map<string, int> tdict;
            for (int j = i; j <= (len - wordlen); j += wordlen) {
                //移動窗口爲[left,j]
                string str = s.substr(j, wordlen);
                // a valid word, accumulate results
                if (wordCount.count(str)) {
                    tdict[str]++;
                    if (tdict[str] <= wordCount[str]) 
                        count++;
                    else {
                        //當前的單詞在map中,但是它已經在窗口中出現了相應的次數,不應該加入窗口,此時,應該把窗口起始位置想左移動到,該單詞第一次出現的位置的下一個單詞位置
                        while (tdict[str] > wordCount[str]) {
                            string str1 = s.substr(left, wordlen);
                            tdict[str1]--;
                            if (tdict[str1] < wordCount[str1]) count--;
                            left += wordlen;
                        }
                    }
                    // come to a result
                    if (count == num) {
                        result.push_back(left);
                        // advance one word
                        tdict[s.substr(left, wordlen)]--;
                        count--;
                        left += wordlen;
                    }
                }
                // not a valid word, reset all vars
                else {
                    tdict.clear();
                    count = 0;
                    left = j + wordlen;
                }
            }
        }
        return result;
    }
};

76. Minimum Window Substring

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

example

S = “ADOBECODEBANC”
T = “ABC”
Minimum window is “BANC”.

Note:

If there is no such window in S that covers all characters in T, return the empty string “”.
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

解析:

(1)方法一:暴力法,假定子串步長step,然後從0開始依次取長度爲step的串substr,判斷T中的字符是否都出現在substr中,如果沒有,step++,循環。時間複雜度爲O(N*N)。超時!!!
(2)方法二:移動窗口和雙指針,設定兩個指針slow和fast,[slow,fast]代表窗口,窗口即爲包含了T中所有字符的一個S的子串substr。用count記錄T中字符出現次數,如果count>T.size,則說明此時[slow,fast]形成了一個窗口,然後通過移動slow指針,不斷縮小窗口;每次找到一個更小的窗口fast-slow+1小於min,更新結果。具體實現見代碼。
(3)方法三:萬能法,可解決大部分“substring”問題,本質和方法2類似,代碼比方法二少很多。下面是算法模板:

int findSubstring(string s){
        unordered_map<char,int> map(128,0);
        int counter; // check whether the substring is valid
        int begin=0, end=0; //two pointers, one point to tail and one  head
        int d; //the length of substring

        for() { /* initialize the hash map here */ }

        while(end<s.size()){

            if(map[s[end++]]-- ?){  /* modify counter here */ }

            while(/* counter condition */){ 

                 /* update d here if finding minimum*/

                //increase begin to make it invalid/valid again

                if(map[s[begin++]]++ ?){ /*modify counter here*/ }
            }  

            /* update d here if finding maximum*/
        }
        return d;
  }

The code of solving Longest Substring Without Repeating Characters is below:

int lengthOfLongestSubstring(string s) {
        vector<int> map(128,0);
        int counter=0, begin=0, end=0, d=0; 
        while(end<s.size()){
            if(map[s[end++]]++>0) counter++; 
            while(counter>0) if(map[s[begin++]]-->1) counter--;
            d=max(d, end-begin); //while valid, update d
        }
        return d;
    }

C++代碼實現:
方法一:暴力法

class Solution {
public:
    string minWindow(string s, string t) {
        string result = "";
        int lenS = s.length();
        int lenT = t.length();
        if(lenS==0 || lenT==0 || lenS<lenT)
            return result;
        unordered_map<char,int> dict;
        for(char c : t)
            dict[c]++;
        int dictSize = dict.size();
        int step = lenT;        //步長
        for(int i=0; i<=(lenS-lenT); i++){
            unordered_map<char,int> tdict;
            int count = 0;
            for(int j=0; j<=(lenS-step); j++){
                string substr = s.substr(j,step);
                for(char c : substr){
                    if(dict.count(c))    //字符存在
                        tdict[c]++;
                }
                for(auto it=dict.begin(); it!=dict.end(); it++){
                    if(tdict[it->first]>=it->second)
                        count++;
                    else
                        break;
                }
                if(count==dictSize)
                    return substr;
                count = 0;
                tdict.clear();
            }
            step++;
        }
        return result;
    }
};

方法二:移動窗口+雙指針

class Solution {
public:
    string minWindow(string s, string t) {
        string result = "";
        int lenS = s.length();
        int lenT = t.length();
        if(lenS==0 || lenT==0 || lenS<lenT)
            return result;
        unordered_map<char,int> dict;
        unordered_map<char,int> window;
        for(char c : t)
            dict[c]++;
        int minLen = INT_MAX;
        int count = 0;
        int slow = 0,fast = 0;
        for(; fast<lenS; fast++){
            char c = s[fast];
            if(dict.count(c)){
                window[c]++;
                if(window[c]<=dict[c])
                    count++;
            }
            if(count>=lenT){
                while(!dict.count(s[slow]) || window[s[slow]]>dict[s[slow]]){
                    window[s[slow]]--;
                    slow++;
                }
                if((fast-slow+1)<minLen){
                    minLen = fast-slow+1;
                    result = s.substr(slow,minLen);
                }
            }
        }
        return result;
    }
};

方法三:hashmap+two pointers(推薦)

class Solution {
public:
    string minWindow(string s, string t) {
        string result;
        int lenS = s.length();
        int lenT = t.length();
        if(lenS==0 || lenT==0 || lenS<lenT)
            return result;
        unordered_map<char,int> dict;
        for(char c : t)
            dict[c]++;
        int counter=t.size(), begin=0, end=0, d=INT_MAX, head=0;
        while(end<s.size()){
            if(dict[s[end++]]-->0) counter--; //in t
            while(counter==0){ //valid
                if(end-begin<d)  d=end-(head=begin);
                if(dict[s[begin++]]++==0) counter++;  //make it invalid
            }
        }
        return d==INT_MAX? "":s.substr(head, d);
        return result;
    }
};

37. Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by the character ‘.’.
You may assume that there will be only one unique solution.
這裏寫圖片描述

解析:

回溯法:每一個空格從1-9試探是否可以填入。

C++代碼實現:

class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        if(board.empty() || board.size()<9)
            return;
        backtrack(board,0);
    }
private:
    bool backtrack(vector<vector<char>>& board,int position){  //從空格的候選項中選擇一個候選者,然後不斷回溯
        if(position>=81)            //9*9
            return true;
        int row = position/9;
        int col = position%9;
        if(board[row][col]!='.')
            return backtrack(board,position+1);
        else{
            for(char c='1'; c<='9'; c++){
                if(checkBoard(board,row,col,c)){
                    board[row][col] = c;
                    if(!backtrack(board,position+1))
                        board[row][col] = '.';
                    else
                        return true;
                }
            }
        }
        return false;
    }
    bool checkBoard(const vector<vector<char>>& board,int row,int col,char c){
        return checkInRow(board,row,c) && checkInCol(board,col,c) && checkInCell(board,row,col,c);
    }
    bool checkInRow(const vector<vector<char>>& board,int row,char c){
        for(int i=0; i<9; i++){
            if(board[row][i]==c){
                return false;
            }
        }
        return true;
    }
    bool checkInCol(const vector<vector<char>>& board,int col,char c){
        for(int i=0; i<9; i++){
            if(board[i][col]==c){
                return false;
            }
        }
        return true;
    }
    bool checkInCell(const vector<vector<char>>& board,int row,int col,char c){
       int startRow = (row/3)*3;
       int startCol = (col/3)*3;
       for(int i=startRow; i<(startRow+3); ++i){
           for(int j=startCol; j<(startCol+3); ++j){
               if(board[i][j]==c)
                    return false;
           }
       }
       return true;
    }
};

149. Max Points on a Line

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

解析:

給定n個點,尋找包含點最多的直線。基本思路是對集合中任意兩個點對,構建直線。
判斷A B C三個點是否在一條直線上,通過AB與AC的斜率來判斷。斜率的表示可以是double和pair(int,int),double在計算時容易丟失精度,所以這裏推薦使用pair(int,int)。 時間複雜度O(n^2)。

C++代碼實現:

/**
 * Definition for a point.
 * struct Point {
 *     int x;
 *     int y;
 *     Point() : x(0), y(0) {}
 *     Point(int a, int b) : x(a), y(b) {}
 * };
 */
class Solution {
public:
    int maxPoints(vector<Point>& points) {
        int count = points.size();
        if(count<=2)
            return count;
        int result = 2;              //至少有兩個點
        for(int i=0; i<count; ++i){
            int same = 1,infinitySlop=0;
            map<pair<int,int>,int> lines;                                //記錄不同的行
            for(int j=i+1; j<count; ++j){
                if(points[i].x==points[j].x && points[i].y==points[j].y)    //與point[i]相同的點
                    same++;
                else if(points[i].x==points[j].x)                           //斜率無窮大
                    infinitySlop++;
                else{
                    int a = points[i].x-points[j].x;
                    int b = points[i].y-points[j].y;
                    int g = gcd(a,b);
                    a /= g;
                    b /= g;
                    lines[make_pair(a,b)]++;
                }

            }
            int currentMax = infinitySlop;

            for(auto it = lines.begin(); it!=lines.end(); ++it){
                currentMax = (currentMax > it->second)? currentMax : it->second;
            }
            currentMax += same;
            result = (result > currentMax)? result : currentMax;
        }
        return result;
    }
    int gcd(int a,int b) {
        int r = 0;
        while(b!=0){
            r = a%b;
            a = b;
            b = r;
        }
        return a;
    }
};

336. Palindrome Pairs

Given a list of unique words, find all pairs of distinct indices (i, j) in the given list, so that the concatenation of the two words, i.e. words[i] + words[j] is a palindrome.

Example 1:

Given words = [“bat”, “tab”, “cat”]
Return [[0, 1], [1, 0]]
The palindromes are [“battab”, “tabbat”]

Example 2:

Given words = [“abcd”, “dcba”, “lls”, “s”, “sssll”]
Return [[0, 1], [1, 0], [3, 2], [2, 4]]
The palindromes are [“dcbaabcd”, “abcddcba”, “slls”, “llssssll”]

解析:

(1)暴力法。對任意兩個單詞w1\w2,判斷w1+w2 和 w2+w1是否是迴文串。算法複雜度爲O(n^2)。容易超時
(2)hashmap法。用hashmap <string,int>記錄詞及下標。w1和w2構成迴文串有以下幾種情況:

  • 如果w1爲“”,如果w2是迴文串,則w1+w2 和 w2+w1都是迴文串;
  • 如果w2是w1的反轉字符串,則w1+w2 和 w2+w1都是迴文串;
  • 如果w1[0 : cut]是迴文串,且w2是w1[cut+1 : ]的反轉字符串,則 w2+w1是迴文串;
  • 如果w1[cut+1:]是迴文串,且w2是w1[0 : cut]的反轉字符串,則 w1+w2是迴文串;

C++代碼實現:

class Solution {
public:
    vector<vector<int>> palindromePairs(vector<string>& words) {
        vector<vector<int>> result;
        int wordCount = words.size();
        if(wordCount<=1)
            return result;
        unordered_map<string,int> dict;
        for(int i=0; i<wordCount; ++i)
            dict[words[i]] = i;
        //第一種情況
        if(dict.count("")){
            int index = dict[""];
            for(int i=0; i<wordCount; ++i){
                if(i==index)
                    continue;
                if(isPalindrome(words[i])){
                    result.push_back({index,i});
                    result.push_back({i,index});
                }
            }
        }
        //第二種情況
        for(int i=0; i<wordCount; ++i){
            string reverseWord = words[i];
            reverse(reverseWord.begin(),reverseWord.end());
            if(dict.count(reverseWord)){
                int index = dict[reverseWord];
                if(i==index)
                    continue;
                //result.push_back({index,i}); //防止重複計算
                result.push_back({i,index});
            }
        }
        //第三、四種情況
        for(int i=0; i<wordCount; ++i){
            for(int j=1; j<words[i].length(); ++j){
                string w1 = words[i].substr(0,j);
                if(isPalindrome(w1)){
                    string w2 = words[i].substr(j);
                    reverse(w2.begin(), w2.end());
                    if(dict.count(w2)){
                        int index = dict[w2];
                        result.push_back({index,i});
                    }
                }
                w1 = words[i].substr(j);
                if(isPalindrome(w1)){
                    string w2 = words[i].substr(0,j);
                    reverse(w2.begin(), w2.end());
                    if(dict.count(w2)){
                        int index = dict[w2];
                        result.push_back({i,index});
                    }
                }
            }
        }
        return result;
    }
private:
    bool isPalindrome(const string& word){
        int len = word.length();
        int end = len>>1;
        for(int i=0; i<=end; ++i){
            if(word[i]!=word[len-1-i])
                return false;
        }
        return true;
    }
};
發佈了31 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章