//设立一个数组来存储当前窗口中各元素的个数,当新加入的元素导致其出现个数超过2,需要移动左边界,使窗口内的各元素出现次数为1.
//leetcode使用的固定左边界,扩展右边界。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left = 0, right = 0, len = 0;
vector<int> cnt(128, 0);
while (right < s.size()) {
cnt[s[right]]++;
while (cnt[s[right]] > 1)//查找值等于当前元素的位置,左边界移到下一位置,使窗口内各字符不会重复出现
cnt[s[left++]]--;
right++;
len = max(len, right - left);
}
return len;
}
};
//依次合并两个数组,直到到达合并数组的中间时,可以直接求得中位数。
class Solution {
public:
double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2){
int i = 0, j = 0, cnt = 0;
int m = nums2.size(), n = nums1.size();
int mid = (m + n - 1) / 2;
while (cnt < mid && i < n && j < m){ //找中位数的位置,丢弃前(m+n)/2-1个元素
if (nums1[i] < nums2[j])
i++;
else
j++;
cnt++;
}
if (cnt < mid){ //一个数组遍历完
while (cnt < mid){
i == n ? j++ : i++;
cnt++;
}
}
double x;
if ((m + n) % 2){ //根据数组个数的奇偶性确定中位数。
if (i == n)
x = nums2[j];
else if (j == m)
x = nums1[i];
else
x = min(nums1[i], nums2[j]);
}
else{
if (i == n)
x = nums2[j] + nums2[j + 1];
else if (j == m)
x = nums1[i] + nums1[i + 1];
else{//需要找接下来最小的两个数。
int min1 = min(nums1[i], nums2[j]), min2;
if (nums1[i] < nums2[j])
i++;
else
j++;
if (i == n)
min2 = nums2[j];
else if (j == m)
min2 = nums1[i];
else
min2 = min(nums1[i], nums2[j]);
x = min1 + min2;
}
x /= 2;
}
return x;
}
};
//相同的方法,更少的代码。
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int left, right, i = 0, j = 0, k = 0; //left和right用来存放第(m+n)/2和第(m+n)/2+1小的值
int n = nums1.size(), m = nums2.size();
while (k <= (m + n) / 2) {
left = right;
if (i < n && (j >= m || nums1[i] < nums2[j]))
right = nums1[i++];
else
right = nums2[j++];
k++;
}
if ((m + n) & 1)
return right;
else
return (left + right) / 2.0;
}
};
//该题为目标为找出正确的划分线。可以选择在小的数组进行查找划分的位置,
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
unordered_map<string, vector<int>> wordsSet;
int num = 0;
for (auto w : words){ //统计各词的出现次数,并将每个词对应一个整数
if (wordsSet.find(w) != wordsSet.end())
wordsSet[w][0]++;
else
wordsSet[w] = {1, num++};
}
int n = s.size(), m = words[0].size(), k = words.size();
vector<int> vis(num), ans; //vis每个词出现的次数
for (int i = 0; i <= n - m * k; ++i){
auto sub = s.substr(i, m);
if (wordsSet.find(sub) != wordsSet.end()){
for (auto w : wordsSet)
vis[w.second[1]] = w.second[0];
int cnt = k, j = i;
while (wordsSet.find(sub) != wordsSet.end() && vis[wordsSet[sub][1]] > 0){
vis[wordsSet[sub][1]]--;
j = j + m;
sub = s.substr(j, m);
cnt--;
}
if (cnt == 0)//所有词都出现
ans.push_back(i);
}
}
return ans;
}
};
//还可以从第一个单词的每个位置开始,一次移动每个单词的长度,这样在后续比较时,可以跳过一些不可能匹配的子串。
//在原数组上修改。用来记录某个数是否出现过。
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int MinInt = 1, n = nums.size();
for (int i = 0; i < n; ++i){
if (nums[i] < 1)
nums[i] = (n + 1);
}
for (int i = 0; i < n; ++i){
int k = abs(nums[i]) - 1;
if (k < n)
nums[k] = -abs(nums[k]);
}
for (int i = 0; i < n; ++i){
if (nums[i] > 0)
return i + 1;
}
return n + 1;
}
};
//无括号的计算器,使用双栈
class Solution{
stack<int> num;
stack<char> opt;
int compute(){
int p = num.top();num.pop();
int q = num.top();num.pop();
char c = opt.top();opt.pop();
if (c == '*')
return q * p;
else if (c == '/')
return q / p;
else if (c == '+')
return q + p;
return q - p;
}
public:
int calculate(string s){
int n = s.size(), i = 0, ans = 0;
unordered_map<char, int> pri{
{'*', 1}, {'/', 1}, {'+', 0}, {'-', 0}};
//pri['*']=1,pri['/']=1,pri['+']=0,pri['-']=0;
while (i < n){
if (s[i] == ' ')
i++;
else if (!isdigit(s[i])){
while (!opt.empty() && pri[s[i]] <= pri[opt.top()])
num.push(compute());
opt.push(s[i]);
i++;
}else{
int k = 0;
while (i < n && isdigit(s[i]))
k = k * 10 + (s[i++] - '0');
num.push(k);
}
}
while (!opt.empty())
num.push(compute());
return num.top();
}
};
//还可以用栈存储*和/的计算结果,后面再求总和
//一个队列作为压入队栈,一个作为弹出栈,队列当要弹出元素时,如果弹出栈为空,将压入栈的元素压入到弹出栈中。
class MyQueue {
public:
stack<int> inStack, outStack;
void in2out(){
while (!inStack.empty()){
int x = inStack.top();
outStack.push(x);
inStack.pop();
}
}
/** Initialize your data structure here. */
MyQueue() {}
/** Push element x to the back of queue. */
void push(int x){
inStack.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop(){
if (outStack.empty())
in2out();
int x = outStack.top();
outStack.pop();
return x;
}
/** Get the front element. */
int peek(){
if (outStack.empty())
in2out();
return outStack.top();
}
/** Returns whether the queue is empty. */
bool empty(){
return inStack.empty() && outStack.empty();
}
};
//统计树最少未遍历的节点数cnt,遍历一个新节点,cnt--;遇到数字:cnt+=2;
class Solution {
public:
bool isValidSerialization(string preorder){
int n = preorder.size(), i = 0, cnt = 1;
while (i < n){
if (preorder[i] == ',')
i++;
else{
if (!cnt)
return false;
cnt--;
if (preorder[i] != '#')
cnt += 2;
while (i < n && preorder[i] != ',')
i++;
}
}
return cnt == 0;
}
};
//方法:基本方法是申请一个大小为n的数组,用来标记下标为i的数是否出现。因为值全部小于n,所以可以利用原数组来表示,如果下标为i的数出现,则i位置上的数就加n。//或者可以进行排序,排第i个位置时,往后查找为值为i的地址,并交互,则缺失的数会找不到。int*findDisappearedNumbers(int*nums,int numsSize,int*returnSize){
for(int i =0; i < numsSize;++i)
nums[(nums[i]-1)% numsSize]+= numsSize;int*ans =(int*)malloc(sizeof(int)* numsSize);*returnSize =0;for(int i =0; i < numsSize;++i){
if(nums[i]<= numsSize)
ans[(*returnSize)++]= i +1;}return ans;}
//方法:构建两个堆,一个最大堆存储前半部分,一个最小堆存储后半部分,每次只需比较两个堆顶的值和新加入的值,并删掉窗口去掉的值,然后不断维护两个堆。//窗口长度为奇数时,最大堆存储的个数比最小堆多一个,则大堆堆顶的值即为中位数。//leetcode使用了优先队列和延迟删除,主要堆顶的元素不是需要删除的元素,则其作为中位数就不会出错,相当于两个队列将窗口同时往两边扩大。#define MAXSIZE 100000typedefstruct node {
int i, v;} node;voidmaxHeapPush(node* heap,int* s, node k){
int son