一、进制转换
题目: 将一个十进制数据转换为八进制
分析: 在我们学习计算机基础知识的时候, 知道怎么将一个十进制转换为二进制. 对十进制数不断的除以二并对二取余数. 得到的余数反过来就是想要的结果.
这里转换为八进制同理.
- 首先定义一个栈, 每一次取余就把余数进栈,并且把数据除以二
- 当数据为0时, 证明数据已经除成0了
- 直接出栈即为我们想要的数据
代码:
void conversion(int N){
int stackSize = 10;//栈大小
int *stack = (int *)malloc(stackSize * sizeof(int));//栈空间
int top = -1;//栈顶
int v = N;
while (v) {
//栈满了扩充
if (v == stackSize - 1) {
stack = realloc(stack, stackSize * 2);
stackSize = stackSize * 2;
}
//取余
stack[++top] = v % 8;
v = v / 8;
}
//打印出栈里的结果
while (top != -1) {
printf("%d", stack[top--]);
}
printf("\n");
}
二、有效的括号(LeetCode 20)
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
分析:
- 括号都是成对的出现, 每出现一个左括号就一定会有一个右括号
- 碰到左括号就入栈, 右括号出栈
- 当碰到右括号出栈的时候, 判断栈顶的括号是否匹配当前右括号
bool isValid(char * s){
//长度
int len = (int)strlen(s);
//括号是成对出现, 奇数长度字符串一定是错误的
if (len % 2 != 0) {
return false;
}
//栈空间只需要小于等于字符串的一半. 因为只需要入栈字符串长度一半的括号,入栈超过这个长度都是错误的
int *stack = (int *)malloc(len / 2 * sizeof(int));
int top = -1;
for (int i = 0; i < len; i++) {
switch (s[i]) {
case '(':
case '[':
case '{':
//满栈还继续入账肯定是错误的
if (top == len / 2 - 1) {
return false;
}
stack[++top] = s[i];
break;
case ')':
if (stack[top--] != '(') {
return false;
}
break;
case ']':
if (stack[top--] != '[') {
return false;
}
break;
case '}':
if (stack[top--] != '{') {
return false;
}
break;
default:
break;
}
}
return true;
}
三、每日温度(LeetCode 739)
题目: 根据每日气温列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置0来代替。例如,给定一个列表temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是[1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是[1, 30000]。每个气温的值的均为华氏度,都是在[30, 100]范围内的整数。 解题关键: 实际上就是找当前元素 从[i,TSize] 找到大于该元素时. 数了几次. 首先最后一个元素默认是0,因为它后面已经没有元素了.
3.1、暴力法
分析:
- 从左到右按顺序遍历到倒数第二个, 最后一个后面没有元素, 默认为0
- 当前温度与前一个温度一样时, 可以取前一个温度的记录值减一, 特殊判断是否为0
- 从i+1个开始向后遍历,直到找到比i这个位置数据大的
int *dailyTemperatures(int* T, int TSize, int* returnSize){
int *result = (int *)alloca(sizeof(int) * TSize);
result[TSize - 1] = 0;
for (int i = 0; i < TSize - 1; i++) {
//当这个气温与前一个气温相同, 则可以直接读取前一个气温的记录值减去一, 得判断一下是否为0
if (i > 0 && T[i] == T[i - 1]) {
result[i] = result[i] == 0 ? 0 : result[i - 1] - 1;
break;
}
for (int j = i + 1; j < TSize; j++) {
if (T[i] < T[j]) {
result[i] = j - i;
break;
}
if (j == TSize - 1) {
result[i] = 0;
}
}
}
return result;
}
3.2、跳跃对比法
分析:
- 从倒数第二个记为i向左遍历, 最后一天的默认为0
- 从[i+1, TSize]开始遍历记为j.
- 若T[i] < T[j], 则记录j-i
- 若result[j] == 0, 则后面不会存在比T[j]更大的数,达到减少遍历的效果
代码:
//每日气温跳跃对比法
int *dailyTemperatures(int* T, int TSize, int* returnSize){
int *result = (int *)alloca(sizeof(int) * TSize);
result[TSize - 1] = 0;
for (int i = TSize - 2; i >= 0; i--) {
for (int j = i + 1; j < TSize; j++) {
if (T[i] < T[j]) {
result[i] = j - i;
} else if (result[j] == 0) {
result[i] = 0;
break;
}
}
}
return result;
}
3.2、栈方法
分析:
- 初始化一个栈, 用来记录温度的下标index
- 从左向右遍历, 第一次直接入栈
- 从第二个开始i, 拿到温度, 空栈则直接入栈, 否则与栈顶做对比, 低于则i入栈, 高于则出栈
- 出栈后再继续与栈顶对比, 低于则入栈, 高于则出栈 , 重复此步骤
- 直到栈为空或者碰到栈顶元素大于当前元素,则停止对比, 直接入栈
代码:
//每日气温栈
int *dailyTemperatures_3(int* T, int TSize, int* returnSize){
//此处返回的记录长度即等于传过来的天气长度
*returnSize = TSize;
//返回的数据
int *result = (int *)malloc(sizeof(int) * TSize);
//清空
for (int i = 0; i < TSize; i++) {
result[i] = 0;
}
//栈
int *stack = (int *)malloc(sizeof(int) * TSize);
int top = -1;
//遍历
for (int i = 0; i < TSize - 1; i++) {
while (top >= 0 && T[stack[top]] < T[i]) {
//记录温差数据
result[stack[top]] = i - stack[top];
//出栈操作
top--;
}
//入栈
stack[++top] = i;
}
free(stack);
return result;
}
四、杨辉三角(LeetCode 118)
给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
分析:
- 需要控制两层循环
- 外层循环i : 由图可知,每一层代表外部循环, 一层中的头尾均为1
- 内存循环j : 每一层的内部循环triangle[i][j] = triangle[i - 1][j] + triangle[i - 1][j - 1]
//numRows: 行数
//returnSize: 数组大小, 指有多少行
//returnColumnSizes: 每一行数组大小 [2, 3, 4...]
int** generate(int numRows, int* returnSize, int** returnColumnSizes){
*returnSize = numRows;
*returnColumnSizes = (int*)malloc(numRows * sizeof(int));
int **res = (int **)malloc(sizeof(int *) * numRows);
for (int i = 0; i < numRows; i++) {
res[i]=(int *)malloc(sizeof(int) * (i + 1));
res[i][0] = 1;
res[i][i] = 1;
(*returnColumnSizes)[i] = i + 1;
for (int j = 1; j < i; j++) {
res[i][j] = res[i - 1][j] + res[i - 1][j - 1];
}
}
return res;
}
五、爬楼梯(LeetCode 70)
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
5.1、递归求解
分析:
- 每一次走无非两种情况, 要么一步要么两步
- 拿出每一次走步来模拟要是是1要么是2
- 递归这个走步函数
代码:
int ClimbStairs(int n){
if (n<1) return 0;
if (n == 1) return 1;
if (n == 2) return 2;
return ClimbStairs(n-1) + ClimbStairs_1(n-2);
}
5.2、动态规划法
分析:
| 层 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 方法 | 0 | 1 | 2 | 3 | 5 | 8 | 13 |
- 假设n层有f(n)种可能
- 假设走1步, 剩下n-1层就有f(n-1)种方法
- 假设走2步, 剩下n-2层就有f(n-2)种方法
- 已经走了n阶可以转化为上面两种走法的问题的和 f(n) = f(n-1) + f(n-2)
代码:
int ClimbStairs(int n){
if(n==1) return 1;
int *sum = (int *)malloc(sizeof(int) * n + 1);
sum[0] = 0;
sum[1] = 1;
sum[2] = 2;
for (int i = 3; i <= n; i++) {
sum[i] = sum[i-1] + sum[i-2];
}
return sum[n];
}
六、字符串解码(LeetCode 394)
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像3a或2[4]的输入。
示例:
s = "3[a]2[bc]", 返回 "aaabcbc". s = "3[a2[c]]", 返回 "accaccacc". s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".
分析:
- 以 ] 为界限分割成一个组合, 每次遍历不是 ] , 则入栈
- 遇到 ] 后出栈, 直到碰到 [, 记录下每次出栈的字符
- 遇到 [ 后, 继续出栈, 记录数字, 直到遇到不在0-9范围内的字符,或者栈为空
- 根据记录的数字循环次数创建记录的字符
- 继续向下遍历查找 ]
代码:
char * decodeString(char * s){
int len = (int)strlen(s);
int stackSize = len;
//+1是为存最后的\0
char *stack = (char *)malloc(sizeof(char) * stackSize + 1);
int top = -1;
for (int i = 0; i < len; i++) {
if (s[i] != ']') {
//入栈
if (top == stackSize - 1) {
stack = (char *)realloc(stack, stackSize * 2 + 1);
stackSize = stackSize * 2;
}
stack[++top] = s[i];
} else {
//遍历 [ 与 ] 中间的字母
int zmSize = 50;
char *tempZM = (char *)malloc(sizeof(char) * zmSize);
int tempZMTop = -1;
while (stack[top] != '[') {
if (tempZMTop == zmSize - 1) {
tempZM = (char *)realloc(tempZM, zmSize * 2);
zmSize = zmSize * 2;
}
tempZM[++tempZMTop] = stack[top--];
}
//此时栈顶是 [
top--;
//遍历获取数字
char strOfInt[11];
int tempTop = top;//记录当前栈顶
//遍历到数字的其实位置
while ((top > -1) && (stack[top] >= '0') && (stack[top] <= '9')) {
top--;
}
//存储数字字符
for (int j = top + 1; j <= tempTop; ++j) {
strOfInt[j - (top + 1)] = stack[j];
}
//在数字字符末尾补\0
strOfInt[tempTop - (top + 1) + 1] = '\0';
//char 转 int
int sum = atoi(strOfInt);
//根据记录数字循环创建字符
for (int j = 0; j < sum; j++) {
//此时字符是倒叙的
for (int k = tempZMTop; k > -1; k--) {
if (top == stackSize - 1) {
stack = (char *)realloc(stack, stackSize * 2 + 1);
stackSize = stackSize * 2;
}
stack[++top] = tempZM[k];
}
}
free(tempZM);
}
}
//末尾补0
stack[++top] = '\0';
return stack;
}