LeetCode-堆排序

1 介绍

        最大堆:priority_queue, less> maxHeap;

        最小堆:priority_queue, greater> minHeap;

        如果使用 priority_queue 创建堆,默认创建的是最大堆;

        最小堆会在一些图算法中应用,比如prim,dijkstra算法等,参考链接:

        最小生成树-kruskal-prim(《算法导论3rd-P362》)_hclbeloved的博客-CSDN博客

        单源最短路径(《算法导论3rd-P374》)_hclbeloved的博客-CSDN博客        

2 题目

2.1 前K个高频元素

347. 前 K 个高频元素

剑指 Offer II 060. 出现频率最高的 k 个数字

class Solution {
public:
    vector topKFrequent(vector& nums, int k) {
        unordered_map occur;
        for (auto& i : nums) 
            occur[i]++;

        struct cmp
        {
            bool operator()(const pair& m, const pair& n) 
            {
                return m.second > n.second;
            }  
        };

        // pair 的第一个元素代表数组的值,第二个元素代表了该值出现的次数
        priority_queue, vector>, cmp> minHeap;
        for (auto& item : occur) 
        {
            if (minHeap.size() >= k) 
            {
                if (item.second > minHeap.top().second) 
                {
                    minHeap.pop();
                    minHeap.push({item.first, item.second});
                }
            } 
            else 
            {
                minHeap.push({item.first, item.second});
            }
        }

        vector r;
        while (!minHeap.empty()) 
        {
            r.emplace_back(minHeap.top().first);
            minHeap.pop();
        }

        return r;
    }
};

2.2 数组中的第K个最大元素

215. 数组中的第K个最大元素

class Solution {
public:
    int findKthLargest(vector& nums, int k) {
        //方法一:借助快速排序的思路,o(n)
        // return partition(nums, 0, nums.size()-1, k);

        //借助于堆排序,这里使用的是容量为k的最小堆,o(nlogk)
        priority_queue,greater> minHeap;
        for(auto& i:nums)
        {
            if (minHeap.size() < k)
            {
                minHeap.push(i);
            }
            else
            {
                if (i > minHeap.top())
                {
                    minHeap.pop();
                    minHeap.push(i);
                }
            }
        }

        return minHeap.top();
    }

    //第K(K从1开始索引)大就是第 size+1-K 小
    //对应的从0开始的索引就是 size-K
    int partition(vector& nums, int p, int r, int k)
    {
        int x = nums[r];
        int j = p-1;
        for(int i=p;i<=r-1;++i)
        {
            if (nums[i] <= x)
                std::swap(nums[++j], nums[i]);
        }
        std::swap(nums[++j], nums[r]);
        
        if (j < nums.size() - k)
        {
            return partition(nums, j+1, r, k);
        }
        else if (j > nums.size() - k)
        {
            return partition(nums, p, j-1, k);
        }
        else
        {
            return nums[j];
        }
    }
};

2.3 数据流中的中位数

295. 数据流的中位数

class MedianFinder {
public:
    std::priority_queue, greater> minHeap;
    std::priority_queue, less> maxHeap;
    /** initialize your data structure here. */
    MedianFinder() {

    }
    
    void addNum(int num) {
        if (maxHeap.size() > minHeap.size())
        {
            int top = maxHeap.top();
            if (num > top)
            {
                minHeap.push(num);
            }
            else
            {
                maxHeap.pop();
                minHeap.push(top);
                maxHeap.push(num);
            }
        }
        else
        {
            if (!minHeap.empty())
            {
                int top = minHeap.top();
                if (num > top)
                {
                    minHeap.pop();
                    minHeap.push(num);
                    maxHeap.push(top);
                }
                else
                {
                    maxHeap.push(num);
                }
            }
            else
            {
                maxHeap.push(num);
            }
        }
    }
    
    double findMedian() {
        if (maxHeap.size() > minHeap.size())
        {
            return maxHeap.top();
        }
        else
        {
            if (!maxHeap.empty())
            {
                return (maxHeap.top() + minHeap.top()) / 2.0;
            }
            else
            {
                return 0.0;
            }
        }
    }
};

2.4 最小的k个数

剑指 Offer 40. 最小的k个数

class Solution {
public:
    vector getLeastNumbers(vector& arr, int k) {
        //方法二:使用堆排序,使用的是最大堆
        if (k <= 0)
            return vector{};
            
        priority_queue maxHeap;
        for (auto& i:arr)
        {
            if (maxHeap.size() < k)
            {
                maxHeap.push(i);
            }
            else
            {
                if (i < maxHeap.top())
                {
                    maxHeap.pop();
                    maxHeap.push(i);
                }
            }
        }

        vector r;
        while (!maxHeap.empty())
        {
            r.push_back(maxHeap.top());
            maxHeap.pop();
        }

        return r;
    }
};

2.5 根据字符出现的频率排序

451. 根据字符出现频率排序

//类似题目:https://leetcode-cn.com/problems/g5c51o/
class Solution {
public:
    string frequencySort(string s) {
        unordered_map occur;
        for (auto& i : s) 
            occur[i]++;

        struct cmp
        {
            bool operator()(const pair& m, const pair& n) 
            {
                return m.second < n.second;
            }  
        };

        // pair 的第一个元素代表数组的值,第二个元素代表了该值出现的次数
        priority_queue, vector>, cmp> maxHeap;
        for (auto& item : occur) 
            maxHeap.push({item.first, item.second});

        string r;
        while (!maxHeap.empty()) 
        {
            r.append(maxHeap.top().second, maxHeap.top().first);
            maxHeap.pop();
        }

        return r;
    }
};

2.6 和最小的k个数对

剑指 Offer II 061. 和最小的 k 个数对

373. 查找和最小的 K 对数字

class Solution {
public:
	vector> kSmallestPairs(vector& nums1, vector& nums2, int k) {
		//方法一:最大堆
        //https://leetcode-cn.com/problems/qn8gGX/solution/jian-zhi-offer-2-mian-shi-ti-61-shu-zhon-d9q5/
		// struct cmp 
		// {
		//     bool operator()(const pair& a, const pair& b)
		//     {
		//         return (a.first+a.second < b.first+b.second);
		//     }
		// };
		// priority_queue, vector>, cmp> maxHeap;

        // for (int i = 0; i < nums1.size() && i < k; ++i) 
        // {
        //     for (int j = 0; j < nums2.size() && j < k; ++j) 
        //     {
        //         if (maxHeap.size() < k) 
        //         {
        //             maxHeap.push({nums1[i], nums2[j]});
        //         }
        //         else if (nums1[i] + nums2[j] < maxHeap.top().first + maxHeap.top().second)  
        //         {
        //             maxHeap.pop();
        //             maxHeap.push({nums1[i], nums2[j]});
        //         }
        //     }
        // }

		// vector> r;
		// while (!maxHeap.empty())
		// {
		//     r.push_back({maxHeap.top().first, maxHeap.top().second});
		//     maxHeap.pop();
		// }

		// return r;

		//方法二: 最小堆
        //https://leetcode-cn.com/problems/qn8gGX/solution/jian-zhi-offer-2-mian-shi-ti-61-shu-zhon-d9q5/
        auto cmp = [&](const pair& lhs, const pair& rhs) 
        {
            return nums1[lhs.first] + nums2[lhs.second] > nums1[rhs.first] + nums2[rhs.second];
        };
        priority_queue, vector>, decltype(cmp)> minHeap(cmp);

        for (int i = 0; i < k && i < nums1.size(); ++i) 
        {
            minHeap.push({i, 0});
        }
        vector> r;
        while (k-- > 0 && !minHeap.empty()) 
        {
            auto ids = minHeap.top();
            minHeap.pop();
            r.push_back({nums1[ids.first], nums2[ids.second]});

            if (ids.second < nums2.size() - 1) 
            {
                minHeap.push({ids.first, ids.second + 1});
            }
        }

        return r;
	}
};

2.7 替换单词

剑指 Offer II 063. 替换单词

648. 单词替换

// class Solution {
// public:
//     string replaceWords(vector& dictionary, string sentence) {
//         //最大堆
//         auto cmp = [](const string& a, const string& b)->bool
//         {
//             return a.length() < b.length();
//         };
//         priority_queue, decltype(cmp)> maxHeap(cmp);
//         for (auto& str:dictionary)
//             maxHeap.push(str);

//         int pos = -1, start = 0;
//         vector v;
//         while((pos=sentence.find_first_of(' ', start)) != string::npos)
//         {
//             v.push_back(sentence.substr(start, pos-start));
//             start = pos + 1;
//         }
//         string str = sentence.substr(start);
//         if (!str.empty())
//             v.push_back(str);

//         while (!maxHeap.empty())
//         {
//             const string& pattern = maxHeap.top();
//             for (auto& str : v)
//             {
//                 // if (KnuthMorrisPratt(str, pattern) != -1)
//                 if (KnuthMorrisPratt(str, pattern) == 0)
//                 {
//                     str = pattern;
//                 }
//             }

//             maxHeap.pop();
//         }
        
//         string res;
//         for (auto& str : v)
//         {
//             if (res.empty())
//             {
//                 res.append(str);
//             }
//             else
//             {
//                 res.append(1,' ').append(str);
//             }
//         }
//         return res;
//     }

//     // pattern表示模式串
//     vector getNexts(const string& pattern) 
//     {
//         int n = pattern.length();
//         vector next(n, 0);
//         next[0] = -1;
//         int k = -1;
//         //求解所有好前缀的最长可匹配前缀子串,最长的好前缀为[0, n-2],所以下面可以修改为: i < n - 1
//         //for (int i = 1; i < n; ++i) //这里就算是计算了next[n-1]其实也用不到,所以这里就是计算了也没影响
//         for (int i = 1; i < n - 1; ++i) 
//         {
//             while (k != -1 && pattern[k + 1] != pattern[i]) 
//             {
//                 k = next[k];
//             }

//             if (pattern[k + 1] == pattern[i]) 
//             {
//                 ++k;
//             }
//             next[i] = k;
//         }

//         return next;
//     }


//     // src, pattern分别是主串和模式串
//     int KnuthMorrisPratt(const string& src, const string& pattern) 
//     {
//         int patternLen = pattern.length();
//         vector next = getNexts(pattern);
//         int j = 0, n = src.length();
//         for (int i = 0; i < n; ++i) 
//         {
//             while (j > 0 && src[i] != pattern[j]) // 一直找到a[i]和b[j]
//             { 
//                 //next[j - 1]表示模式串中最长可匹配前缀子串的结尾字符的下标,那么就可将主串中索引 i 处的坏字符开始与next[j - 1] + 1字符进行比较
//                 j = next[j - 1] + 1;//当j=0时退出循环,表示下一轮主串开始从索引 i+1 处与模式串(从头开始也就是j=0)开始新一轮的比较
//             }

//             if (src[i] == pattern[j]) 
//             {
//                 ++j;
//             }

//             if (j == patternLen) // 找到匹配模式串的了
//             { 
//                 //src[r, i]恰好等于pattern,所以 i - r + 1 = pattern, r = i + 1 - pattern
//                 return i - patternLen + 1;
//             }
//         }

//         return -1;
//     }    
// };

class Solution {
public:
    string replaceWords(vector& dictionary, string sentence) {
        //最大堆
        auto cmp = [](const string& a, const string& b)->bool
        {
            return a.length() < b.length();
        };
        priority_queue, decltype(cmp)> maxHeap(cmp);
        for (auto& str:dictionary)
            maxHeap.push(str);

        int pos = -1, start = 0;
        vector v;
        while((pos=sentence.find_first_of(' ', start)) != string::npos)
        {
            v.push_back(sentence.substr(start, pos-start));
            start = pos + 1;
        }
        string str = sentence.substr(start);
        if (!str.empty())
            v.push_back(str);

        while (!maxHeap.empty())
        {
            const string& pattern = maxHeap.top();
            for (auto& str : v)
            {
                if (str.substr(0, pattern.length()).compare(pattern) == 0)
                {
                    str = pattern;
                }
            }

            maxHeap.pop();
        }
        
        string res;
        for (auto& str : v)
        {
            if (res.empty())
            {
                res.append(str);
            }
            else
            {
                res.append(1,' ').append(str);
            }
        }
        return res;
    }   
};

2.8 数据流中第K大数值

剑指 Offer II 059. 数据流的第 K 大数值

703. 数据流中的第 K 大元素

//使用含有k个元素的最小堆
class KthLargest {
public:
    int n;
    priority_queue, greater> minHeap;
    KthLargest(int k, vector& nums) {
        n = k;
        for (auto& i:nums)
        {
            if (minHeap.size() < k)
            {
                minHeap.push(i);
            }
            else
            {
                if (i > minHeap.top())
                {
                    minHeap.pop();
                    minHeap.push(i);
                }
            }            
        }
    }
    
    int add(int val) {
        if (minHeap.size() < n)
        {
            minHeap.push(val);
        }
        else
        {
            if (val > minHeap.top())
            {
                minHeap.pop();
                minHeap.push(val);
            }
        }

        return minHeap.top();       
    }
};

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest* obj = new KthLargest(k, nums);
 * int param_1 = obj->add(val);
 */

2.9

2.10

2.11

2.12

2.13

2.14

2.15

2.16

2.17

2.18

2.19

2.20

2.21

你可能感兴趣的:(#,LeetCode-排序,#,LeetCode-堆,leetcode,算法,职场和发展)