一、20.有效的括号
该题是栈的思想的体现,在解决过程中,利用栈的特性,把括号对一对一对消除。在解决问题过程中,遇到几个问题
1 如果len不能被2整除,那么永远消除不完,直接false;
2 括号对匹配,把数组index向前移动,可能还剩下其他字符,因此消除了可以消除的括号对,如果还有“)” 、“] ”、“}”这三个类型的在前面,那么一定不能消除!
下面我写了2种写法:
#if 0
bool isValid(char* s) {
char* str = (char*)malloc(strlen(s));
char* dumpstr = (char*)malloc(strlen(s));
int index = -1;
int dumidx = -1;
if(strlen(s) % 2)
{
return false;
}
for(int i = 0; i < strlen(s); i++)
{
if(s[i] == '(' || s[i] == '{' || s[i] == '[')
{
str[++index] = s[i];
}
else
{
dumpstr[++dumidx] = s[i];
}
/**如果index 不为-1,那么之前填入了字符**/
if(index >= 0 && dumidx >=0)
{
if(s[i] == ')' || s[i] == '}' || s[i] == ']')
{
//printf("12 index = %d char = %c %c\n", index, s[i], str[index]);
if(dumpstr[dumidx] == ')' && str[index] == '(')
{
index--;
dumidx--;
}
else if(dumpstr[dumidx] == '}' && str[index] == '{')
{
index--;
dumidx--;
}
else if(dumpstr[dumidx] == ']' && str[index] == '[')
{
index--;
dumidx--;
}
else
{
return false;
}
}
}
//printf("2 index = %d\n", index);
}
//printf("last index = %d\n", index);
if(index < 0 && dumidx < 0)
return true;
else
return false;
}
#else
//优化思路:malloc数组2个,可以减少1个,
bool isValid(char* s) {
char* str = (char*)malloc(strlen(s));
//char* dumpstr = (char*)malloc(strlen(s));
int index = -1;
//int dumidx = -1;
if(strlen(s) % 2)
{
return false;
}
for(int i = 0; i < strlen(s); i++)
{
if(s[i] == '(' || s[i] == '{' || s[i] == '[')
{
str[++index] = s[i];
}
/**如果index 不为-1,那么之前填入了字符**/
if(index >= 0)
{
if(s[i] == ')' || s[i] == '}' || s[i] == ']')
{
//printf("12 index = %d char = %c %c\n", index, s[i], str[index]);
if(s[i] == ')' && str[index] == '(')
{
index--;
}
else if(s[i] == '}' && str[index] == '{')
{
index--;
}
else if(s[i] == ']' && str[index] == '[')
{
index--;
}
else
{
return false;
}
}
}
else
{
if(s[i] == ')' || s[i] == '}' || s[i] == ']')
{
return false;
}
}
//printf("2 index = %d\n", index);
}
//printf("last index = %d\n", index);
if(index < 0)
return true;
else
return false;
}
#endif
二、1047 删除字符串相邻的字符
利用栈的思想,把首个字符写入字符数组str,然后遍历字符s,从i = 1开始,如果遇到了相等的字符,那么str index减1,这里有一个点,就是index会减到-1,需要另外判断,重新开始赋值,从下一个字符开始,s的i也对应加1(注意不要越界),完成所有的字符遍历,然后字符串str最后加\0
代码如下:
char* removeDuplicates(char* s) {
char* str = (char*)malloc(strlen(s));
if(s == NULL) return NULL;
str[0] = s[0];
int idx = 0;
/**indx**/
for(int i = 1; i < strlen(s); i++)
{
if(idx == -1)
{
str[++idx] = s[i];
if(i < strlen - 1) i++;
//printf("f str%d = %c i= %d\n",idx, str[idx], i);
}
if(str[idx] == s[i])
{
/**遇到可以消除的字符对**/
// printf("str = %c\n", str[idx]);
idx--;
// printf("idx = %d\n", idx);
}
else
{
idx++;
str[idx] = s[i];
}
}
str[++idx] = '\0';
return str;
}
三、150. 逆波兰表达式求值
栈的经典应用,c语言中没有栈相关的直接函数,思路一就是创建一个栈,并例化栈的操作,然后利用栈的操作来解决该题目;其二就是利用栈的思想,用数组作为栈,来解决该题,以下是利用数组方式解决的方案:
解决过程遇到的问题:
1 需要考虑不满足的情况:1)因为加减乘除是双目运算符,因此至少要2个数字才能组成一个计算式,如果第一个字符串或者第二个字符串不是数字,那么不可能算对;2)如果只有一个数字,那么返回原数字;3)如果长度为0 ,即没字符串,那么返回-1;
2 字符转换函数需要判断是正数还是负数,一开始并没有判断正负数,导致计算失误;
3 判断是否是数字串,这里需要注意负数和减法的符号是一样的,因此,需要做判断,如果字符串len有且仅有1个,那么就是减法,否则是负数,那么就是数字,需要保存到数组。
4 判断运算符后,加减乘除,除法和减法,需要理清楚被除数和被减数,另外拿出来2个数字,计算回一个数字,index指向下一个;
/**字符转换函数**/
int transNum(char* s)
{
int num = 0;
int index = 0;
if(s[0] == '-')
{
//负数处理
for(int i = strlen(s) -1; i > 0; i--)
{
if(s[i] <= '9' && s[i] >= '0')//0 ~9
{
num += (s[i] - '0') * pow(10 , index);
index++;
}
}
num = 0 - num;
}
else
{
for(int i = strlen(s) -1; i >= 0; i--)
{
if(s[i] <= '9' && s[i] >= '0')//0 ~9
{
num += (s[i] - '0') * pow(10 , index);
index++;
}
}
}
return num;
}
bool judgeNum(char* s)
{
/**考虑负数**/
if(s[0] == '-')
{
//后面有数字
for(int i = 1; i < strlen(s); i++)
{
if(s[i] > '9' || s[i] < '0')//0 ~9
{
return false;
}
}
if(strlen(s) == 1)
return false;//考虑到'-'字符一个的情况
}
else
{
for(int i = 0; i < strlen(s); i++)
{
if(s[i] > '9' || s[i] < '0')//0 ~9
{
return false;
}
}
}
return true;
}
int evalRPN(char** tokens, int tokensSize) {
//char* arr = (char*)malloc(tokensSize);
int* nums = (int*)malloc(sizeof(int) * tokensSize);
//int nums[1000] = {0};
int index = 0;
//int cal_value = 0;
/**判断不合规的结构:如果一开头不是数字,那么表达式结构有误; 或者只有一个数字**/
if(tokensSize == 1)
{
return transNum(tokens[0]);
}
if(tokensSize == 0 || judgeNum(tokens[0]) == false || judgeNum(tokens[1]) == false)
{
//不是数字,+ - * /都是双目运算符
return -1;
}
//printf("size = %d\n", tokensSize);
for(int i = 0; i < tokensSize; i++)
{
if(judgeNum(tokens[i]))
{
nums[index] = transNum(tokens[i]);
//printf("num%d = %d\n",index, nums[index]);
index++;
}
else
{
index--;//回到上一次位置,拿到数字
char p = tokens[i][0];
//printf("p is %c, index = %d\n", p, index);
int a = 0;
int b = 0;
switch(p)
{
case '+':
/**计算结果重新填进去**/
a = nums[index--];
b = nums[index];
nums[index] = a + b;//覆盖掉之前的数据
break;
case '-':
a = nums[index--];
b = nums[index];
nums[index] = b - a;
break;
case '*':
a = nums[index--];
b = nums[index];
nums[index] = b * a;
break;
case '/':
a = nums[index--];
b = nums[index];
nums[index] = b / a;
break;
}
//跳一个位置,保存数字,继续进行计算
index++;
//printf("switch index = %d\n", index);
}
}
return nums[0];
}