150. 逆波兰表达式求值
根据 逆波兰表示法,求表达式的值。
有效的运算符包括 + , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
- 输入: ["2", "1", "+", "3", " * "]
- 输出: 9
- 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
思路:
1、遇到数字进栈
2、遇到运算符,pop出两个数字进行运算,将结果进栈
**注意:
1、字符串比较 注意Comparison with string literal results in unspecified behaviour
在C ++中,== 仅在内部为原始类型(如int、char、bool…)实现,而 const char* 不是原始类型,因此const char* 和字符串会作为两个char* 比较,即两个指针的比较,而这是两个不同的指针,“connection”== nextElement->Name()不可能为真。
可以使用:
1. 使用std::string保存字符串,通过其"==" 运算符重载比较两字符串,无需获取指针;
2. 使用 strcmp 比较char*和const char*,字符串相等则返回0;
原文链接:https://blog.youkuaiyun.com/xb_2015/article/details/118738192
2、atoi函数
将字符串直接转换成整型数据的操作
eg:将字符串 “ -12345” 转换成了整数 -12345 atoi("-12345")=-12345
3、注意是怎么判断是数字\符号的
符号:char==‘+’? 注意是单引号
单引号‘+’ 是指向ascii码,“+”表示这是一个字符串
数字:有两个问题:要把字符串转化成数字(用atoi解决);要区分0~9和字符
其实理论上也可以先把符号挑出来,其他的全部丢进atoi
4、char**怎么处理
char** 指向一个数组,数组中每一项的内容是字符串
形如:["2","1","+","3","*"]
通过这种方式读出每一项:
for (int i=0;i<tokensSize;i++){
char* p=tokens[i];
代码:
typedef struct {
int data[20000];
int top;
}listnode;
void push(listnode *l,int e){
l->data[++l->top]=e;
}
int pop(listnode *l){
int e=l->data[l->top--];
return e;
}
int evalRPN(char** tokens, int tokensSize) {
listnode*l=(listnode*)malloc(sizeof(listnode));
l->top=-1;
for (int i=0;i<tokensSize;i++){
char* p=tokens[i];
if(strlen(p)>1 || (p[0]>='0' && p[0]<='9')){
//为数字,考虑是多位数 一位数(用ascii码区别符号和一位数)的情况
push(l,atoi(p));
}
else{
int b=pop(l);
int a=pop(l);
if(p[0]=='+'){
push(l,a+b);
}
else if(p[0]=='-'){
push(l,a-b);
}
else if(p[0]=='*'){
push(l,a*b);
}
else{
push(l,a/b);
}
}
}
return pop(l);
}
239. 滑动窗口最大值
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
进阶:
你能在线性时间复杂度内解决此题吗?
思路:
只需要关心某一段中最大的元素,最小的元素可以丢掉
采用 单调队列,出口处是最大值
设计单调队列的时候,pop,和push操作要保持如下规则:
1、pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
2、push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
在实际操作时,前k个元素进队时不需要返回最大值,故而单独拎出来操作
**注意:
一、在leetcode中返回数组
1、需要再分配空间
2、需要给*returnsize赋值 / 用*returnsize作为answer的序号
eg:
int *answer=(int *)malloc(sizeof(int)*(numsSize-k+1));
int *returnSize=numsSize-k+1;
二、两端都是入口出口的队列
通过改变push pop中 front和rear的变化规则可以实现
区别++front &front++
代码:
typedef struct {
int data[500000];
int front,rear;
}listnode;
bool empty(listnode *l){
if(l->front==l->rear) return true;;
return false;
}
void push(listnode *l,int e){
while(!empty(l) && e>l->data[l->rear]){//新来的元素,比队列前面的元素大,把队列里的全pop
l->rear--;
}
l->data[++l->rear]=e;//队列为空,新来的元素小,新来的元素大——最终都要放入新来的元素
}
void pop(listnode*l,int nowmax){
if(nowmax ==l->data[l->front+1]){//需要pop的情况
l->front++;
}
}
int getmax(listnode*l){
return l->data[l->front+1];
}
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
listnode *l=(listnode *)malloc(sizeof(listnode));
l->front=-1;
l->rear=-1;
int maxnumber;
//对于0~k-1 第一个窗口需要push k次,getmax一次,故而单独写出
for (int i=0;i<k;i++){
push(l,nums[i]);
}
int *answer=(int *)malloc(sizeof(int)*(numsSize-k+1));
answer[0]=getmax(l);
int answer_n=1;
//对于k~numszie-1,每移动一次窗口:是否需要移出元素,是否需要移入元素,修改窗口后 得到最大值
for (int i=k;i<numsSize;i++){
pop(l,nums[i-k]);
push(l,nums[i]);
answer[answer_n++]=getmax(l);
}
*returnSize=numsSize-k+1;
return answer;
}
347.前 K 个高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
- 输入: nums = [1,1,1,2,2,3], k = 2
- 输出: [1,2]
1、用快速排序的方法(利用qsort函数简化)
qsort函数:
qsort写法:void qsort(s, n, sizeof(s[0]), cmp);
第一个参数是参与排序的数组名(也就是开始排序的地址,所以&s[i],也是可以的)。
第二个参数是参与排序的元素的个数。
第三个参数是单个元素的大小(sizeof(s[0])这样就是获取到s[0]的元素大小)。
第四个参数是一个函数,定义qsort排序排序规则的函数。
原文链接:https://blog.youkuaiyun.com/qq_43448856/article/details/112749222
//定义结构体,记录数字及其出现的次数
struct Times{
int num;
int cnt;
};
//用于初始数组nums的排序
int cmp(const void* a,const void* b){
return *(int*)a - *(int*)b;
}
//用于结构体的一级排序
int cmps(const void* a,const void* b){
return (*(struct Times*)b).cnt - (*(struct Times*)a).cnt;
}
int* topKFrequent(int* nums, int numsSize, int k, int* returnSize){
*returnSize = k;
int* res = (int*)malloc(sizeof(int)*k);
struct Times time[numsSize];
int index=0;
//1.对初始数组nums进行排序
qsort(nums,numsSize,sizeof(int),cmp);
//2.遍历计算各个数字出现的次数
time[index].num = nums[0];
time[index].cnt = 1;
for(int i=1;i<numsSize;i++){
if(nums[i]==nums[i-1])time[index].cnt++;
else{
time[++index].num = nums[i];
time[index].cnt = 1;
}
}
//3.对结构体数组按出现次数降序排序
qsort(time,index+1,sizeof(struct Times),cmps);
//4.返回前k个数字
for(int i=0;i<k;i++){
res[i] = time[i].num;
}
return res;
}
//作者:Shaw 链接:https://leetcode.cn/problems/top-k-frequent-elements/solutions/404234/bi-jiao-zhi-bai-de-si-lu-he-jian-dan-de-dai-ma-jie/
2、堆排序
优先队列
堆
1、用大顶堆还是小顶堆:
假如用大顶堆:定义一个大小为k的大顶堆,在每次移动更新大顶堆的时候,每次弹出都把最大的元素弹出去了,那么怎么保留下来前K个高频元素呢。
故而用小顶堆,要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。
不断把较小元素弹出,留下较大元素
2、具体过程
先放入k个元素,初始化堆
若新的元素比堆顶大,则弹出堆顶,放入新的元素至堆顶,调整至小顶堆
**使用的注意事项:
1、sift函数:将low位置的元素,按大顶堆or小顶堆的规则向下安置至合适的位置,high是实取
以小顶堆为例:
找到孩子中较小的那个(要求孩子结点编号j<high)
与孩子中较小的项进行比较,父结点>较小孩子,则父结点与较小孩子 交换位置
直至父结点<孩子中较小的那个(即比两个孩子都小)
2、初始化堆:
找到倒数第二排最后一个结点,从这个结点向前sift(堆,移动结点i,总长度);
(因为最后一排的结点不可能再下沉了)
3、要记得!比较的是value值!
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
typedef struct {
int key;
int value;
}record;
//用于初始数组nums的排序
int cmp(const void* a,const void* b){
return *(int*)a - *(int*)b;
}
void sift(record* a,int low,int high){//给low安置一个合适的位置
int i=low,j=2*i+1;//因为是从0开始,两个孩子分布对应2i+1 和2i+2
record tmp=a[i];
while(j<=high){
if(j<high && a[j].value>a[j+1].value) j++;//j落在更小的孩子上
if(tmp.value>a[j].value){
a[i]=a[j];
i=j;
j=2*i+1;
}
else break;
}
a[i]=tmp;
}
int* topKFrequent(int* nums, int numsSize, int k, int* returnSize) {
record *r=(record*)malloc(sizeof(record)*numsSize);//记录频率
record *a=(record *)malloc(sizeof(record)*k);//记录堆排序的过程
int *ans=(int *)malloc(sizeof(int)*k);//记录key
*returnSize=k;
int t=0;
qsort(nums,numsSize,sizeof(int),cmp);//从大到小排序,方便录入record
r[0].key=nums[0];
r[0].value=1;
for(int i=1;i<numsSize;i++){
if(nums[i]==r[t].key) r[t].value++;
else{
r[++t].key=nums[i];
r[t].value=1;
}
}
int j=0;
for (int i=0;i<k;i++){
a[j++]=r[i];
}
for(int i=(k-2)/2;i>=0;i--){
sift(a,i,k-1);
}
for(int i=k;i<=t;i++){
if(r[i].value>a[0].value){
a[0]=r[i];
sift(a,0,k-1);
}
}
for(int i=0;i<k;i++){
ans[i]=a[k-1-i].key;
}
return ans;
}