【算法题】牛客研发最爱考[31 - 40]

刷题链接

合并k个有序链表(堆多路归并)

用堆进行多路归并,时间复杂度 O ( n l o g k ) O(nlogk) O(nlogk)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
    
    
        typedef pair<int,ListNode*> PIL;
        priority_queue<PIL,vector<PIL>,greater<PIL>> heap; // 小根堆
        
        
        for(auto &c : lists)
            if(c) heap.push({
    
    c->val,c});
        
        ListNode *head = new ListNode(-1);
        auto cur = head;
        
        while(heap.size())
        {
    
    
            auto t = heap.top();
            heap.pop();
            
            ListNode* p = t.second;
            cur->next = p;
            cur = cur->next;
            
            auto next = p->next;
            if(next) heap.push({
    
    next->val,next});
        }
        
        cur->next = NULL;
        return head->next;
    }
};

字符串的排列(有重复)

递归实现排列

class Solution {
    
    
public:
    
    vector<string> res;
    vector<bool> st;
    int n;
    string s;
    string path;
    
    vector<string> Permutation(string str) {
    
    
        s = str;
        n = s.size();
        st = vector<bool>(n);
        
        dfs(0);
        return res;
    }
    
    void dfs(int u)
    {
    
    
        if(u == n)
        {
    
    
            res.push_back(path);
            return;
        }
        
        for(int i = 0;i < n;i ++ )
            if(!st[i])
            {
    
    
                path.push_back(s[i]);
                st[i] = true;
                dfs(u + 1);
                st[i] = false;
                path.pop_back();
                
                while(i + 1 < n && s[i + 1] == s[i]) i ++ ;
            }
    }
};

next_permutation()函数返回下一个排列

class Solution {
    
    
public:
    
    vector<string> res;
    
    vector<string> Permutation(string str) {
    
    
        sort(str.begin(),str.end());
        do{
    
    
            res.push_back(str);
        }while(next_permutation(str.begin(), str.end()));
        
        return res;
    }
};

斐波那契数列(递推)

递推

class Solution {
    
    
public:
    int Fibonacci(int n) {
    
    
        if(n <= 1) return n;
        
        int a = 0,b = 1, c;
        for(int i = 1;i < n;i ++ )
        {
    
    
            c = a + b;
            a = b, b = c;
        }
        return c;
    }
};

最长递增子序列(求具体方案,贪心 + 二分)

贪心 + 二分,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
增加记录方案的dp[i] : 表示下标为i的元素长度为dp[i]。

class Solution {
    
    
public:
    /**
     * retrun the longest increasing subsequence
     * @param arr int整型vector the array
     * @return int整型vector
     */
    vector<int> LIS(vector<int>& arr) {
    
    
        // write code here
        int n = arr.size();
        vector<int> q(n + 1); // 贪心二分,q[i]表示长度为i的最小元素是q[i]
        
        vector<int> dp(n); // 记录方案,dp[i]表示下标为i的元素长度是dp[i]
        
        int len = 0;
        for(int i = 0;i < n;i ++ )
        {
    
    
            int l = 0,r = len; // 二分找第一个小于arr[i]的数,下一个数即为>=arr[i]
            while(l < r)
            {
    
    
                int mid = l + r + 1>> 1;
                if(q[mid] < arr[i]) l = mid;
                else r = mid - 1;
            }
            dp[i] = r + 1;
            len = max(len,r + 1);
            q[r + 1] = arr[i];
            
        }
        
        vector<int> res(len);
        //cout << len <<endl;
        for(int i = 0;i < n;i ++) cout << dp[i] <<" ";
        for(int i = n - 1;len >= 1;i -- )  // 从后往前遍历,在后面的一定是字典序最小的(贪心决定)
            if(dp[i] == len){
    
    
                res[len - 1] = arr[i]; // res下标从0开始,所以要-1
                len --;
            }
        return res;
    }
};

在转动过的有序数组中寻找目标值(二分)

二分找分界点,再根据if(target <= A[n - 1])判断是在前半段还是后半段

class Solution {
    
    
public:
    /**
     * 
     * @param A int整型一维数组 
     * @param n int A数组长度
     * @param target int整型 
     * @return int整型
     */
    int search(int* A, int n, int target) {
    
    
        // write code here
        int l = 0,r = n - 1;
        while(l < r)
        {
    
    
            int mid = l + r >> 1;
            if(A[mid] <= A[n - 1]) r = mid;
            else l = mid + 1;
        }
        
        if(target <= A[n - 1]) r = n - 1; // 后半段
        else l = 0, r -- ; // 前半段
        while(l < r)
        {
    
    
            int mid = l + r >> 1;
            if(A[mid] >= target) r = mid;
            else l = mid + 1;
        }
        if(A[l] != target) return -1;
        return l;
    }
};

数组中相加和为0的三元组(排序 + 双指针)

排序 + 双指针,时间复杂度 O ( n 2 ) O(n ^ 2) O(n2)

class Solution {
    
    
public:
    vector<vector<int> > res;
    vector<vector<int> > threeSum(vector<int> &num) {
    
    
        int n = num.size();
        sort(num.begin(),num.end());
        
        for(int i = 0;i < n;i ++ )
        {
    
    
            if(i != 0 && num[i] == num[i - 1]) continue;
            
            int l = i + 1,r = n - 1;
            
            while(l < r)
            {
    
    
                int sum = num[i] + num[l] + num[r];
                if(sum > 0)
                {
    
    
                    r -- ;
                    continue;
                }
                else if(sum < 0)
                {
    
    
                    l ++;
                    continue;
                }
                
                res.push_back({
    
    num[i] , num[l] , num[r]});
                // 去重
                do{
    
    l ++ ;}while(l < r && num[l] == num[l -1 ]);
                do{
    
    r -- ;}while(l < r && num[r] == num[r + 1]);
            }
            
        }
        return res;
    }
};

最长回文子串(枚举,双指针)

class Solution {
    
    
public:
    int getLongestPalindrome(string s, int n) {
    
    
        // write code here
        /*
            以每个点为中心向两边扩展,回文串为奇数和偶数
        */
        int len = 0;
        for(int k = 0;k < n; k ++ )
        {
    
    
            // 回文串是奇数
            int i = k, j = k;
            while(i >= 0 && j < n && s[i] == s[j]) i --, j ++ ;
            len = max(len,j - i - 1);
            
            // 回文串是偶数
            i = k,j = k + 1;
            while(i >= 0 && j < n && s[i] == s[j]) i --, j ++ ;
            len = max(len,j - i - 1);
        }
        return len;
    }
};

容器盛水问题(单调栈)

class Solution {
    
    
public:
    /**
     * max water
     * @param arr int整型vector the array
     * @return long长整型
     */
    long long maxWater(vector<int>& arr) {
    
    
        // write code here
        stack<int> stk; // 维护一个单调下降的栈
        int n = arr.size();
        long long res = 0;
        for(int i = 0;i < n;i ++ )
        {
    
    
            while(stk.size() && arr[i] >= arr[stk.top()]) // 单调栈存的是下标
            {
    
    
                int bottom = stk.top();
                stk.pop();
                if(stk.empty()) break;
                
                int r = i;
                int l = stk.top();
                res += (long long)(r - l - 1) * (min(arr[r],arr[l]) - arr[bottom]);
            }
            stk.push(i);
        }
        return res;
    }
};

单链表的排序(归并排序)

前置知识:1. 快慢指针 2. 归并排序 3. 合并两个有序链表
题解

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

class Solution {
    
    
public:
    /**
     * 
     * @param head ListNode类 the head node
     * @return ListNode类
     */
    ListNode* sortInList(ListNode* head) {
    
    
        // write code here
        if(!head || !head->next) return head;
        
        auto fast = head,slow = head;
        while(fast->next && fast->next->next)
        {
    
    
            fast = fast->next->next;
            slow = slow->next;
        }
        
        fast = slow;
        slow = slow->next; // slow 指向中间节点
        fast->next = NULL;
        
        // 归并排序
        ListNode *left = sortInList(head);
        ListNode *right = sortInList(slow);
        return merge_sort(left,right);
        
        
    }
    
    ListNode* merge_sort(ListNode *l1,ListNode *l2)
    {
    
    
        ListNode *dummy = new ListNode(-1);
        auto cur = dummy;
        
        while(l1 && l2)
        {
    
    
            if(l1->val < l2->val)
            {
    
    
                cur->next = l1;
                l1 = l1->next;
            }
            else{
    
    
                cur->next = l2;
                l2 = l2->next;
            }
            cur = cur->next;
        }
        cur->next = l1 == NULL ? l2 : l1;
        
        return dummy->next;
    }
};

二叉树的镜像(递归)

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
    
    
public:
    void Mirror(TreeNode *pRoot) {
    
    
        dfs(pRoot);
    }
    
    void dfs(TreeNode *root)
    {
    
    
        if(!root) return ;
        auto left = root->left,right = root->right;
        root->left = right,root->right = left;
        dfs(root->left);
        dfs(root->right);
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_43154149/article/details/113823257
40