LeetCode做题记录
由于去年毕业写论文,后来参加工作,导致好久没有更新博客了,前段时间看到一个游客评论说让我加油坚持更新,于是打算开一个文章,来记录一下工作以后下班时间偶尔的做题记录。
28. 实现 strStr()
本题在LeetCode上显示为简单,原因是出题人理解为可以直接调用API,但是如果用C语言实现,不调用API的情况下,需要使用字符串对比的KMP算法
在这里放一个B站讲解KMP算法原理的视频
//首先是构造next数组
void getnext(int *next,char *pattern)
{
int k=-1,j=0;
next[0]=-1;//next数组的0位设置为-1
//计算pattern字符的长度
char *p=pattern;
int length=0;
while(*p++!='\0')
length++;
//对于next数组的j位,设置其next[j]
while(j<length)
{
//如果k为-1,表示前面的字符串没有公共前后缀,将next[j+1]设置为0
//如果k不为-1,表示前面的字符串最大公共前后缀长度为k
//这时,如果pattern[j]==pattern[k],表示j处的最大公共前后缀的长度可以增加1,即设置next[j+1]=k+1;
//因此,将k++,j++,next[j]=k即可
if(k==-1||pattern[j]==pattern[k])
{
j++;k++;
next[j]=k;
}
//如果不匹配,将最大公共前后缀的长度进行回溯,让k=next[k],去next[k]的位置进行对比
else //pattern[j]!=pattern[k]
k=next[k];
}
return;
}
int strStr(char *text,char *pattern)
{
//记录text与pattern的字符串的长度
int length1=0,length2=0;
char *p;
p=text;
while(*p++!='\0')
length1++;
p=pattern;
while(*p++!='\0')
length2++;
//构建next数组
int *next=(int*)malloc((length2+1)*sizeof(int));
getnext(next,pattern);
//i代表text,j代表pattern
int i=0,j=0;
while(i<length1&&j<length2)
{
//如果回溯到j==-1,表示要j要从0开始重新匹配,i从下一个位置进行匹配
//如果text[i]==pattern[j],i与j同时增加
if(j==-1||text[i]==pattern[j])
{
i++;j++;
}
else//如果j!=-1,并且text[i]!=pattern[j]
{
//j往前回溯到next[j]的位置i不变;
j=next[j];
}
}
//如果退出循环,有两种情况,1是j==length2,这是表示已经匹配到,返回i-j的位置为起始匹配到的位置
if(j==length2)
return i-j;
//反之表示没有匹配上
else
return -1;
}
KMP算法比较难理解,网上很多文章写得晦涩难懂,这里建议多看看视频演示原理。
另外由于next的数组不同的教材有不同的写法,例如有的直接将最大公共前后缀长度设为next,有的将最大公共前后缀数组向右边移动一位,把0位设为-1,本质上原理是一样的,只是在代码实现上有所区别
本文采用的是0位设为-1的方法
27. 移除元素
//27. 移除元素
int removeElement(int* nums, int numsSize, int val){
int i=0;
for(;i<numsSize;)
{
if(nums[i]==val)
{
nums[i]=nums[--numsSize];
}
else
i++;
}
return numsSize;
}
当遇到相同的元素,直接删除,删除时将最后一个元素移动到该位置
26. 删除排序数组中的重复项
int removeDuplicates(int* nums, int numsSize){
if(numsSize<=1)
return numsSize;
int i=0,j=1;
for(;j<numsSize;)
{
if(nums[j]==nums[i])
j++;
else
nums[++i]=nums[j];
}
return i+1;
}
由于是有序数组,用两个指针标记原数组与新数组的位置即可
21. 合并两个有序链表
非递归方法:指针的操作,这里使用三个指针分别指向L1,L2与合并后的L3,注意指针为空的情况
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
struct ListNode*ptr1,*ptr2,*ptr3,*head;
ptr1=l1;
ptr2=l2;
if(!ptr1)
return ptr2;
if(!ptr2)
return ptr1;
if(ptr1->val<=ptr2->val)
{
head=ptr1;
ptr1=ptr1->next;
}
else
{
head=ptr2;
ptr2=ptr2->next;
}
ptr3=head;
while(ptr1&&ptr2)
{
if(ptr1->val<=ptr2->val)
{
ptr3->next=ptr1;
ptr1=ptr1->next;
}
else
{
ptr3->next=ptr2;
ptr2=ptr2->next;
}
ptr3=ptr3->next;
}
if(ptr1)
ptr3->next=ptr1;
if(ptr2)
ptr3->next=ptr2;
return head;
}
递归的方法
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
if(!l1)
return l2;
if(!l2)
return l1;
if(l1->val<=l2->val)
{
//l1头结点较小,将l1->next与l2合并后,将l1->next赋值为合并的链表
l1->next=mergeTwoLists(l1->next,l2);
return l1;
}
else
{
//l2头结点较小,将l2->next与l1合并后,将l2->next赋值为合并的链表
l2->next=mergeTwoLists(l2->next,l1);
return l2;
}
}
20. 有效的括号
入职以后基本都转为写C语言了,所以在这里也改用C语言来做题,不过思路方法都是相通的。
bool isValid(char * s){
char stack[5001];
int top=0;
while(*s!='\0')
{
stack[top++]=*s++;
if(top>=2)
{
if((stack[top-2]=='('&&stack[top-1]==')')||(stack[top-2]=='['&&stack[top-1]==']')||(stack[top-2]=='{'&&stack[top-1]=='}'))
top-=2;
else if((stack[top-1]==')'&&stack[top-2]!='(')||(stack[top-1]==']'&&stack[top-2]!='[')||(stack[top-1]=='}'&&stack[top-2]!='{'))
return false;
}
}
if(top!=0)
return false;
return true;
}
题目是一个很简单的栈的题,构建一个栈,入栈时,对比栈顶的两个字符是否匹配即可。如果同为左括号则不比对,如果栈顶为右括号)]},则需比对栈顶与栈顶下的元素是否匹配,o。