算法题之数制的转换 字符串编码 字符去重

386 阅读8分钟

数制的转换

题目:

设计一个算法由十进制转八进制

代码

#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */

typedef int Status;
typedef int SElemType; 
typedef struct
{
SElemType data[MAXSIZE];
int top; /* 用于栈顶指针 */
}SqStack;
//4.1 构建一个空栈S
Status InitStack(SqStack *S){
S->top = -1;
return OK;
}

//4.2 将栈置空
Status ClearStack(SqStack *S){
 //疑问: 将栈置空,需要将顺序栈的元素都清空吗?
 / /不需要,只需要修改top标签就可以了.
S->top = -1;
return OK;
}
//4.3 判断顺序栈是否为空;
Status StackEmpty(SqStack S){
if (S.top == -1)
return TRUE;
else
return FALSE;
}
//4.4 返回栈的长度
int StackLength(SqStack S){
return S.top + 1;
}
//4.5 获取栈顶
Status GetTop(SqStack S,SElemType *e){
if (S.top == -1)
return ERROR;
else
*e = S.data[S.top];
return OK;
}
//4.6 插入元素e为新栈顶元素
Status PushData(SqStack *S, SElemType e){
//栈已满
if (S->top == MAXSIZE -1) {
return ERROR;
}
//栈顶指针+1;
S->top ++;
//将新插入的元素赋值给栈顶空间
S->data[S->top] = e;
return OK;
}
//4.7 删除S栈顶元素,并且用e带回
Status Pop(SqStack *S,SElemType *e){
//空栈,则返回error;
if (S->top == -1) {
return ERROR;
}
//将要删除的栈顶元素赋值给e
*e = S->data[S->top];
//栈顶指针--;
S->top--;
return OK;
}
//4.8 从栈底到栈顶依次对栈中的每个元素打印
Status StackTraverse(SqStack S){
int i = 0;
printf("此栈中所有元素");
while (i<=S.top) {
printf("%d ",S.data[i++]);
}
printf("\n");
return OK;
}
/*
1. 初始化一个空栈S
2. 当十进制N非零时,循环执行以下操作
* 把N与8求余得到的八进制数压入栈S;
* N更新为N与8的商;
3. 当栈S非空时,循环执行以下操作
* 弹出栈顶元素e;
* 输出e;
*/
void conversion(int N){
SqStack S;
SElemType e;
//1.初始化一个空栈S
InitStack(&S);
//2.
while (N) {
PushData(&S, N%8);
N = N/8;
}
//3.
while (!StackEmpty(S)) {
Pop(&S, &e);
printf("%d\n",e);
}
}
int main(int argc, const char * argv[]) {
// insert code here...
printf("Hello, World!\n");
conversion(1348);
return 0;
}

字符串编码问题

 题目: 

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

例如:

s = "3[a]2[bc]", 返回 "aaabcbc".z

s = "3[a2[c]]", 返回 "accaccacc".

s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".

思路:

 例如:12[a]为例;

1.遍历字符串 S

2.如果当前字符不为方括号"]" 则入栈stack中;

2.如果当前字符遇到了方括号"]" 则:

① 首先找到要复制的字符,例如stack="12[a",那么我要首先获取字符a;将这个a保存在另外一个栈去tempStack;

② 接下来,要找到需要备份的数量,例如stack="12[a",因为出栈过字符"a",则当前的top指向了"[",也就是等于2;

③ 而12对于字符串是2个字符, 我们要通过遍历找到数字12的top上限/下限的位置索引, 此时上限curTop = 2, 下限通过出栈,top = -1;

④ 根据范围[-1,2],读取出12保存到strOfInt 字符串中来, 并且将字符"12\0",转化成数字12;

⑤ 当前top=-1,将tempStack中的字符a,复制12份入栈到stack中来;

 ⑥ 为当前的stack扩容, 在stack字符的末尾添加字符结束符合'\0';

实现:

char * decodeString(char * s){
   
    /*.
     1.获取字符串长度
     2.设置默认栈长度50
     3.开辟字符串栈(空间为50)
     4.设置栈头指针top = -1;
     */
    int len = (int)strlen(s);
    int stackSize = 50;
    char* stack = (char*)malloc(stackSize * sizeof(char));
    int top = -1;
    
    //遍历字符串,在没有遇到"]" 之前全部入栈
    for (int i = 0; i < len; ++i) {
        if (s[i] != ']') {
            //优化:如果top到达了栈的上限,则为栈扩容;
            if (top == stackSize - 1) {
                stack = realloc(stack, (stackSize += 50) * sizeof(char));
            }
            //将字符入栈stack
            stack[++top] = s[i];
            printf("#① 没有遇到']'之前# top = %d\n",top);
        }
        else {
            int tempSize = 10;
            char* temp = (char*)malloc(tempSize * sizeof(char));
            int topOfTemp = -1;
            
            printf("#② 开始获取要复制的字符信息之前 # top = %d\n",top);
            //从栈顶位置开始遍历stack,直到"["结束;
            //把[a]这个字母a 赋值到temp栈中来;
            //简单说,就是将stack中方括号里的字符出栈,复制到temp栈中来;
            while (stack[top] != '[') {
                
                //优化:如果topOfTemp到达了栈的上限,则为栈扩容;
                if (topOfTemp == tempSize - 1) {
                    temp = realloc(temp, (tempSize += 10) * sizeof(char));
                }
                //temp栈的栈顶指针自增;
                ++topOfTemp;
                //将stack栈顶字符复制到temp栈中来;
                temp[topOfTemp] = stack[top];
                //stack出栈,则top栈顶指针递减;
                top--;
            }
            printf("#② 开始获取要复制的字符信息之后 # top = %d\n",top);
            
            //找到倍数数字.strOfInt字符串;
            //注意:如果是大于1位的情况就处理
            char strOfInt[11];
            //p记录当前的top;
            int curTop = top;
            printf("#③ 开始获取数字,数字位置上限 # curTop = %d\n",curTop);
            
            //top--的目的是把"["剔除,才能找到数字;
            top--;
            //遍历stack得出数字
            //例如39[a] 就要找到这个数字39.
            //p指向当前的top,我就知道上限了; 那么接下来通过循环来找它的数字下限;
            //结束条件:栈指针指向为空! stack[top] 不等于数字
            while (top != -1 && stack[top] >= '0' && stack[top] <= '9') {
                top--;
            }
            printf("#③ 开始获取数字,数字位置下限 # top = %d\n",top);
            
            //从top-1遍历到p之间, 把stack[top-1,p]之间的数字复制到strOfInt中来;
            //39中3和9都是字符. 我们要获取到这2个数字,存储到strOfInt数组
            for (int j = top + 1; j < curTop; ++j) {
                strOfInt[j - (top + 1)] = stack[j];
            }
            //为字符串strOfInt数组加一个字符结束后缀'\0'
            strOfInt[curTop - (top + 1)] = '\0';
            
            //把strOfInt字符串转换成整数 atoi函数;
            //把字母复制strOfInt份到stack中去;
            //例如39[a],就需要把复制39份a进去;
            int curNum = atoi(strOfInt);
            for (int k = 0; k < curNum ; ++k) {
                
                //从-1到topOfTemp 范围内,复制curNum份到stackTop中去;
                int kk = topOfTemp;
                while (kk != -1) {
                    
                    //优化:如果stack到达了栈的上限,则为栈扩容;
                    if (top == stackSize - 1) {
                        stack = realloc(stack, (stackSize += 50) * sizeof(char));
                    }
                    
                    //将temp栈的字符复制到stack中;
                    //stack[++top] = temp[kk--];
                    ++top;
                    stack[top] = temp[kk];
                    kk--;
                    
                }
            }
            free(temp);
            temp = NULL;
        }
    }
    
    //realloc 动态内存调整;
    //void *realloc(void *mem_address, unsigned int newsize);
    //构成字符串stack后, 在stack的空间扩容.
    char* ans = realloc(stack, (top + 1) * sizeof(char));
    ans[++top] = '\0';
    
    //stack 栈不用,则释放;
    free(stack);
    return ans;
}



字符去重

题目

题目:• 去除重复字母(LeetCode-困难)

给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)

示例1:

输入:"bcabc"

输出:"abc"

示例2:

输入:"cbacdcbc"

输出:"acdb"

思路

1. 判断字符串可能出现的特殊情况

2. 用一个record数组记录字符串中字母出现的次数;

3. 申请一个字符串栈stack用来存储去除重复字母的结果,并利用它的特性帮助我们找到正确的次序;

4. 遍历字符串s

5. 从0~top,遍历stack 判断当前字符s[i]是否存在于栈stack中

如果当前字符是否存在于栈的定义一个falg 标记isExist, 0表示不存在, 1表示存在

6.如果isExist存在,record[s[i]]位置上的出现次数减一,并继续遍历下一个字符; 表示当前的stack已经有这个字符了没有必要处理这个重复的字母;

7.如果isExist不存在,则

如果不存在,则需要循环一个找到一个正确的位置,然后在存储起来;

如果不存在,跳过栈中所有比当前字符大、且后面还会出现的元素,然后将当前字符入栈

top > -1表示栈非空

stack[top] > s[i]表示栈顶元素比当前元素大

record[stack[top]] > 1表示后面还会出现

通过一个while循环找到将栈中位置错误的数据,出栈. 找当前合适的位置,则结束while循环;

找到合理的位置后,则将当前字符s[i]入栈;

 8.直到遍历完所有字符后,则为字符串栈stack 添加一个结束符'\0',并返回当前字符串首地址;

代码

char *removeDuplicateLetters(char *s)
{
    if (s == NULL || strlen(s) == 0) {
        return "";
    }
    if (strlen(s) == 1) {
        return s;
    }
    char record[26] = {0};
    int len = (int)strlen(s);    char* stack = (char*)malloc(len * 2 * sizeof(char));    memset(stack, 0, len * 2 * sizeof(char));
    int top = -1;
    int i;
    for (i = 0; i < len; i++) {
        record[s[i] - 'a']++;
    }
    for (i = 0; i < len; i++) {        int isExist = 0;        for (int j = 0; j <= top; j++) {
            if (s[i] == stack[j]) {
                isExist = 1;
                break;
            }
        }
        if (isExist == 1) {
            record[s[i] - 'a']--;
        } else {
            while (top > -1 && stack[top] > s[i] && record[stack[top] - 'a'] > 1) {
                record[stack[top] - 'a']--;                top--;
            }                        top++;            stack[top] = s[i];
        }
    }
    
    //结束栈顶添加字符结束符
    stack[++top] = '\0';
    return stack;
}