Data structure -- LeetCode special exercise Day14

Posted by Fearpig on Sun, 19 Sep 2021 09:39:55 +0200

43. String multiplication

Give two nonnegative integers in string form   num1   and   Num2, return   num1   and   num2   Their products are also expressed in string form.

Example 1:

Input: num1 = "2", num2 = "3"
Output: "6"

Example   2:

Input: num1 = "123", num2 = "456"
Output: "56088"


explain:

num1   and   num2   The length of is less than 110.
num1 and   num2 contains only numbers   0-9.
num1 and   num2   Do not start with zero unless it is the number 0 itself.
You cannot use the large number type of any standard library (such as BigInteger) or directly convert the input to an integer.

Original idea:

1. Convert a string into an array 2. Multiply the corresponding bits 3. Change the result to a string

(corresponding bit multiplication is not thought clearly, that is, how to multiply, and zero filling mentioned later)

Train of thought correction:

Method 1: add
1. If one of num 1 and num2 is 0, you can directly return 0 as the result.
2. If neither num 1 nor num2 is 0, it is calculated by vertical multiplication.
Traverse the multiplier from left to right, multiply each bit of the multiplier (num2) by the multiplicand (num1) to obtain the corresponding result, and then accumulate the results obtained each time
num2 processes the lowest bit, and the operation result of each other bit needs to be supplemented with 0

class Solution {
public:
	
    string multiply(string num1, string num2) {
		//0
        if (num1 == "0" || num2 == "0") {
            return "0";
        }
        string ans = "0";

        int m = num1.size(), n = num2.size();
		//Traverse num2 from left to right
        for (int i = n - 1; i >= 0; i--) {
            string curr;
            int add = 0;//carry
            for (int j = n - 1; j > i; j--) {
                curr.push_back(0);//push_back() adds an element at the end of the Vector (the parameter is the value to be inserted), where 0 is added
            }
            int y = num2.at(i) - '0';//String. At() is used to get the specified character; at(i),i is the subscript of the character you want to get, and the return value of the function is the specified character
			//Traverse num1
            for (int j = m - 1; j >= 0; j--) {
                int x = num1.at(j) - '0';
                int product = x * y + add;//Multiplication + carry
                curr.push_back(product % 10);//Reserved remainder
                add = product / 10;//carry
            }
            while (add != 0) {
                curr.push_back(add % 10);
                add /= 10;
            }
            reverse(curr.begin(), curr.end());
			// The reverse function is used to reverse the order within the range of [first, last] (including the elements pointed to by first, excluding the elements pointed to by last). The reverse function does not return a value
            for (auto &c : curr) {
                c += '0';//Zero filling
            }
            ans = addStrings(ans, curr);
        }
        return ans;
    }

    string addStrings(string &num1, string &num2) {
        int i = num1.size() - 1, j = num2.size() - 1, add = 0;
        string ans;
        while (i >= 0 || j >= 0 || add != 0) {
            int x = i >= 0 ? num1.at(i) - '0' : 0;
            int y = j >= 0 ? num2.at(j) - '0' : 0;
            int result = x + y + add;
            ans.push_back(result % 10);
            add = result / 10;
            i--;
            j--;
        }
        reverse(ans.begin(), ans.end());
        for (auto &c: ans) {
            c += '0';
        }
        return ans;
    }
};// 8ms

Two functions:   multiply(string num1, string num2); and addstrings (string & num1, string & num2); implement addition and carry functions respectively

Special functions used:

push_back(): add an element at the end of the Vector (the parameter is the value to be inserted).

String. At(): get the specified character; at(i), i is the subscript of the character you want to get, and the return value of the function is the specified character

Reverse(): reverses the order within the range of [first, last] (including the elements pointed to by first, excluding the elements pointed to by last). The reverse function does not return a value

Ternary operator:

  Method 2: multiplication

Storing results with arrays instead of strings
Let m and N represent the lengths of num1 and num2 respectively, and neither of them is 0, then the length of their product is m+n-1 or m+n
This creates an array ansArr of length m+n to store the product
num 1[i] × The result of num2[j] is located in ansArr[i+j+1]. If ansArr[i+j+1] ≥ 10, the carry part is added to ansArr[i+j]

class Solution {
public:
    string multiply(string num1, string num2) {
        if (num1 == "0" || num2 == "0") {
            return "0";
        }
        int m = num1.size(), n = num2.size();
        auto ansArr = vector<int>(m + n);//Store product, size m+n
		//Traverse num1
        for (int i = m - 1; i >= 0; i--) {
            int x = num1.at(i) - '0';
			//Traversal num2
            for (int j = n - 1; j >= 0; j--) {
                int y = num2.at(j) - '0';
                ansArr[i + j + 1] += x * y;//product
            }
        }

        for (int i = m + n - 1; i > 0; i--) {
            ansArr[i - 1] += ansArr[i] / 10;//Top ten (to the first)
            ansArr[i] %= 10;//The remainder exists in this bit
        }
        int index = ansArr[0] == 0 ? 1 : 0;
        string ans;
        while (index < m + n) {
            ans.push_back(ansArr[index]);
            index++;
        }
        for (auto &c: ans) {
            c += '0';
        }
        return ans;
    }
};//4ms

49. Grouping of acronyms

Give you a string array, please combine the letter ectopic words together. You can return the result list in any order.

An alphabetic ectopic word is a new word obtained by rearranging the letters of the source word. All the letters in the source word are used just once.

 

Example 1:

Input: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
Output: ["bat"],["nat","tan"],["ate","eat","tea"]]


Example 2:

Input: strs = [""]
Output: [""]]


Example 3:

Input: strs = ["a"]
Output: ["a"]]
 

Tips:

1 <= strs.length <= 104
0 <= strs[i].length <= 100
strs[i]   Contains only lowercase letters

The meaning of the title is: put the words with the same letters in an array

Key points: how to recognize the letters of each word? First, make it clear that the string needs to be transformed into an array

Method 1: sorting

1. Convert different strings into character arrays and sort them alphabetically
2. The sorted results of ectopic words are the same, so they can be used as the key value of the hash table
3. Take the set composed of alphabetic ectopic words as the value value of the hash table

  java version:

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
       //Determine whether it is an empty string array
        if(strs == null || strs.length == 0){
            return new ArrayList();
        }
        //1. Create a hash table
        Map<String,List> map = new HashMap<String, List>();
        for (String s: strs) {
            //Convert string to character array
            char[] chars = s.toCharArray();
            //Sort the character array alphabetically
            Arrays.sort(chars);
            //The sorted string is used as the key value in the hash table
            String key = String.valueOf(chars);
            //2. Judge whether the key value exists in the hash table
            if (!map.containsKey(key)){
                //If it does not exist, it will be a new ectopic word and create a new key value pair in the map
                map.put(key,new ArrayList());
            }
            //3. Put the string in the list of the corresponding key
            map.get(key).add(s);
        }
        //Returns a list of all key value objects in the map
        return new ArrayList(map.values());
    }
}

c + + version  

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string, vector<string>> mp;
		//Construct word character sort as key
        for (string& str: strs) {
            string key = str;
            sort(key.begin(), key.end());//sort
            mp[key].emplace_back(str);
        }
        vector<vector<string>> ans;
		//Add the corresponding position of hash table
        for (auto it = mp.begin(); it != mp.end(); ++it) {
            ans.emplace_back(it->second);
        }
        return ans;
    }
};

Method 2: counting

Since the two strings of mutually alphabetic ectopic words contain the same letters, the occurrence times of the same letters in the two strings must be the same. Therefore, the occurrence times of each letter can be represented by a string as the key of the hash table.
Because strings contain only lowercase letters, you can use an array of length 26 to record the number of occurrences of each letter for each string.

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        // Customize the hash function for array < int, 26 >
        auto arrayHash = [fn = hash<int>{}] (const array<int, 26>& arr) -> size_t {
            return accumulate(arr.begin(), arr.end(), 0u, [&](size_t acc, int num) {
                return (acc << 1) ^ fn(num);
            });
        };

        unordered_map<array<int, 26>, vector<string>, decltype(arrayHash)> mp(0, arrayHash);
        for (string& str: strs) {
            array<int, 26> counts{};
            int length = str.length();
            for (int i = 0; i < length; ++i) {
                counts[str[i] - 'a'] ++;
            }
            mp[counts].emplace_back(str);
        }
        vector<vector<string>> ans;
        for (auto it = mp.begin(); it != mp.end(); ++it) {
            ans.emplace_back(it->second);
        }
        return ans;
    }
};

Method 3: violent solution

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        List<List<String>> result = new ArrayList<>();

        int len = strs.length;
        String[] strings = new String[len];

//Put the sorted dest string array into a new string array
for (int i = 0; i < len; i++) {
    byte[] bytes = strs[i].getBytes();
    Arrays.sort(bytes);
    strings[i] = new String(bytes);
}
//Traverse the new string array and classify the same string (the classified string can be set to null)
for (int i = 0; i < len; i++) {
    ArrayList<String> strings1 = new ArrayList<>();
    //If it is blank, it indicates that it has been classified
    if (strings[i] != null) {
        strings1.add(strs[i]);
        //Find the same string after sorting
        for (int j = i + 1; j < len; j++) {
            if (strings[i].equals(strings[j])) {
                strings1.add(strs[j]);
                // The classified string is left blank
                strings[j] = null;
            }
        }
    }
//Put the classified string group into the result set
	if (strings1.size() != 0)
                result.add(strings1);
        }
        return result;
    }
}

Method 4: hash table solution
1. Prepare several bucket s to store the original string after grouping
2. Find the bucket according to the sorted string and put the original string into the bucket
The sorted string is used as the key, and the sorted string findbucke is used
After traversing the string array, the grouping is completed
3. Put the sub result set in each bucket into the final result set

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string, vector<string>> mp;
        vector<vector<string>> result;//Result set
		//Sort; put the corresponding original string into the bucket
        for(auto str : strs) {
            auto tempStr = str;
            sort(tempStr.begin(), tempStr.end());
            mp[tempStr].push_back(str);
        }
		//Put into result set
        for(auto elem : mp) {
            result.push_back(elem.second);
        }
        return result;
    }
};

Summary:
Once you need to classify according to characteristics, use hash table
In fact, the idea of this classification problem can be determined: the first traversal should be divided into categories, and the second time can be taken out as ans.
Then, the key selection idea is the core. Each question may have the characteristics of each question.
For this question, after sorting, the disordered strings can be divided into one category

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string,vector<string>> mymap;

        for( int i=0; i<strs.size() ;i++ )
        {
            string str = strs[i];
            sort( str.begin() , str.end() );//sort
            mymap[str].push_back( strs[i] );
        }
        vector<vector<string>> ans;//Result set
        for(auto it = mymap.begin() ;it!= mymap.end() ;it++ )
        {
            ans.push_back(it->second);
        }

        return ans;
    }
};

Topics: Algorithm data structure leetcode string Hash table