刷题记录——排序

1 排序

在这里插入图片描述
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

在这里插入图片描述

1.1冒泡排序

冒泡排序就是重复地走访过要排序的元素列,依次比较两个相邻的元素。
第一个循环是冒泡次数,为数组大小-1,第二个循环是比较相邻元素,只需要比较数组大小-1-i次
代码:

    vector<int> sortArray(vector<int>& nums) {
        int n = nums.size();
        if (n == 0 or n == 1) return nums;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n - i - 1; ++j) {
                if (nums[j] > nums[j + 1]){
                    int temp = nums[j + 1];
                    nums[j + 1] = nums[j];
                    nums[j] = temp;
                }
            }
        }
        return nums;
    }

冒泡排序改进:
在每轮循环前设置一个flag表明本轮是否发生了元素交互,若一轮循环下来,都没有发生元素交互,则说明已经排序完成,直接break

    vector<int> sortArray(vector<int>& nums) {
        int n = nums.size();
        if (n < 2) return nums;
        for (int i = 0; i < n; ++i) {
            bool flag = false;
            for (int j = 0; j < n - i - 1; ++j) {
                if (nums[j] > nums[j + 1]) {
                    swap(nums[j], nums[j + 1]);
                    flag = true;
                }
            }
            if (!flag) break;//说明这轮循环内,没有发生元素交互,说明已经排好序了
        }
        return nums;
    }

正反冒泡


void Bubble_sort(int a[],int size)
{
	int low = 0;
	int high = size-1;
	while(high > low)
	{
		for (int i = low; i != high; ++i)//正向冒泡,确定最大值
		{
			if (a[i] > a[i+1])
			{
				int temp = a[i];
				a[i] = a[i+1];
				a[i+1] = temp;
			}
		}
		--high;
 
		for (int j = high; j != low; --j)//反向冒泡,确定最小值
		{
			if (a[j] < a[j-1])
			{
				int temp = a[j];
				a[j] = a[j-1];
				a[j-1] = temp;
			}
		}
		++low;
	}
}

1.2 快速排序

[注]:rand()%30将随机数限制在[0,30)
随机初始设定数组中的任意值,以他为标准,小于他的放在他左边,大于他的放他右边(能够确定这个值的位置)。在反复
eg : nums = [6,4,5,3,2]
设定l为这段数组的首位置,r为这段数组的尾位置。随机选择一个值cur(rand()%(r-l+1)+l),作为标准
在 l < r的情况下进入循环,

  • 1.若nums[r] >=cur,则 r–,循环结束再令nums[l] = nums[r]。即:若从数组末端开始若有小于cur的数,就将他移到前面,若大于cur,就先r–,直至出现<=cur的数或者l>=r。
  • 2.同理接着若nums[l] <=cur,则l++,循环结束再令nums[r] = nums[l]。即:若从数组首端开始若有大于cur的数,就将他移到后面,若<=cur,就先l++,直至出现>=cur的数或者l>=r。
  • l >= r后,再令nums[l] = cur,并返回l。
    -令mid = 返回的l, 然后再以(l,mid-1)和(mid+1,r)重复1,2
vector<int> sortArray(vector<int>& nums) {
        quickSort(nums, 0, nums.size() - 1);
        return nums;
    }
    void quickSort(vector<int>& nums, int l, int r) {
        if (l >= r) return;
        int mid = dfs(nums, l, r);
        quickSort(nums, l, mid - 1);
        quickSort(nums, mid + 1, r);
        
    }
    int dfs(vector<int>& nums, int l, int r) {
        int i = rand()%(r - l + 1) +l;
        swap(nums[i],nums[l]);
        int cur = nums[l];
        while (l < r) {
            while (l < r and nums[r] >= cur) r--;
            nums[l] = nums[r];
            while (l < r and nums[l] <= cur) l++;
            nums[r] = nums[l];
        }
        nums[l] = cur;
        return l;
    }

1.3归并排序

稳定排序,平均 O(nlogn),最好 O(nlogn), 最差 O(nlogn),辅助空间 O(n)
归并排序的主要思想是分治法。主要过程是:

  • 将n个元素从中间切开,分成两部分。(左边可能比右边多1个数)
  • 将步骤1分成的两部分,再分别进行递归分解。直到所有部分的元素个数都为1。
  • 从最底层开始逐步合并两个排好序的数列。
    在这里插入图片描述
    思路:
  1. 确定数组的大小,以及输入数组中的元素值;将输入的数组进行分组归并;
  2. 将整个数组分成左右两个数组,左右两个数组再向下分,直至子数组的元素少于2个时(first >= last,),子数组将停止分割;
    **[注]: **找到其中中点,不断划分成mergeSort(nums, first, mid, temp) ; mergeSort(nums, mid + 1, last, temp);
  3. 当左右子数组不能再分割,也是都是一个元素时,比较他们的大小,进行排序合并;
  • (针对nums)让l(左序列指针)=firstr(右序列指针)=mid+1 ,再设置一个temp数组的指针 i=0;
  • 在l<=mid且r<=last的条件下 比较左右序列元素的大小,小的那个等于nums[i++] ,然后同时l++或r++
  • 若左右序列还有剩(l<=mid或r<=last),在将左边或右边的剩余元素填充进temp中
  • 最后将temp里面的元素拷贝给nums
  1. 再排序合并上一级子数组为两个元素的数组,接着再排序合并上一级子数组为四个元素的数组;直至到排序合并刚开始的两个子数组,最后成为排好序的数组;
class Solution {
    void MergeSort(vector<int>& nums, int first, int last, vector<int>& temp) {
        if (first >= last) return;
        int mid = (first + last) / 2;
        MergeSort(nums, first, mid, temp);
        MergeSort(nums, mid + 1, last, temp);
        int i = 0, l = first,  r = mid + 1;
        while (l <= mid and r <= last) {
            if (nums[l] >= nums[r]) temp[i++] = nums[r++];
            else {
                temp[i++] = nums[l++];
            }
        }
        while (l <= mid) temp[i++] = nums[l++];
        while (r <= last) temp[i++] = nums[r++];
        i = 0;
        for (int j = first; j <= last; ++j) {
            nums[j] = temp[i++];
        }
    }
public:
    vector<int> sortArray(vector<int>& nums) {
        int n = nums.size();
        if (n < 2) return nums;
        vector<int> temp(n, 0);
        MergeSort(nums, 0, n - 1, temp);
        return nums;
    }
};

1.4 堆排序

堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

  • 先构造一个大顶堆:
  1. 从数组长度len的len/2-1位置开始调整位置,一直到0
    for (int i = len / 2 - 1; i >= 0; --i )
  2. 调整:将位置k为根的子树进行调整,先保存最开始需要比较的结点的值nums[k],它的左孩子位置为2*k+1,看它的右孩子是否存在并且比较与左孩子的关系,拿大的值和nums[k]进行比较。若nums[k]大,则说明不用交换,直接break。若它的孩子大,则交换值,并令k=i,继续循环.最后再令nums[k]=temp;
  • 然后交换堆顶元素(最大值)和堆底元素,再根据新的堆顶重新调整堆
class Solution {
    void Bulid(vector<int>& nums, int len) {          //构造一个大顶堆
        for (int i = len / 2 - 1; i >= 0; --i ) {
            Adjust(nums, i, len);
        }
    }
    void Adjust(vector<int>& nums, int k, int len) {
        int temp = nums[k];
        for (int i = 2 * k + 1; i < len; i = 2 * i + 1) {
            if (i < len - 1 and nums[i] < nums[i + 1]) ++i;
            if (temp > nums[i]) break;
            else {
                nums[k] = nums[i];
                k = i;
            }
        }
        nums[k] = temp;
    }
    void HeapSort(vector<int>& nums, int len) {    //堆排序函数
        Bulid(nums, len);
        for (int i = len - 1; i >= 0; --i) {
            swap(nums[i], nums[0]);
            Adjust(nums, 0, i);
        }

    }
public:
    vector<int> sortArray(vector<int>& nums) {
        int n = nums.size();
        if (n < 2) return nums;
        HeapSort(nums, n);
        return nums;
    }
};

1.5 插入排序

稳定排序,平均 O(n2),最好 O(n), 最差 O(n2),辅助空间 O(1)

将一个数插入一个已经排好序的数据中:

直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。

  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 如果被扫描的元素(已排序)大于新元素,将该元素后移一位
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置后
  6. 重复步骤2~5
// 稳定排序,平均 O(n**2),最好 O(n), 最差 O(n**2),辅助空间 O(1)
void InsertSort(vector<int> &nums)
{
    int n = nums.size();
    if (n==0) return;
    // 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的
    for (int i=1;i<n;i++)
    {
          // 记录要插入的数据
          int temp  = nums[i];
          int j = i- 1;
          //与已排序的数逐一比较,大于temp时,该数移后
          while (j>=0) && (temp < nums[j])
          {
                nums[j+1] = nums[j];
                j--;
          }
          nums[j+1] = temp;
    }
}

2 最小K个数

  • 思路一: 直接排序
  • 思路二:用大顶堆(从大到小)priority_queue<int> q
    当q的size小于K,就填充进去,否则比较top和arr[i]的大小,若top大,则pop,再将arr[i]放进去,始终保持里面是最小的K个数。
    vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
        if (input.size() == 0 or k == 0) return {};
        priority_queue<int> q;
        for (auto c : input) {
            if (q.size() < k) q.emplace(c);
            else {
                if (q.top() > c) {
                    q.pop();
                    q.emplace(c);
                }
            }
        }
        vector<int> res;
        while (!q.empty()) {
            res.emplace_back(q.top());
            q.pop();
        }
        return res;
    }
  • 思路三:快排优化:
    第一次快排后,会返回哨兵的位置l,若l >k,则对左边序列继续快排,若l<k则对右边序列继续快排,l=k时,新建一个数组并v.assign(arr.begin(), arr.begin() + k);
    vector<int> GetLeastNumbers_Solution(vector<int>& nums, int k) {
        quickSort(nums, 0, nums.size() - 1, k);
        vector<int> res(nums.begin(), nums.begin() + k);
        return res;
    }
    
    void quickSort(vector<int>& nums, int l, int r, int k) {
        if (l >= r) return;
        int first = l;
        int last = r;
        int i = rand() % (r - l + 1) + l;
        swap(nums[i], nums[l]);
        int cur = nums[l];
        while (l < r) {
            while (l < r and nums[r] >= cur) r--;
            nums[l] = nums[r];
            while (l < r and nums[l] <= cur) l++;
            nums[r] = nums[l];
        }
        nums[l] = cur;
        if (l > k) quickSort(nums, first, l - 1, k);
        if (l < k) quickSort(nums, l + 1, last, k);
        return;
    }

附:手撕大小顶堆??

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

  • 思路一: 直接排序
  • 思路二:用小顶堆(从小到大)priority_queue<int, vector<int>, greater<int>>q;
    当q的size小于K,就填充进去,否则比较top和arr[i]的大小,若top小,则pop,再将arr[i]放进去,始终保持堆顶是第K个最大数。
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int, vector<int>, greater<int>> q;
        for (auto c : nums) {
            q.emplace(c);
            if (q.size() > k) q.pop();
        }
        return q.top();
        
    }
        
  • 思路三:快排优化
    排序好后,数组中的第K个最大元素位置是index = nums.size() - k
    第一次快排后,会返回哨兵的位置l,若l >index,则对左边序列继续快排,若l<index则对右边序列继续快排,l=k时 返回nums[l]
    int findKthLargest(vector<int>& nums, int k) {
        
        return quickSort(nums, 0, nums.size() - 1, k);

    }
    int quickSort(vector<int> nums, int l, int r, int k) {
        if (l >= r) return nums[l];
        int index = nums.size() - k;
        int first = l;
        int last = r;
        int i = rand() % (r - l + 1) + l;
        swap(nums[i], nums[l]);
        int cur = nums[l];
        while (l < r) {
            while (l < r and nums[r] >= cur) r--;
            nums[l] = nums[r];
            while (l < r and nums[l] <= cur) l++;
            nums[r] = nums[l];
        }
        nums[l] = cur;
        
        if (l < index) return quickSort(nums, l + 1, last, k);
        
        if (l > index) return quickSort(nums, first, l - 1, k);
        
        return nums[l];
    }
        

4 合并区间

区间:Interval a = [A,B] a.start = A, a.end = B
思路1:双指针 + 排序

  • 首先排序,将二维数组按首个数字进行排序sort(nums.begin(), nums.end());,第i区间的起始值≤ 第i-1区间的起始值
  • 设置两个指针u=0,v=1,排序后所有nums[u][0] <= nums[v][0]
  • 排序后,有三种情况:
    在这里插入图片描述
  1. [1,2], [3,4] nums[u][1] < nums[v][0] 即:u区间与v区间没有交集,直接将u添加进res,并令u=v,v++
  2. [1,4],[2,3] 或[1,5],[2,5] nums[u][1] > nums[v][1] 即:u区间完全包含v区间,直接v++
  3. [1,5] ,[2, 6] nums[u][1] < nums[v][1] 即u区间与v区间有交集,令 nums[u][1] = nums[v][1]; 再v++;
  • 最后v = nums.size()时退出循环,还需要将此时的nums[u]放进res;
    【注】:第三种情况应该最后讨论,(只要在第一种情况不满足时,才考虑他,不然会导致只有一个区间,因为第三种情况实际的条件是nums[u][1] < nums[v][1] andnums[u][1] < nums[v][0]
vector<vector<int>> merge(vector<vector<int>>& nums) {
        if (nums.size() == 0 or nums.size() == 1) return nums;
        int u = 0;
        int v = 1;
        vector<vector<int>> res;
        sort(nums.begin(), nums.end());
        while (v < nums.size()) {
            if (nums[u][1] < nums[v][0]) {   //前者最大小于后者最小
                res.emplace_back(nums[u]);
                u = v; 
                
            }
            else if (nums[u][1] <= nums[v][1]) {
                nums[u][1] = nums[v][1];      
            }           
            v++;
        }
        res.emplace_back(nums[u]);
        return res;

区间版:

    vector<Interval> merge(vector<Interval> &intervals) {
        if (intervals.size() == 0 or intervals.size() == 1) return intervals;
        sort(intervals.begin(),intervals.end(),cmp);//排序
         vector<Interval>ans;//返回的结果数组
        int p1 = 0, p2 = 1;
        while (p2 < intervals.size()) {
            if (intervals[p1].end < intervals[p2].start) {
                ans.emplace_back(intervals[p1]);
                p1 = p2;
            }
            else if (intervals[p1].end < intervals[p2].end) intervals[p1].end = intervals[p2].end;
            p2++;
        }
         ans.emplace_back(intervals[p1]);
         return ans;
        
    }
    static bool cmp(Interval &a, Interval &b) {
        if (a.start == b.start) return a.end < b.end;
        return a.start < b.start;
    }

5 最大数

定义一个新的比较函数。必须是static bool型的,因为std::sort是属于全局的,无法调用非静态成员函数;或者在该类的上方定义
static静态成员函数不用加对象名,就能直接访问函数
若排序后str第一个是‘0’则返回“0”

    string largestNumber(vector<int>& nums) {
        if (nums.size() == 1) return to_string(nums[0]);
        sort(nums.begin(), nums.end(), cmp);
        string str;
        for (auto c : nums) str += to_string(c);
        if(str[0] == '0') return "0";
        return str;

    }

    static bool cmp(const int& a, const int& b) {
        return to_string(a) + to_string(b) > to_string(b) + to_string(a);
    }

6 单链表排序

思路一:归并+切

  • 快慢指针找中点,这里需要设置一个pre,在只需要切一次的时候不会用到,但是在这里,若链表长度为2,没有pre会导致栈溢出。返回slow。
  • 合并两个有序链表
  • 归并,注意归并时若链表长度为1,即head->next = nullprt,则返回head
    ListNode* sortList(ListNode* head) {
        if (!head or !head->next) return head;
        return mergeSort(head);
    }
    ListNode* cut(ListNode* head) {
        ListNode* pre = nullptr;
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast and fast->next) {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        pre->next = nullptr;
        return slow;
    }
    ListNode* merge(ListNode* l1, ListNode* l2) {
        ListNode* dummy = new ListNode(0);
        ListNode* p = dummy;
        while(l1 and l2) {
            if (l1->val > l2->val) {
                p->next = l2;
                l2 = l2->next;
            }
            else {
                p->next = l1;
                l1 = l1->next;
            }
            p = p->next;
        }
        p->next = l1 ? l1 : l2;
        return dummy->next;
    }
    ListNode* mergeSort(ListNode* head) {
        if (!head->next) return head;
        ListNode* mid = cut(head);
        ListNode* l1 = mergeSort(head);
        ListNode* l2 = mergeSort(mid);
        return merge(l1, l2);
    }
    

7 奇偶链表

奇数节点串联 oddnode->next = oddnode->next->next;
偶数节点串联 evennode->next = evennode->next->next;

    ListNode* oddEvenList(ListNode* head) {
        if (!head or !head->next) return head;
        ListNode* evenhead = head->next;
        ListNode* odd = head;
        ListNode* even =evenhead;
        while (even and even->next) {
            odd->next = odd->next->next;
            even->next = even->next->next;
            odd = odd->next;
            even = even->next;
        }
        odd->next = evenhead;
        return head;
    }

8 数据流中的中位数

思路:

  • 中位数< 它右边的数,大于它左边的数,因此根据左半边数的最大值及右半边数的最小值即可得到中位数。因此构建一个大顶堆放左边的数,小顶堆放右边的数。
  • 若输入的数据个数是奇数,比如 1、2、3、4、5。我们可以把左边的 1、2 存入一个大顶堆中,把右边的 3、4、5 存入一个小顶堆中。那么中位数就是小顶堆的 top()。
  • 若输入的数据个数是偶数,比如 1、2、3、4。我们可以把左边的 1、2 存入一个大顶堆中,把右边的 3、4 存入一个小顶堆中。那么中位数就是两个堆的 top() 的和再乘 0.5。
  • 整个过程我们需要维护两个地方:两个堆的 size() 最大只能相差 1;大顶堆的 top() 必须小于等于小顶堆的 top()。

实现:保持了两个堆的size最大只相差1(要么相等,要么小顶堆size大1)

  • 若大顶堆的size = 小顶堆的size,数据先添加进大顶堆,再将大顶堆的top到小顶堆。
  • 否则数据先进入小顶堆,数据先添加进小顶堆,再将小顶堆的top到大顶堆。
  • 输出的时候,只需要观察两个堆size,若相同,则两个堆顶求和 * 0.5(不能/2因为/以后强制化整),若不同返回小顶堆top()
class MedianFinder {
    priority_queue<int> maxheap;
    priority_queue<int, vector<int>, greater<int>> minheap;

public:
    /** initialize your data structure here. */
    MedianFinder() {

    }
    
    void addNum(int num) {
        if (maxheap.size() == minheap.size()) {
            maxheap.emplace(num);
            minheap.emplace(maxheap.top());
            maxheap.pop();
        }
        else {
            minheap.emplace(num);
            maxheap.emplace(minheap.top());
            minheap.pop();
        }
    }
    
    double findMedian() {
        return maxheap.size() == minheap.size() ? (maxheap.top() + minheap.top()) * 0.5 : minheap.top();

    }
};

9 前 K 个高频元素

TOPK问题,想到priority_queue,前K大,用小顶堆。
哈希表记录元素和出现的频率
因为比较的是频率,输出的是对应的元素,因此需要将他们作为一对pair一起放入堆里,且必须得是q.emplace(make_pair(it.second, it.first));频率在前,元素在后,(因为比较的是频率
对于里面元素是pair<int,int>的堆,创建时应该
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;

    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> ma;
        vector<int> res;
        for (auto& c : nums) ma[c]++;
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
        for (auto& it : ma) {
            if (q.size() < k) q.emplace(make_pair(it.second, it.first));
            else {
                if (it.second > q.top().first) {
                    q.pop();
                    q.emplace(make_pair(it.second, it.first));
                }
            }
        }
        while (!q.empty()) {
            res.emplace_back(q.top().second);
            q.pop();
        }
        return res;
    }

10 和为 K 的子数组

前缀和:
在这里插入图片描述
eg:
在这里插入图片描述

10.1 返回个数

题目就可以由:有多少个[i,j]使得从第 i 到 j 项的子数组和等于 k。
转变为有几种 i、j 的组合,满足 prefixSum[j] - prefixSum[i - 1] == k
找出前缀和之差=k的次数

  • unordered_map<int, int> ma;key表示前缀和,value表示出现的次数

  • 因为i-1是在j之前的,所以去找prefixsum[j]-k 在哈希表里出现的次数

  • ma[0] = 1,表示最开始时,前缀和为0的情况出现了一次
    需要初始化的原因是,为了防止漏掉prefixsum[j]恰好等于k的情况
    例如[1,1,1] k = 2
    i = 0, prefixsum= 1; hash={1,1}
    i = 1, prefixsum= 2; hash={1,1}{2,1} 此时出现了prefixsum =k的情况,但是此时prefixsum - k = 0,在哈希表里没有出现,所以漏掉了

    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> ma;
        ma[0] = 1;
        int prefixSum = 0;
        int res = 0;
        for (auto c : nums) {
            prefixSum += c;
            if (ma.count(prefixSum - k)) res += ma[prefixSum - k];
            ma[prefixSum]++;
        }
        return res;
    }

10.2 返回最长长度

要返回最长长度,需要记录下前缀和和位置

  • unordered_map<int, int> ma;key表示前缀和,value表示位置i
  • if (ma.count(prefixSum - k)),此时更新最大长度max(i - ma[prefixSum - k], maxL);
  • 同时为避免后面也出现相同的prefixSum,因此若哈希表中没有prefixSum时,才将它放入哈希表
    eg[1,-1,1,2,3] i=0和i=3时,perfixsum均为1,若不限制的添加perfixsum,会使最大长度减小。
  • ma[0] = -1。表示前缀和为0的位置为-1。
    int maxlenEqualK(vector<int>& arr, int k) {
        // write code here
        int prefixSum = 0;
        int maxL = 0;
        unordered_map<int, int> ma;
        ma[0] = -1;
        for (int i = 0; i < arr.size(); ++i) {
            prefixSum += arr[i];
            if (ma.count(prefixSum - k)) {
                maxL =max(i - ma[prefixSum - k], maxL);
            }
            if (!ma.count(prefixSum))ma[prefixSum] = i;
        }
        return maxL;
    }

11 前K个高频单词(字符串出现次数的TopK问题)

本来想用和上面一样的方法,但是由于要求当不同的字符串有相同出现频率,按字典序排序。行不通
,因为当q.size()<k时,他是直接填充,排序也是根据int来的,无法在频率相同时,根据字符来排序[[“2”,“174”],[“9”,“166”],[“6”,“148”],[“1”,“148”]]

所以想到用仿函数+小顶堆
小堆序实现从大到小排序,大堆序实现从小到大排序
频率从大到小,字符从小到大
因为频率相同时,需要比较字符,所以所有的都需要先进队列,size>k时再弹出
因为小顶堆堆顶是最小的,所以可以用res[i] = q.top().first; i--

    struct cmp {
        bool operator() (pair<string, int> a, pair<string, int> b) {
            return a.second== b.second ? a.first < b.first ? a.second > b.second;
        }
    };

例如ma={‘a’,1}{‘c’,2}{‘b’, 2}
第一次比较 cab, 第二次比较cba,第三次比较bca
返回出现次数前k名的字符串

class Solution {
    struct cmp {
        bool operator() (pair<string, int> a, pair<string, int> b){
            return a.second == b.second ? a.first < b.first : a.second > b.second;
        }
    };
public:
    vector<string> topKFrequent(vector<string>& words, int k) {
        unordered_map<string, int> ma;
        for (auto& c : words) ma[c]++;
        priority_queue<pair<string, int>, vector<pair<string, int>>, cmp> q;
        for (auto& it : ma) {           
            q.emplace(it);
            if (q.size() > k) q.pop();
        }
        vector<string> res(k);
        for (int i = k - 1; i >= 0; --i) {
            res[i] = q.top().first;
            q.pop();
        }
        return res;
    }
};

返回出现次数前k名的字符串和对应的次数。

class Solution {
    struct cmp {
      bool operator() (pair<string, int> a, pair<string, int> b) {
          return a.second == b.second ? a.first < b.first : a.second > b.second;
      }  
    };
public:
    /**
     * return topK string
     * @param strings string字符串vector strings
     * @param k int整型 the k
     * @return string字符串vector<vector<>>
     */
    vector<vector<string> > topKstrings(vector<string>& strings, int k) {
        // write code here
        unordered_map<string, int> ma;
        for (auto& c : strings) ma[c]++;
        priority_queue<pair<string, int>, vector<pair<string, int>>, cmp> q;
        for (auto& it : ma) {
            q.emplace(it);
            if (q.size() > k) q.pop();
        }
        vector<vector<string> > res(k, vector<string>(2));
        for (int i = k - 1; i >= 0; --i) {
            res[i] = {q.top().first, to_string(q.top().second)};
            q.pop();
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值