牛客top高频刷题

1,快速排序

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 将给定数组排序
     * @param arr int整型vector 待排序的数组
     * @return int整型vector
     */
    void quickSort(vector<int>& arr, int left, int right) {
        // 定界
        if (left >= right) {
            return;
        }
        int i = left, j = right;
        int base = arr[left];
        while (i < j) {
            while((i < j) && (arr[j] >= base)) {
                j--;
            }
            
            while((i < j) && (arr[i] <= base)) {
                i++;
            }
            if (i < j) {
                swap(arr[i], arr[j]);
            }
        }
        arr[left] = arr[i];
        arr[i] = base;
        quickSort(arr, left, i - 1);
        quickSort(arr, i + 1, right);
    }
    vector<int> MySort(vector<int>& arr) {
        int len = arr.size();
        if (len == 0) {
            return arr;
        }
        quickSort(arr, 0, len - 1);
        return arr;
    }
};

2,数组的归并排序

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 将给定数组排序
     * @param arr int整型vector 待排序的数组
     * @return int整型vector
         归并排序
     */
    void merge(int left, int mid, int right, vector<int>& arr) {
        int i = left, j = mid + 1;
        int k = 0;
        vector<int>temp(right - left + 1, 0);
        while(i <= mid && j <= right) {
            if (arr[i] < arr[j]) {
                temp[k++] = arr[i++];
            } else {
                temp[k++] = arr[j++];
            }
        }
        
        while(i <= mid) {
            temp[k++] = arr[i++];
        }
        
        while(j <= right) {
            temp[k++] = arr[j++];
        }
        
        int index = 0;
        for(int i = left; i <= right; i++) {
            arr[i] = temp[index++];
        }
    }
    
    void guibing(int left, int right, vector<int>& arr) {
        if (left >= right) {
            return;
        }
        int mid = (left + right) / 2;
        guibing(left, mid, arr);
        guibing(mid + 1, right, arr);
        merge(left, mid, right, arr);
    }
    
    vector<int> MySort(vector<int>& arr) {
        guibing(0, arr.size() - 1, arr);
        return arr;
    }
};

3,链表的归并排序


https://www.nowcoder.com/practice/f23604257af94d939848729b1a5cda08

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param head ListNode类 the head node
     * @return ListNode类
     */
    ListNode* sortInList(ListNode* head) {
        if (!head || !head->next) {
            return head;
        }
        ListNode* mid = getMid(head);
        ListNode *left = sortInList(head);
        ListNode *right = sortInList(mid);
        return Merge(left, right);        
    }
    
    ListNode* getMid(ListNode* head) {
        if(!head) {
            return head;
        }
        ListNode* fast = head, *slow = head;
        ListNode* prev = slow;
        while(fast && fast->next) {
            prev = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        prev->next = nullptr; // 切断mid和之前的联系,mid属于后面
        return slow;
    }
    
    ListNode *Merge(ListNode *l1, ListNode *l2) {
        if (!l1) {
            l2;
        }
        if (!l2) {
            l1;
        }
        ListNode *head = new ListNode(-1);
        ListNode *ret = head;
        while(l1 && l2) {
            if (l1->val < l2->val) {
                ret->next = new ListNode(l1->val);
                l1 = l1->next;
            } else {
                ret->next = new ListNode(l2->val);
                l2 = l2->next;
            }
            ret = ret->next;
        }
        if (l1) {
            ret->next = l1;
        }
        if (l2) {
            ret->next = l2;
        }
        return head->next;
    }
    

};

4,寻找第K大


使用快速排序,利用左面的都比base小,右面的都比base大这件事。

class Solution {
public:
    int findKth(vector<int> a, int n, int K) {
        return quickfind(a, 0, n-1, K);
    }
     
    int quickfind(vector<int>& a, int left, int right, int k) {
        int i = left;
        int j = right;
        int mark = a[left];
         
        while (i < j) {
            while (i < j && a[j] >= mark)
                --j;
            
             
            while (i < j && a[i] <= mark)
                ++i;
          
            if (i < j) {
                int temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
        a[left] = a[i];
        a[i] = mark;
        
         
        //哨兵右侧比他大的数字个数
        int big_num = right - i;
        
        //如果哨兵刚好是第K大的数
        if (k - big_num - 1 == 0)
            return mark;
        else if (k - big_num - 1 > 0) {
            //如果右侧数字个数不够K个,则从左侧找第k-big_num-1大的数
            return quickfind(a, left, i - 1, k - big_num - 1);
        } else {
            //如果右侧数字个数比K多,则在右侧找第K大的数
            return quickfind(a, i + 1, right, k);
        }
    }
};

5,NC41 最长无重复子数组


在这里插入图片描述

class Solution {
public:
    /**
     * 
     * @param arr int整型vector the array
     * @return int整型
     */
         /*
    最长无重复子数组
        1,使用map记录数组中各个元素出现位置
        2, 若遇到重复的, 找到之前最近的一个重复的值,记为index
        3,index+1(认为是start)~i的距离是ret的候选人,不断更新最大值。
        ret = max(ret, [index + 1, i])
    */
    int maxLength(vector<int>& arr) {
        // write code here
        int len = arr.size();
        int ret = 0, start = 0;
        map<int, int>mp;
        for (int i = 0; i < len; i++) {
            // 如果找到重复的,开始刷新ret
            if(mp.find(arr[i]) != mp.end()) {
                start = max(start, mp[arr[i]] + 1);
            }
            ret = max(ret, i - start + 1);
            // 更新位置
            mp[arr[i]] = i;
        }
        return ret;
        
    }
};

6,字符串出现次数的topK问题


在这里插入图片描述

class Solution {
public:
    /**
     * return topK string
     * @param strings string字符串vector strings
     * @param k int整型 the k
     * @return string字符串vector<vector<>>
     */
    /*
        使用map记录每个字符串出现的次数
        将map的东西放在vector中,对vec进行排序和输出,重点是比较功能
    */
    static bool cmp(vector<string> &a, vector<string> &b) {
        if (a[1] == b[1]) {
            return a[0] < b[0];
        }
        return stoi(a[1]) > stoi(b[1]);
    }
    
    vector<vector<string> > topKstrings(vector<string>& strings, int k) {
        // write code here
        int len = strings.size();
        map<string, int>mp;
        // 1, 将数据记录到map中
        for (int i = 0; i < len; i++) {
            mp[strings[i]]++;
        }
        
        map<string, int>::iterator it = mp.begin();
        vector<vector<string>> ret;
        // 2, 将数据记录到vector中
        for (; it != mp.end(); it++) {
            ret.push_back({it->first, to_string(it->second)});
        }
        // 3,比较
        sort(ret.begin(), ret.end(), cmp);
        
        ret.resize(k);
        return ret;
    }
};

7,未排序数组中累加和为给定值的数组最大长度


在这里插入图片描述

class Solution {
public:
    /**
     * max length of the subarray sum = k
     * @param arr int整型vector the array
     * @param k int整型 target
     * @return int整型
     */
    /*
        遍历arr,S(i) 表示arr[0, i]的和,使用map记录这些前缀和。
        S(j)表示从[0,j]的前缀和
        若s[i] - s[j] = target,那么[i + 1, j]就是候选人之一,使用ret不断刷新。
        为了防止漏掉0, mp插入(0,-1)。
    */
    int maxlenEqualK(vector<int>& arr, int k) {
        int len = arr.size();
        map<int, int>mp;
        int sum = 0;
        int ret = 0;
        mp[0] = -1;
        for (int i = 0; i < len; i++) {
            sum += arr[i];
            // 在mp中寻找s(i)
            if (mp.find(sum) == mp.end()) {
                mp[sum] = i;
            }
            if (mp.find(sum - k) != mp.end()) {
                ret = max(ret, i - mp[sum - k]);
            }
        }
        return ret;
    }
};

8,信封嵌套问题


在这里插入图片描述

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param letters intvector<vector<>> 
     * @return int
     */
       /*
        二维问题是信封嵌套,一维问题就是一个数组中最长递增子序列是多少。
        如何将二维问题转化成一维问题呢?
        信封=长X宽。
        1,先对长进行递增排序,若长相等的,宽度要递减排序
        所以从后遍历,若宽度>前面的,表示后面可以嵌套前面的。
*/
    static bool cmp(vector<int> &a, vector<int> &b) {
        if (a[0] == b[0]) {
            return a[1] > b[1];
        }
        return a[0] < b[0];
    }
    int maxLetters(vector<vector<int> >& letters) {
        // write code here
        // 对输入进行判断
        if(letters.size() == 0) {
            return 0;
        }
        int len = letters.size();
        sort(letters.begin(), letters.end(), cmp);
        vector<int>dp(len, 1);
        int ret = 1;
        for (int i = 1; i < len; i++) {
            for (int j = 0; j < i; j++) {
                if (letters[i][1] > letters[j][1]) {
                    dp[i] = max(dp[i], dp[j] + 1);
                }
                ret = max (ret, dp[i]);
            }
        }
        return ret;
    }
};

9,信封嵌套问题


在这里插入图片描述
层次遍历
打印Z字形
右视图
寻找next
这四种都是层次遍历的变形。

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;
    Node* next;

    Node() : val(0), left(NULL), right(NULL), next(NULL) {}

    Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

    Node(int _val, Node* _left, Node* _right, Node* _next)
        : val(_val), left(_left), right(_right), next(_next) {}
};
*/

/*
    层次遍历,设置pre和curr节点
*/
class Solution {
public:
    Node* connect(Node* root) {
        if(!root) {
            return root;
        }

        queue<Node*> que;
        que.push(root);
        Node *preNode, *currNode; 

        while(!que.empty()) {
            int size = que.size();
            int cnt = 0;
            while(cnt < size) {
                if (cnt == 0) {
                    preNode = currNode = que.front();
                    que.pop();
                } else {
                    currNode = que.front();
                    que.pop();
                    preNode->next = currNode;
                    preNode = preNode->next;
                }

                if (currNode->left) {
                    que.push(currNode->left);
                }
                if (currNode->right) {
                    que.push(currNode->right);
                }
                cnt++;
            }
        }
        
        return root;
        
    }
};

9,560. 和为 K 的子数组


在这里插入图片描述

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        /*
            map<sum, vector<int>>; --map<int, int就可以
            表示vector<i>之前的,包括i,和为sum
            遍历到i
            看map<i - k>是否存在,
            如果存在
            cnt + map[i-k]
        */
        int len = nums.size();
        if (len == 0) {
            return 0;
        }
        int ret = 0, sum = 0;
        map<int, int>mp;
        mp[0] = 1;
        for (int i = 0; i < nums.size(); i++) {
            sum += nums[i];            
            if (mp.find(sum - k) != mp.end()) {
                ret += mp[sum - k];
            }

            mp[sum]++;
            
        }
        return ret;

    }
};

10,297. 二叉树的序列化与反序列化

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
 /*
 序列化和反序列化
 序列化:
 前序遍历,遇到空的string后面添加“NULL,”,其他数字加“,”
 反序列化:
 将上面的string 拆解在list中
 list<string>list
 然后开始反序列化,遇到NULL,擦除list的头部+返回nullptr
 开始左右递归。

 */
class Codec {
public:

    void reserialize(TreeNode *root, string &data) {
        if (!root) {
            data += "NULL,";
            return;
        }

        data += to_string(root->val) + ",";
        reserialize(root->left, data);
        reserialize(root->right, data);
    }

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        string ret;
        reserialize(root, ret);
        return ret;
    }

    TreeNode* redeserialize(list<string> &arr) {
        if (arr.front() == "NULL") {
            arr.erase(arr.begin());
            return nullptr;
        }

        TreeNode *root = new TreeNode(stoi(arr.front()));
        arr.erase(arr.begin());
        root->left = redeserialize(arr);
        root->right = redeserialize(arr);
        return root;
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        int len = data.size();
        if (len == 0) {
            return nullptr;
        }

        string str;
        list<string> dataArr;
        for (int i = 0; i < data.size(); i++) {
            if (data[i] == ',') {
                dataArr.push_back(str);
                str.clear();
            } else {
                str += data[i];
            }
        }
        if (!str.empty()) {
            dataArr.push_back(str);
        }

        return redeserialize(dataArr);
        
    }
};

// Your Codec object will be instantiated and called as such:
// Codec ser, deser;
// TreeNode* ans = deser.deserialize(ser.serialize(root));

11,253. 会议室 II

class Solution {
public:

    static bool cmp(vector<int> &a, vector<int> &b) {
        if (a[0] == b[0]) {
            return a[1] > b[1];
        }

        return a[0] < b[0];
    }

    int minMeetingRooms(vector<vector<int>>& intervals) {
        /*
            按照会议开始时间升序排列,
            if(当前开始时间 > 上一个结束时间) {
                pq pop// 因为当前和上面是可以共用的
                将当前开始时间push到队列中
            } else {
                将当前开始时间push到队列中
            }
            return pq.size();
        */

        int len = intervals.size();
        if (len == 0 || len == 1) {
            return len;
        }
        sort (intervals.begin(), intervals.end(), cmp);

        priority_queue<int, vector<int>, greater<int>> pq;
        pq.push(intervals[0][1]);
        int ret = 1;
        for (int i = 1; i < len; i++) {
            if (intervals[i][0] >= pq.top()) {
                pq.pop();
            }
            pq.push(intervals[i][1]);
        }
        return pq.size();
    }
};

12,994. 腐烂的橘子


在这里插入图片描述

class Solution {
public:
    int orangesRotting(vector<vector<int>>& grid) {
        if (grid.size() == 0) {
            return 0;
        } 

        // 1, 遍历当前数组中的腐烂句子
        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[i].size(); ++j) {
                if (grid[i][j] == 2)
                    dfs(grid, i, j, 2);
            }
        }
        
        // 2, 计算形成最后的画面需要的最长时间
        int maxTime = 0;
        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[i].size(); ++j) {
                if (grid[i][j] == 1) {
                    return -1;
                } else {
                    maxTime = max(maxTime, grid[i][j]);
                }
            }
        }
        return maxTime == 0 ? 0 : maxTime - 2;
    }

    void dfs(vector<vector<int>>& grid, int x, int y, int time) {
        // 基本定界
        if (x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size()) {
            return;
        }
        
        // 如果grid不是新鲜橘子而且到这里腐烂的时间<time,说明之前已经遍历过了
        if (grid[x][y] != 1 && grid[x][y] < time) {
            return;
        }
        grid[x][y] = time;

        dfs(grid, x + 1, y, time + 1);
        dfs(grid, x - 1, y, time + 1);
        dfs(grid, x, y + 1, time + 1);
        dfs(grid, x, y - 1, time + 1);
    }
};

13,128. 最长连续序列


在这里插入图片描述

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        if(nums.empty()){
            return 0;
        }
        unordered_set<int> myset(nums.begin(), nums.end());
        int res = 0;
        
        for(auto num : nums){
            if(myset.count(num-1)==0){
                int x = num + 1;
                while(myset.count(x)){
                    x ++;
                }
                res = max(res, x-num);
            }
        }
        return res;
    }
};

14,49. 字母异位词分组


在这里插入图片描述

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        vector<vector<string>>ret;
        map<string, vector<string>>mp;

        for (auto n : strs) {
            auto temp = n;
            sort(temp.begin(), temp.end());
            mp[temp].push_back(n);
        }

        for(auto n : mp) {
            ret.push_back(n.second);
        }

        return ret;
    }
};

15,3. 无重复字符的最长子串


在这里插入图片描述

class Solution {
public:
/*
    以当前数字为起始位置的最长子串
*/
    int lengthOfLongestSubstring(string s) {
        int len = s.size();
        if(len == 0 || len == 1) {
            return len;
        }
        int ret = 0;
        for (int i = 0; i < len; i++) {
            map<char, int>mp;
            int cnt = 0;
            for (int j = i; j < len; j++) {
                if (mp.find(s[j]) == mp.end()) {
                    mp[s[j]]++;
                    cnt++;
                } else {
                    break;
                }
                ret = max (ret, cnt);
            }
        }
        return ret;

    }
};

16,面试题 16.25. LRU 缓存


在这里插入图片描述

class LRUCache {
public:
    map<int,int> mp, vis; // 使用map存储键值 + 版本号机制
    queue<pair<int,int>> que;
    int cnt, cap, currSize;

    LRUCache(int capacity) {
        cap = capacity; // 容量
        cnt = 0;  // 用来位置版本号 
        currSize = 0; // 当前缓存的个数
    }
    
    int get(int key) {
        // 如果在visited中找不到key, return -1
        if (vis[key] == 0) {
            return -1;
        }

        // 一把更新,cnt用来维持版本号,保证每次版本号都不同
        que.push({key, vis[key] = ++ cnt});

        return mp[key];
    }
    
    void put(int key, int value) {
      // 如果当前的版本号和现在的版本号一样,说明没有被操作过,也就是最久没有被访问过的,需要被pop
        if(!vis[key]){
            while(currSize == cap){
                auto front = que.front();
                que.pop();
                if(vis[front.first] == front.second){
                    // 这里是把它降为0,而不是erase
                    vis[front.first] = 0;
                    --currSize;
                    break;
                }
            }
            ++currSize;
        }

        mp[key]=value;
        que.push({key,vis[key] =++cnt});
    }
};

17,694. 不同岛屿的数量


在这里插入图片描述

class Solution {
public:
/*
如何计算呢?
使用string计算路径。上下左右分布是1,2,3,4 反向分别是-1-2-3-4
set<string>st;
st.insert()
最终计算st.size();
1,使用string来表示对应的路径,还有回溯的思想,使用-dir表示已经回头。
2,使用set去重,因此set.size可以直接表示ret
*/
    void dfs(vector<vector<int>>& grid, int x, int y, string &str, string dir) {
        // 定界
         if(x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size()) {
            return;
        } 
        if (grid[x][y] == 0) {
            return;
        }
        grid[x][y] = 0;
        str += dir;

        dfs(grid, x + 1, y, str, "1");
        dfs(grid, x - 1, y, str, "2");
        dfs(grid, x, y + 1, str, "3");
        dfs(grid, x, y - 1, str, "4");

        str += "-";
        str += dir;
    }
    int numDistinctIslands(vector<vector<int>>& grid) {
        int column = grid.size();
        int line = grid[0].size();
        set<string> st1;
        for (int i = 0; i < column; i++) {
            for (int j = 0; j < line; j++) {
                if (grid[i][j] == 1) {
                    string str = "";
                    dfs(grid, i, j, str, "0");
                    cout << str << endl;
                    st1.insert(str);
                }
            }
        }
        
        return st1.size();
    }
};

18,剑指 Offer 07. 重建二叉树

在这里插入图片描述

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    unordered_map<int, int>mp;
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        int len = pre.size();
        if (len == 0) {
            return nullptr;
        }
        for (int i = 0; i < len; i++) {
            mp[vin[i]] = i;
        }
        return dfs(pre, vin, 0, len - 1, 0, len - 1);
    }
    TreeNode * dfs(vector<int> pre,vector<int> vin, int preLeft, int preRight, int inLeft, int inRight) {
        if (preLeft > preRight || inLeft > inRight) {
            return nullptr;
        }
        // 获取pos
        int pos = mp[pre[preLeft]];
        TreeNode *root = new TreeNode(pre[preLeft]); // 左子树节点的个数为 pos - inLeft
        root->left = dfs(pre, vin, preLeft + 1, preLeft + pos - inLeft, inLeft, pos - 1); // 注意pre的左子树应该去掉首值
        root->right = dfs(pre, vin, preLeft + pos - inLeft + 1, preRight, pos + 1, inRight);
        return root;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值