《慕课网玩转算法面试》笔记及习题解答4

来源:互联网 发布:论文查重软件 编辑:程序博客网 时间:2024/05/16 07:56

查找问题


查找有无

-元素‘a’是否存在?set;集合


查找对应关系(键值对应)

-元素‘a’出现了几次?map;字典

 

set和map常见操作:

insert

find

erase

change (map)


LeetCode 349

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

思路:判断是否有相同,直接用set就行

vector<int> intersection(vector<int>& nums1, vector<int>& nums2){    set<int> record(nums1.begin(), nums1.end());    set<int> resultSet;    for(int i = 0; i < nums2.size();i++)    {        if( record.find(nums2[i]) != record.end() )            resultSet.insert(nums2[i]);    }    vector<int> resVec(resultSet.begin(), resultSet.end());    return resVec;}

 LeetCode 350

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

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


思路:寻找交集,可以有相同元素 ,如 因此可以使用map

vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {    map<int,int> record;    for(int i = 0; i < nums1.size(); i++)        record[nums1[i]]++;    vector<int> res;    for(int i = 0; i < nums2.size(); i++)        if( record[nums2[i]] > 0 )    {        res.push_back(nums2[i]);        record[nums2[i]]--;    }    return res;    }

注意 set 和 map这两个数据结构的 find方法返回值为 .end()时为没找到。

其次,set 和 map 的底层实现为平衡二叉树,它的一次查找,增添,删除时间复杂度都是 O(logn ), 存储n个元素的空间复杂度为O(n)。



对于查找问题,哈希表非常优秀,它的增删查复杂度都是O(1)。

但是哈希表的缺点在于打乱了数据的顺序性。

unordered_map和 unordered_set 底层实现为哈希表。


对于一般的查找问题,哈希表就能解决, 但是对于 需要顺序关系的问题,比如前驱后继,最大最小等问题, 平衡二叉树更好。


练习题:

LeetCode 242

Given two strings s and t, write a function to determine if t is an anagram of s.

For example,
s = "anagram", t = "nagaram", return true.
s = "rat", t = "car", return false.


bool isAnagram(string s, string t) {    unordered_map<char,int> char_count;    for(int i = 0; i < s.length(); i++)        char_count[s[i]]++;    for(int j = 0; j < t.length(); j++)        char_count[t[j]]--;    for(unordered_map<char,int>::iterator iter = char_count.begin(); iter!= char_count.end(); iter++ )        if(iter->second != 0)            return false;    return true;}



LeetCode 202

Write an algorithm to determine if a number is "happy".

A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.


bool isHappy(int n) {    if( 1 == n )        return true;    unordered_map<int,int>  exist_num;    while( !exist_num[n] )    {        exist_num[n]++;        int sum = 0;        while( n )        {            sum += (n % 10) * (n % 10);            n /= 10;        }        if( 1 == sum )            return true;                n = sum;            }    return false;}



LeetCode 290

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:

  1. pattern = "abba", str = "dog cat cat dog" should return true.
  2. pattern = "abba", str = "dog cat cat fish" should return false.
  3. pattern = "aaaa", str = "dog cat cat dog" should return false.
  4. pattern = "abba", str = "dog dog dog dog" should return false.

思路:因为必须是一一对应关系,所以应该使用两个哈希表,一个从string映射到char,一个从char 映射到 string,如果给定一个(string,pair)对,两个哈希表的key / val都为空,则赋值;如果都存在,则判断是否和之前的赋值一样,不一样则return false; 如果一个哈希表存在,一个不存在,则有可能是("abba","dog dog dog dog")形式,不满足条件,直接返回false。 注意循环终止时候

bool wordPattern(string pattern, string str) {    int slice_start = 0;    int i = 0;    map<char, string> char2string;    map<string, char> string2char;    while( i < pattern.length() && slice_start < str.length()){        int slice_end = str.find(" ", slice_start);        if(slice_end == string::npos)            slice_end = str.length();        string slice = str.substr(slice_start, slice_end - slice_start);        slice_start = slice_end+1;        if(char2string[pattern[i]].empty() && !string2char[slice] )        {            char2string[pattern[i]] = slice;            string2char[slice] = pattern[i++];        }        else if(!char2string[pattern[i]].empty() && string2char[slice] )            if( char2string[pattern[i]] != slice || string2char[slice] != pattern[i] )            {                return false;            }            else                i++;        else        {            return false;        }    }    if( (i < pattern.length() && slice_start < str.length()) ||  i >= pattern.length() && slice_start >= str.length())        return true;    else        return false;}


LeetCode 205

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.


思路:同构可以用一一映射来表示,一一映射的问题都可以用两个哈希表来解决

bool isIsomorphic(string s, string t) {    if(s.empty() ||s.length() <1)        return true;    unordered_map<char, char> s2t;    unordered_map<char, char> t2s;    int n = s.length();    for( int i = 0; i < n; i++ )    {        if( !s2t[s[i]] && !t2s[t[i]] ){            s2t[s[i]] = t[i];            t2s[t[i]] = s[i];        }                    else{            if( s2t[s[i]] != t[i] || t2s[t[i]] != s[i] )                return false;        }    }    return true;}



LeetCode 451

思路:使用哈希表计数,使用sort和lambda表达式对s排序

string frequencySort(string s) {        unordered_map<char, int> charCount;        for(int i = 0; i < s.length(); i++)        {            charCount[s[i]]++;        }        auto compare =  [&charCount] (char a, char b) {            return charCount[a] > charCount[b] || (charCount[a] == charCount[b] && a > b);};        sort(s.begin(), s.end(),compare);        return s;    }

LeetCode 15

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

思路:因为不需要输出index,可以先排序,循环第一个数 i ,在[ i+1,......]中使用对撞指针。但是此题需要输出所有的组合。因此需要注意去重, 每次找到一组数都必须将i ,j ,k移动到与当前找到的组合值不同的 i, j, l,r上,注意不能越界


class Solution {public:    vector<vector<int>> fourSum(vector<int>& nums, int target) {        vector<vector<int>> res;        if(nums.size() < 4)            return res;        sort(nums.begin(), nums.end());        for(int i = 0; i < nums.size()-3; i++){ //固定 i,j            for(int j = i+1; j < nums.size() - 2; j++)            {                int l = j+1;                 int r = nums.size() - 1;                while(l < r)                {                    if(nums[i] + nums[j] + nums[l] + nums[r] == target)                    {                        vector<int> temp(4,-1);                        temp[0] = nums[i];                        temp[1] = nums[j];                        temp[2] = nums[l];                        temp[3] = nums[r];                        res.push_back(temp);                        while( l+1 < r && nums[l+1] == nums[l]) l++; //去掉重复的数字                        while( l < r-1 && nums[r-1] == nums[r]) r--; //去掉重复的数字                        l++;                    }                    if(nums[i] + nums[j] + nums[l] + nums[r] < target) l++;                    if(nums[i] + nums[j] + nums[l] + nums[r] > target) r--;                }                while(j+1 < nums.size() - 2 && nums[j+1] == nums[j] ) j++; //去掉重复的数字            }            while(i+1 < nums.size() - 3 && nums[i+1] == nums[i] ) i++; //去掉重复的数字        }        return res;    }};

LeetCode 18

思路:将前两个变量固定进行循环,在最右区域使用对撞指针,主要问题还是避免重复的组合,下面的结果还是有点问题,暂时找不到在哪,思路应该是这样,其实主要是c++不能用vector作为哈希表的key , 如果用python做这题很简单。。。

vector<vector<int> > fourSum(vector<int>& nums, int target) {    sort(nums.begin(), nums.end());    vector<vector<int> > res;    vector<int> quadruplets(4);    int n = nums.size();    for(int i = 0; i < n - 3; i++){int target3 = target - nums[i];for( int j = i+1; j < n -2 ;j++ ){    int target2 = target3 - nums[j];    int l = j+1, r = n-1;    while( l < r)    {if( nums[l] + nums[r] < target2 ) l++;if( nums[l] + nums[r] > target2 ) r--;else if( nums[l] + nums[r] == target2  ){    quadruplets[0] = nums[i];    quadruplets[1] = nums[j];    quadruplets[2] = nums[l];    quadruplets[3] = nums[r];    res.push_back(quadruplets);    while(l < n-1 && nums[l] == quadruplets[2]) l++;                           while(2 < r && nums[r] == quadruplets[3] ) r--;}    }                while( j < n-2 && nums[j+1] == nums[j] ) j++;}        while( i < n-3 && nums[i+1] == nums[i] ) i++;    }    return res;}



LeetCode 454


Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such that A[i] + B[j] + C[k] + D[l] is zero.

To make problem a bit easier, all A, B, C, D have same length of N where 0 ≤ N ≤ 500. All integers are in the range of -228 to 228 - 1 and the result is guaranteed to be at most 231 - 1.

思路: 因为有四个数组且每个数组的长度不大,数据规模其实暗示了可以用空间换时间且级别可以在O(n^2), 我们考虑将 C[i] + D[ j ]的结果存入哈希表, 遍历 A[i] + B[j] 看是否存在鱼哈希表中。


int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {    unordered_map<int, int> record;    for(int i = 0; i < C.size(); i++)for(int j = 0; j < D.size(); j++)    record[ C[i] + D[j] ]++;    int res = 0;    for(int i = 0; i < A.size(); i++)for(int j = 0; j < B.size(); j++){    if( record.find( 0 - A[i] - B[j] ) != record.end() )res += record[ 0 - A[i] - B[j] ];}    return res;}

LeetCode 49

思路:将每个string排序以后可以很容易判断是否为Anagrams,将排序后的string放入哈希表中

    vector<vector<string>> groupAnagrams(vector<string>& strs) {        map<string, int> record;        int j = 0;        vector<vector<string> > res;        for(int i = 0; i < strs.size(); i++){            string str_cp(strs[i]);            sort(str_cp.begin(), str_cp.end());            if( record.find(str_cp) != record.end() ){                res[ record[ str_cp] ].push_back( strs[i] );            }            else{                    record[str_cp] = j++;                    vector<string> temp;                    temp.push_back(strs[i]);                    res.push_back(temp);            }                        }        return res;    }

LeetCode 16

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

思路:和3sum差不多,只要注意划分区间即可

int threeSumClosest(vector<int>& nums, int target) {    int n = nums.size();    if(n < 3)return target;    int closest = nums[0] + nums[1] + nums[2] ;    int min_dist = abs( closest - target);    sort( nums.begin(), nums.end());        for( int i = 0; i < n; i++ ){int l = i+1;int r = n-1;int target_2 = target - nums[i];while( l < r ){    int sum = nums[l] + nums[r];    if( sum + min_dist < target_2 ) // 三者之和在target-min_dist的左边,这时显然应该l++增大和l++;    else if( target_2 + min_dist < sum ) // 三者之和在target+min_dist的右边,这时显然应该r--减小和r--;    else{   // 三者之和在  (target-min_dist,target+min_dist)之间,这时满足条件,通过判断是在target的左右两边选择移动l还是rclosest = sum + nums[i];min_dist = abs( target - closest );if( target - closest > 0) l++;else if (target -closest < 0) r--;else    return closest;    }        }    }    return closest;}

LeetCode 447

Given n points in the plane that are all pairwise distinct, a "boomerang" is a tuple of points (i, j, k) such that the distance betweeni and j equals the distance between i and k (the order of the tuple matters).

思路:对于任意一个点 i ,记录与它不同的所有点的距离并以距离为key, 相同距离的点的个数为value构建哈希表, 对于所有value > 2的key,求它所有的两两组合即 , 其中n为value值。

int dist( const pair<int, int>& p1, const pair<int, int>& p2 ) //为了避免根号产生浮点数,可以直接用距离的平方代替距离{    return ( (p1.first - p2.first) * (p1.first - p2.first) + (p1.second - p2.second) * (p1.second - p2.second) ) ;}    int numberOfBoomerangs(vector<pair<int, int> >& points) {    int n_p = points.size();    int res = 0;        for(int i = 0; i < n_p; i ++){      map<int, int> record;for(int j = 0; j < n_p; j++)    if( i != j){record[ dist(points[i], points[j])]++;    }        for( map<int, int>::iterator iter = record.begin(); iter != record.end(); iter++ )    {//cout << iter->second << endl;res +=( iter->second * (iter->second -1) );     }    }    return res;}




LeetCode 149

感觉边界条件一堆坑,好难,暂时跳过吧


LeetCode 219

Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the absolute difference between i and j is at most k.

思路:遍历数组,用一个大小不超过k的set保存前k个不同元素,对于遍历到的元素,查看set中是否存在重复元素,存在则返回true,否则将该元素存入set中,并移除掉第i - k个元素保持set的大小不超过k

    bool containsNearbyDuplicate(vector<int>& nums, int k) {        unordered_set<int> record;        for(int i = 0; i < nums.size(); i++){            if( record.find( nums[i] ) != record.end() )            {                return true;            }            else{                record.insert( nums[i] );                if(record.size() > k)                    record.erase(nums[i - k]);                               }                  }        return false;    }


LeetCode 220

Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.

思路:主要是要知道set里面存在lower_bound和upper_bound这样的函数可以返回set中大于等于某个数的最小值,然后判断这个值是否在 [ nums[i]-t , nums[i] +t ]之间,还要注意的是int的越界问题,可以用long long

    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {        set<long long> record;        for(int i = 0; i < nums.size(); i++){            if(  record.lower_bound( (long long)nums[i] - (long long) t ) != record.end() &&                *record.lower_bound( (long long)nums[i] - (long long)t ) <= (long long) nums[i] + (long long)t )            {                return true;            }            else{                record.insert( nums[i] );                if(record.size() > k)                    record.erase(nums[i - k]);                               }                  }        return false;    }


阅读全文
0 0
原创粉丝点击