寒假刷题打卡第二天 | 双指针 & 排序

  1. 判断是否是环形链表
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head==NULL || head->next == NULL)
            return false;
        ListNode *behind = head;
        ListNode *ahead = head->next;  //双指针不一定是一个在前一个在后
        while(behind != ahead)
        {
            if(ahead->next!=NULL && ahead->next->next != NULL)
            {
                ahead = ahead->next->next;
                behind = behind->next;
            }
            else
                return false;
        }
        return true;
    }
};
  1. 最长子序列
    给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删除给定字符串的某些字符来得到。如果答案不止一个,返回长度最长且字典顺序最小的字符串。如果答案不存在,则返回空字符串。
class Solution {
public:
    string findLongestWord(string s, vector<string>& d) {
        int d_size = d.size(), s_ind=0;
        int i1=0,i2=0,j1=s.size(),j2;
        int max_length=0;
        string target="";
        for(;s_ind<d_size;s_ind++)
        {
            i1=0,i2=0;
            string the_sting = d[s_ind];
            j2=the_sting.size();
            while(i1<j1)
            {
                if(s[i1]==the_sting[i2])
                {
                    i1++;
                    i2++;
                }
                else
                {
                    i1++;
                }
            }
            if(i2==j2)
            {
                if(j2>max_length) 
                {
                    max_length=j2;
                    target = the_sting;
                }
                else if(j2==max_length) //第n次把条件判断中的==写成=
                {
                    if(the_sting<target)  //C++可以直接这样判断所谓的字典顺序
                        target = the_sting;
                }
            }
        }
        return target;
    }
};
  1. 找到倒数第 k 小的元素。
    快速排序和堆排序都可以用于找到倒数第k小的元素。找倒数第k小的元素要用大顶堆。当堆中节点数量大于k时,如果此时新插入的元素小于堆顶元素,则删除堆顶元素,从新插入当前元素。插入和删除堆顶元素的时间复杂度都是logN。
    事实上,快拍和堆排还能用于topK问题。对于快排,当找到kth元素时,遍历整个数组,则能得到topK。堆排中保留的K个元素就是topK。(显然堆排的数组中不能有重复的元素。)
    快排:
class Solution {
public:
    int quickSelect(vector<int>& a, int l, int r, int index) {
        int q = partition(a, l, r);
        if (q == index) {
            return a[q];
        } else {
            return q < index ? quickSelect(a, q + 1, r, index) : quickSelect(a, l, q - 1, index);
        }
    }

    inline int partition(vector<int>& a, int l, int r) {
        int x = a[l];
        while(l<r)
        {
            while(a[r]>=x && l<r)
                r--;
            if(l<r)
                swap(a[l],a[r]);
            while(a[l]<=x && l<r)
                l++;
            if(l<r)
                swap(a[l],a[r]);
        }
        a[l]=x;
        return l;
    }

    int findKthLargest(vector<int>& nums, int k) {
        return quickSelect(nums, 0, nums.size() - 1, nums.size() - k);
    }
};

时间复杂度为O(n),空间复杂度O(logN).
最小堆(找最大topk,用最小堆)

class Solution {
public:
    void maxHeapify(vector<int>& a, int i, int heapSize) {
        int l = i * 2 + 1, r = i * 2 + 2, largest = i;
        if (l < heapSize && a[l] > a[largest]) {
            largest = l;
        } 
        if (r < heapSize && a[r] > a[largest]) {
            largest = r;
        }
        if (largest != i) {
            swap(a[i], a[largest]);
            maxHeapify(a, largest, heapSize);
        }
    }

    void buildMaxHeap(vector<int>& a, int heapSize) {
        for (int i = heapSize / 2; i >= 0; --i) {
            maxHeapify(a, i, heapSize);
        } 
    }

    int findKthLargest(vector<int>& nums, int k) {
        int heapSize = nums.size();
        buildMaxHeap(nums, heapSize);
        for (int i = nums.size() - 1; i >= nums.size() - k + 1; --i) {
            swap(nums[0], nums[i]);
            --heapSize;
            maxHeapify(nums, 0, heapSize);
        }
        return nums[0];
    }
};

[C++]数据结构:最大堆MaxHeap的创建与使用

  1. 出现频率最多的 k 个元素
    4.1 基于堆的实现
    一开始的想法是建立hash table,然后把value作为堆的元素。找到最大的k个频率。然后再去遍历hash table,找出对应的key。实际上可以直接把pair作为堆的元素。
    c++中堆有现成的实现,即priority_queue优先队列。
    c++优先队列(priority_queue)用法详解
class Solution { 
public:
    static bool cmp(pair<int, int>& m, pair<int, int>& n) {
        return m.second > n.second;
    }

    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> occurrences;  //unorder_map与map的区别是map内部
        //由红黑树实现,按key排序
        for (auto& v : nums) {  //基于范围的for loop
            occurrences[v]++;
        }

        // pair 的第一个元素代表数组的值,第二个元素代表了该值出现的次数
        priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> q(cmp);
        for (auto& [num, count] : occurrences) {
            if (q.size() == k) {
                if (q.top().second < count) {
                    q.pop();
                    q.emplace(num, count);  //等价于q.push(pair(num, count))
                }
            } else {
                q.emplace(num, count);
            }
        }
        vector<int> ret;
        while (!q.empty()) {
            ret.push_back(q.top().first);
            q.pop();
        }
        return ret;
    }
};

4.2 基于快排的实现(bug版,测试未通过)
bug没有找到。。。

class Solution {
public:
    void qsort(vector<pair<int, int>>& v, int start, int end, int k) {
        if (start==end)
            return;
        pair<int, int> flag = v[start];
        int old_start=start, old_end=end;
        while(end>start)
        {
            while(v[end].second<=flag.second && end>start)
                end--;
            if(end>start)
                swap(v[start], v[end]);
            while(v[start].second>=flag.second)
                start++;
            if(end>start)
                swap(v[start], v[end]);
        }
        v[start]=flag;
        if(k==start-old_start || k==start-old_start-1)
            return;
        else if (k < start - old_start -1) 
            qsort(v, old_start, start - 1, k);
        else 
            qsort(v, start + 1, old_end, k - (start -old_start + 1));
    }

    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> occurrences;
        for (auto& v: nums) {
            occurrences[v]++;  //value默认为0
        }

        vector<pair<int, int>> values; //这个地方一定要用个vector来接收map,
        //因为map无法根据i来索引
        for (auto& kv: occurrences) {
            values.push_back(kv);
        }
        //注意上面这种写法和下面这种写法的区别
        //for(int i=0;i<s.size();i++)
        //    v.push_back(pair(s[i], m[s[i]]));
        vector<int> ret;
        qsort(values, 0, values.size() - 1, k);
        for (int i = 0; i < k; i++) 
        {
            ret.push_back(values[i].first);
        }
        return ret;
    }
};
  1. 按照字符出现次数对字符串排序
    5.1 快排版
class Solution {
public:
    void quicksort(vector<pair<char,int>>& v, int i, int j)
    {
        if(i>=j)
            return;
        pair<char,int> flag = v[i];
        int oi=i,oj=j;
        while(i<j)
        {
            while(v[j].second <= flag.second && i<j)
                j--;
            if(i<j)
                v[i++]=v[j];
             while(v[i].second >= flag.second && i<j)
                i++;
            if(i<j)
                v[j--]=v[i];
        }
        cout<<"i:"<<i<<endl;
        cout<<"j:"<<j<<endl;
        v[i] = flag;
        quicksort(v, oi, i-1);
        quicksort(v, i+1, oj);
    }
    string frequencySort(string s) {
        string ans = s;
        unordered_map<char, int> m;
        for(auto& x:s)
            m[x]++;
        vector<pair<char,int>> v;
        for(auto& kv : m)
            v.push_back(kv);
        quicksort(v,0,v.size()-1);  //这个地方不是s.size()!!!!!
        int i=0;
        for(auto & kv:v)  // 因为key有重复,所以不能i从0到s.size()来给ans[i]赋值
        {
            while(kv.second--)
            {
                ans[i] = kv.first;
                i++;
            }
        }
        return ans;
    }
};

5.2 堆排

class Solution {
public:
    static bool cmp(pair<char, int>& m, pair<char, int>& n) {
        return m.second < n.second;  //后面这个n代表top,m代表son
    }

    string frequencySort(string s) {
        unordered_map<char,int> m;
        for(auto& x:s)
            m[x]++;
        priority_queue<pair<char, int>, vector<pair<char, int>>, decltype(&cmp)> q(cmp);
        for(auto& x:m)
        {
            q.push(x);
        }
        string ans = s;
        int i=0;
        while(!q.empty())
        {
            int temp = q.top().second;
            char temp_char = q.top().first;
            while(temp--)
            {
                ans[i++] = temp_char;
            }
            q.pop();
        }
        return ans;
    }
};

第5题是一个全排序问题,显然会比找topk 和 kth问题要简单。但是都是可以用堆排和快排来做的。

第二天的任务第四天才完成,怎么这么菜的!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值