目錄
基本計算器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;
}
};