2018年力扣高頻算法面試題3堆棧與隊列

基本計算器1【需二刷】

實現一個基本的計算器來計算一個簡單的字符串表達式的值。
字符串表達式可以包含左括號 ( ,右括號 ),加號 + ,減號 -,非負整數和空格 。
分析:用一個棧來存放 ‘(’ 外計算得到的數值,一個棧用於存放 ‘(’ 外的運算符。如果遇到 ‘)’,就更新一下括號內外表達式的運算結果。

class Solution {
public:
    int calculate(string s) {
        stack <int> nums, ops;
        long num = 0;
        int res = 0;
        int op = 1;
        for (char c : s) {
            if (isdigit(c)) {
                num = num * 10 + c - '0';
            }
            else {
                res += op * num;
                num = 0;
                if (c == '+') op = 1;
                else if (c == '-') op = -1;
                else if (c == '(') {
                    nums.push(res);
                    ops.push(op);
                    res = 0;
                    op = 1;
                }
                else if (c == ')' && ops.size()) {
                    res = ops.top() * res + nums.top();
                    ops.pop();
                    nums.pop();
                }
            }
        }
        res += op * num;
        return res;
    }
};

基本計算器2【需二刷】

實現一個基本的計算器來計算一個簡單的字符串表達式的值。
字符串表達式僅包含非負整數,+, - ,*,/ 四種運算符和空格 。 整數除法僅保留整數部分。

class Solution {
public:
    int calculate(string s) {
        
        long res = 0, num = 0, n = s.size();
        char op = '+';
        stack<int> st;
        
        for (int i = 0; i < n; ++i) 
        {
            if (isdigit(s[i])) 
            {
                num = num * 10 + s[i] - '0';
            }
            if ((s[i] < '0' && s[i] != ' ') || i == n - 1) 
            {
                if (op == '+') st.push(num);
                if (op == '-') st.push(-num);
                if (op == '*' || op == '/') 
                {
                    int tmp = (op == '*') ? st.top() * num : st.top() / num;
                    st.pop();
                    st.push(tmp);
                }
                op = s[i];
                num = 0;
            } 
        }
        while (!st.empty()) {
            res += st.top();
            st.pop();
        }
        return res;
    }
};

基本計算器3【需二刷】

加減乘除以及小括號

class Solution {
public:
    int calculate(string s) {
        long res = 0, curRes = 0, num = 0, n = s.size();
        char op = '+';
        for (int i = 0; i < n; ++i) {
            char c = s[i];
            if (c >= '0' && c <= '9') {
                num = num * 10 + c - '0';
            }
            if (c == '+' || c == '-' || c == '*' || c == '/' || i == n - 1) {
                switch (op) {
                    case '+': curRes += num; break;
                    case '-': curRes -= num; break;
                    case '*': curRes *= num; break;
                    case '/': curRes /= num; break;
                }
                if (c == '+' || c == '-' || i == n - 1) {
                    res += curRes;
                    curRes = 0;
                }
                op = c;
                num = 0;
            } 
        }
        return res;
    }
};

至少有K個重複字符的最長子串【需二刷】

找到給定字符串(由小寫字符組成)中的最長子串 T , 要求 T 中的每一字符出現次數都不少於 k 。輸出 T 的長度。

遍歷字符串,找到出現次數少於k次的字符,位置記爲i,分爲(0,i-1) 和(i+1, s.size() - 1)兩個區間,再遞歸,最後取兩區間的最大值。

int longestSubstring(string s, int k) 
{
	if (!s.size()) return 0;
	int *hashMap = new int[26];
	for (int i = 0; i < 26; i++)
		hashMap[i] = 0;
	for (int i = 0; i < s.size(); i++)  //hashmap[i]表示字符i出現的次數
		hashMap[s[i] - 'a']++;
	int sum = 0;
	bool flag = false;  //記錄是否有小於k次的字符
	for (int i = 0; i < s.size(); i++) 
	{
		if (hashMap[s[i] - 'a'] < k) 
		{
			flag = true;
			sum = max(longestSubstring(s.substr(0, i), k), longestSubstring(s.substr(i + 1, s.size()), k));
			//這裏直接break 如果不break 不影響結果 但影響效率 會重複計算相同的情況
			break;
		}
	}
	if (!flag)
		return s.size();
	return sum;
}

數據流的中位數

中位數是有序列表中間的數。如果列表長度是偶數,中位數則是中間兩個數的平均值。

class MedianFinder {
    priority_queue<int>max;  //從大到小排序
    priority_queue<int,vector<int>,greater<int> >min; //從小到大排序
public:
    MedianFinder() {
    }
    
    void addNum(int num) {
        max.push(num);
        min.push(max.top());
        max.pop();
        if(max.size()<min.size())
        {
            max.push(min.top());
            min.pop();
        }
    }
    
    double findMedian() {
        return (max.size()+min.size())%2 ? max.top() : ((double)max.top()+min.top())/2;
    }
};

滑動窗口最大值

給定一個數組 nums,有一個大小爲 k 的滑動窗口從數組的最左側移動到數組的最右側。你只可以看到在滑動窗口內的 k 個數字。滑動窗口每次只向右移動一位。
返回滑動窗口中的最大值。
分析:題目要求我們代碼的時間複雜度爲 O(n),提示我們要用雙向隊列deque來解題,並提示我們窗口中只留下有用的值,沒用的全移除掉。大概思路是用雙向隊列保存數字的下標,遍歷整個數組,如果此時隊列的首元素是 i-k 的話,表示此時窗口向右移了一步,則移除隊首元素。然後比較隊尾元素和將要進來的值,如果小的話就都移除,然後此時我們把隊首元素加入結果中即可,參見代碼如下:

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) 
    {
        vector<int> res;
        deque<int> q;
        for (int i = 0; i < nums.size(); ++i) 
        {
            if (!q.empty() && q.front() == i - k) q.pop_front();
            while (!q.empty() && nums[q.back()] < nums[i]) q.pop_back();
            q.push_back(i);
            if (i >= k - 1) res.push_back(nums[q.front()]);
        }
        return res;
    }
};

數組中的第K個最大元素

在未排序的數組中找到第 k 個最大的元素。請注意,你需要找的是數組排序後的第 k 個最大的元素,而不是第 k 個不同的元素。
分析:直接用sort()排序肯定是最簡單的方法,但是確不是本題真正想考察的東西,可以說有一定的偷懶嫌疑。
用小跟堆做複雜度是O(n),先把數組的前k個元素push到優先隊列裏面,再循環剩下的元素,如果元素比隊頭元素(優先隊列裏面最小的元素)還要小,continue,否則,刪除隊頭元素,把該元素push到隊列裏面,這樣,循環結束後隊頭元素就是這k個元素裏面最小的元素,即第k個最大元素。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        
        priority_queue<int,vector<int>,greater<int> >q(nums.begin(),nums.begin()+k);
        
        int i=k;
        for(;i<nums.size();i++)
        {
            if(nums[i]<q.top())continue;
            if(nums[i]>q.top())
            {
                q.pop();
                q.push(nums[i]);
            }
        }
        return q.top();
    }
};

有序矩陣中第K小的元素

給定一個 n x n 矩陣,其中每行和每列元素均按升序排序,找到矩陣中第k小的元素。
請注意,它是排序後的第k小元素,而不是第k個元素。
分析:我們使用一個最大堆,然後遍歷數組每一個元素,將其加入堆,根據最大堆的性質,大的元素會排到最前面,然後我們看當前堆中的元素個數是否大於k,大於的話就將首元素去掉,循環結束後我們返回堆中的首元素即爲所求。

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        priority_queue<int>q;
        for(int i=0;i<matrix.size();i++)
        {
            for(int j=0;j<matrix[0].size();j++)
            {
                q.push(matrix[i][j]);
                if(q.size()>k)q.pop();
            }
        }
        return q.top();
    }
};

前 K 個高頻元素

給定一個非空的整數數組,返回其中出現頻率前 k 高的元素。

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        map<int,int>m;
        priority_queue<pair<int,int> >q;
        vector<int>ans;
        for(auto a:nums)
            m[a]++;
        for(auto it:m)
            q.push({it.second,it.first});
        for(int i=0;i<k;i++)
        {
            ans.push_back(q.top().second);
            q.pop();
        }
        return ans;
    }
};

補充題目:

Subarray Sum Equals K

Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose sum equals to k.

方法一:一目瞭然,可以用暴力求解,但是時間複雜度肯定是O(n2)

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int count = 0;
        int n=nums.size();
        for (int start = 0; start < n; start++) {
            int sum=0;
            for (int end = start; end < n; end++) {
                sum+=nums[end];
                if (sum == k)
                    count++;
            }
        }
        return count;
    }
};

方法二:可以利用hashmap記錄和的累加值來避免重複計算
時間複雜度和空間複雜度都是O(n)

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        map<int,int>m;
        m[0]=1;
        int res=0;
        int sum=0;
        for(int i=0,len=nums.size();i<len;i++)
        {
            sum+=nums[i];
            res += m[sum - k];
		   m[sum]++;
        }
        return res;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章