力扣238:除自身以外数组的乘积
原题链接:
238. 除自身以外数组的乘积 - 力扣(LeetCode)
本题一开始采用双层循环遍历的方式去解决,但是会超出时间限制,因此采用所求数字的前缀乘积乘上它的后缀乘积。注意在第一个数字的前缀乘积与最后一个数字的后缀乘积应初始化为1,第一次循环是求数字的前缀乘积,在第二次循环时,不再次设立数组存放后缀乘积,直接让前缀乘积乘上后缀即可。
代码如下:
int* productExceptSelf(int* nums, int numsSize, int* returnSize) {
int i, t, k;
int *a = (int *)malloc(sizeof(int) * numsSize); //为所要返回的数组分配空间
t = 1; //一开始的数字为除了第一个数字的乘积,因此设立他的前缀乘积为1
for(i = 0; i < numsSize; i++)
{
a[i] = t;
t *= nums[i];
} //一开始a数组所存放的都为所求数字位置的前缀乘积
//即第二个数字的前缀乘积为第一个数字
//第三个数字的前缀乘积为前两个数字的乘积以此类推
t = 1;
for(i = numsSize - 1; i >= 0; i--)
{
a[i] = a[i] * t;
t *= nums[i];
} //二次循环为使数字的前缀乘积加上后缀乘积,从后向前方便,因此为此遍历方式
//使t再次初始化为1,表示的为数字的后缀乘积,一开始最后一个数字的后缀乘积为1
//倒数第二个数字的后缀乘积为倒数第一个数字,以此类推
*returnSize = numsSize;
return a;
}
力扣394:字符串解码
原题链接:
本题采用了memcpy内存复制函数,在解决此题时用一次循环找到可以对应的括号以及所对应的字符串的复制次数,数字找到则结束内层循环,进入字符串拷贝部分,即将原字符串的括号的左右两边都复制下来,然后将所要复制的字符串进行内存复制操作。
代码如下:
char *decodeString(char *s)
{
if (s == NULL)
{
return NULL;
} //当s字符串为空时,直接返回NULL
char *a = strdup(s); //字符串拷贝函数,将字符串s拷贝到a中
while (true) //一直循环,直到遇到返回
{
int len = strlen(a); //每一次都要求a的长度,每次循环字符串a都会改变
int left = 0, right = len;
int i = len - 1, num = 0, w = 1;
for (; i >= 0; i--) //每次都要从字符串的最后一个位置开始
{
if (a[i] == ']')
{
right = i;
}
else if(a[i] == '[')
{
left = i;
} //right与left分别记录[]的位置,此时记录的就为最内部可配对的两个括号
else if (a[i] >= '0' && a[i] <= '9')
{
do
{ // 组合数字
num += w * (a[i] - '0');
w *= 10;
i--; //
} while (i >= 0 && (a[i] >= '0' && a[i] <= '9'));
break;
} //数字是以单个字符存在于字符串当中,因此我们需要找到数字的大小,从后向前的
//因此第一个数字为个位的数字,第二个数字为十位数字
} //此循环为找到字符串当中由[]的部分
if (num == 0)
{ //没有[]了
return a;
} //此时代表所有的括号都已经拆分完毕
else
{
int slen = (right - left - 1); //此长度为由括号所包含的字符串的大小
int count = (i + 1) + (len - right - 1) + num * slen + 1;;
//此时计算的为将括号内部元素展开所占内存,即数字左边的长度加上右括号以后的长度
//加上所要复制的字符串的长度,因为是长度所以加1
char *t = (char*)calloc(count, sizeof(char)); //设置新的字符串,并为此分配空间
if (i + 1 > 0)
{ // 左
memcpy(t, a, i + 1);
} //memcpy此处用法为将a字符串的前i+1个字符复制到t字符串当中
for (int k = 0; k < num; k++)
{ // 中
memcpy(t + (i + 1) + k * slen, a + left + 1, slen);
} //将字符串复制到所对应位置
if (len - right - 1 > 0)
{
memcpy(t + (i + 1) + num * slen, a + right + 1, len - right - 1);
} //将右括号以后的字符串复制到t当中
free(a);
a = t; //将t字符串复制到a当中
}
}
}
力扣23:合并K个升序链表
原题链接:
此题为合并两个升序链表的延申,先建立一个头结点,使其为空,让其与第一个链表进行合并,将合并后的链表与第二个链表进行合并,即采用递归的方式进行,合并所用的函数与合并两个升序链表的操作方式一样。
代码如下:
struct ListNode* mergetwoLists(struct ListNode *list1, struct ListNode *list2)
{
if(list1 == NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
} //当这两个链表有一个为空时,直接返回另外一个链表的头结点
struct ListNode *lhead = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *tail = lhead;
while(list1 != NULL && list2 != NULL)
{
if(list1->val < list2->val)
{
lhead->next = list1;
lhead = lhead->next;
list1 = list1->next;
}
else
{
lhead->next = list2;
lhead = lhead->next;
list2 = list2->next;
}
} //当两个链表都不为空时,使两个指针从头结点开始遍历,比较指针所指的结点的数字大小,进行链表的合并
if(list1 == NULL)
{
lhead->next = list2;
}
if(list2 == NULL)
{
lhead->next = list1;
} //当有一个链表为空时,直接使新建链表的尾结点指向另一个不为空的链表
return tail->next;
}
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
if(listsSize == 0)
{
return NULL;
} //当链表的个数为0时,不需要进行合并,直接返回NULL
int i;
struct ListNode *head = NULL; //建立一个为空的链表使其与链表1进行合并,从而开始了递归
for(i = 0; i < listsSize; i++)
{
head = mergetwoLists(head, lists[i]); //用合并两个链表的函数
}
return head;
}
力扣232:用栈实现队列
原题链接:
此题考查栈与队列的基础知识以及栈与队列的不同点,即栈是先进后出,而队列是先进先出。用栈实现队列时要取出第一个元素,则需要使栈的其余元素先出来,才能使栈底元素出来,因此设立两个栈,一个用来存放栈本来的元素,另一个则辅助输出,以免元素的丢失。
代码如下:
typedef struct {
//栈是先进后出,队列是先进先出,此题是用栈实现队列,因此需要两个来操作
int stackInTop, stackOutTop;//定义两个数字来当作栈的指针
int stackIn[100], stackOut[100]; //一个栈用来进行输入,一个用来辅助输出
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue *queue = (MyQueue *)malloc(sizeof(MyQueue));
queue->stackInTop = 0;
queue->stackOutTop = 0;//为队列分配空间
return queue;
}
void myQueuePush(MyQueue* obj, int x) {
obj->stackIn[(obj->stackInTop)++] = x;//将数据存放到栈当中
}
int myQueuePop(MyQueue* obj) {
int stackInTop = obj->stackInTop;
int stackOutTop = obj->stackOutTop;//将栈顶指针复制
if(stackOutTop == 0) //如果辅助输出的栈顶指针为空,则进入循环,将输入的栈的元素进行出栈操作
//并进行入栈操作存放到辅助输出的栈当中
{
while(stackInTop > 0)
{
obj->stackOut[stackOutTop++] = obj->stackIn[--stackInTop];
}
} //循环结束,此时辅助输出的栈顶元素为输入时的第一个元素
int top = obj->stackOut[--stackOutTop]; //此时将辅助输出的栈顶元素取出来,进行返回
while(stackOutTop > 0)
{
obj->stackIn[stackInTop++] = obj->stackOut[--stackOutTop];
} //再将其余元素放进栈当中
obj->stackInTop = stackInTop;
obj->stackOutTop = stackOutTop; //取出了栈底的元素,因此更新栈的指针元素
return top;
}
int myQueuePeek(MyQueue* obj) {
return obj->stackIn[0]; //返回队列开头的元素,即栈的最底层元素
}
bool myQueueEmpty(MyQueue* obj) {
if(obj->stackInTop == 0 && obj->stackOutTop == 0)
{
return true; //判断队列为空,即存入数据的栈为空,并且辅助输出的栈也为空
}
return false;
}
void myQueueFree(MyQueue* obj) {
obj->stackInTop = 0;
obj->stackOutTop = 0; //将两个栈顶的指针都置0
}
力扣392:判断子序列
原题链接:
本题为判断子序列,即s字符串的字母需要在t字符串中出现,并且要求字母出现的先后顺序一样,因此采用循环遍历。先用strlen函数求出两个字符串的大小,当s字符串比t字符串大时直接返回false,当s字符串大小为0时一定为t的子字符串,直接返回true。不满足以上条件开始循环遍历,循环所代表的为t字符串,当t字符串的字母与s字符串的字母一样时,s字符串的字母位置向后移动一位,即s[o]让o自增,当在循环当中o自增的与s字符串大小一样时,即代表s为t的子字符串,此时返回true,循环遍历完都没有返回,即不是子字符串,返回false。
代码如下:
bool isSubsequence(char* s, char* t) {
int n = strlen(s);
if(n == 0)
{
return true;
} //求出s字符串的大小,当s字符串的大小为0时,即没有字符则直接返回true
int m = strlen(t);
int x = 0;
if(n > m)
{
return false;
} //当s字符串的大小比t字符串的大,则s不可能为t的子字符串,返回false
for(int i = 0; i < m; i++)
{ //循环为t字符串的字符
if(s[x] == t[i])
{
x++;
if(x == n) //此时代表s字符串中的字母都在t字符串当中出现,并且顺序一样
{
return true;
}
}
}
return false;
}