文章目录
力扣125:验证回文串
题目链接:
由题目可知先去掉除字母与数字以外的字符,还要将大写的字符转换成小写的字符,再对这个新的字符串进行回文验证。在做此题时先用循环遍历一遍字符串,将小写字符与数字直接放在字符串当中,当遇到大写字符时转换成小写字符再放在字符串当中。最后进行回文验证,一个从字符串的开头出发,一个从末尾出发,看两个指针所指字符是否一样,不一样返回false;当回文验证完毕还未返回,即代表是回文字符串,即返回true。
代码如下:
bool isPalindrome(char* s) {
int i, m = 0,j;
int n = strlen(s);
for(i = 0; i < n; i++)
{
if(s[i] >= 'a'&& s[i]<='z')
{
s[m] = s[i];
m++;
} //当字符字母在a与z之间时将它赋给s字符串位置
else if(s[i] >= 'A'&& s[i]<='Z')
{
s[i] = s[i] + 32;
s[m]=s[i];
m++;
} //当字符字母在A与Z之间时将它先变成a与z之间,再赋给s字符串位置
else if(s[i]>='0'&&s[i]<='9')
{
s[m]=s[i];
m++;
} //由题目可知数字也要参与字符串的验证
else
{
;
} //以上情况都不属于时,不进行赋值操作,每次赋值后都应使m自增一
}
for(i = 0, j = m-1;i<=j;i++,j--)
{
if(s[i] != s[j])
{
return false;
}
} //采用双指针方式对新的字符串进行回文验证
return true;
}
力扣73:矩阵置零
原题链接:
此题考查二维数组,要使为零的那一行及列都改为0,因此应该先将为0的位置标记出来。本题设立两个数组(此时数组大小为m * n,因为当所有数字都为0,所记下标为m * n),用来记为0时的横纵坐标。先进行一次循环遍历,将为0时的横纵坐标都记录在数组中,遍历完毕,进入下一个循环来改变数字。
代码如下:
void setZeroes(int** matrix, int matrixSize, int* matrixColSize) {
int m = matrixSize;
int n = matrixColSize[0];
int i, k, j = 0;
int a[m * n], b[m * n];
for(i = 0; i < m; i++)
{
for(k = 0; k < n; k++)
{
if(matrix[i][k] == 0)
{
a[j] = i;
b[j] = k;
j++;
}
}
} //先将数组遍历一遍,将所有为0的点的横纵坐标的点记到两个数组中
for(i = 0; i < j; i++)
{
int q = a[i];
for(k = 0; k < n; k++)
{
matrix[q][k] = 0;
} //a数组所存放的为0点的行数,将这一行所有位置为0
q = b[i];
for(k = 0; k < m; k++)
{
matrix[k][q] = 0;
} //此循环为改列
}
}
力扣21:合并两个有序链表
原题链接:
此题考查链表的操作,将已经排序好的两个链表合并成一个有序链表。当一个链表为空时,直接返回另一个链表,当两个链表都不为空,进行链表的合并,先设立一个虚拟头结点,进入循环,使其都位于头结点的位置,比较两结点的数字大小,将小的数字结点接在我们所设立的链表之后,再让此数字的指针指向此链表的下一个结点,不断循环,只当有一个指针指向为空,即代表有一个链表为空,退出循环。将不为空的链表直接接在新的链表之后,返回新链表的头结点的下一个结点的指针。
代码如下:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
if(list1 == NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
} //此情况即当一个链表为空时,直接返回另一个链表
struct ListNode *head = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *tail;//建立一个虚拟头结点,采用尾插法去形成新的链表
tail = head;
int i;
while(list1!=NULL && list2!=NULL)
{
if(list1->val < list2->val)
{
head->next = list1;
list1 = list1->next;
head = head->next;
}
else
{
head->next = list2;
list2 = list2->next;
head = head->next;
}
} //当两个链表都不为空时,需要进行比较,将小的数字接到新的链表当中。
if(list1==NULL && list2!=NULL)
{
head->next = list2;
}
else
{
head->next = list1;
} //循环跳出即代表有一个链表循环完毕,即不需要进行对比,此时直接将另一个链表接到尾结点之后
return tail->next; //因为做题时让head指针进行了移动,因此设立一个指针tail等于一开始的虚拟头结点,返回虚拟头结点的下一个位置
}
力扣147:对链表进行插入排序
原题链接:
此题为单链表的排序,题目要求插入排序,插入排序先定一个被插入的数字,此数字应该从头结点开始,使它与前一个结点进行比较,如果它比前一个结点的数字小,则它需要进行插入操作,至少会插入到前一个结点之前,为了防止插入到头结点之前,因此需要设立一个虚拟头结点,使其指向头结点。在插入结点时需要一次循环操作,查询它要被插入到哪里。如果无需进行插入操作,则直接使p(所要插入数字的前一个结点)与c(所要插入数字的结点)指针都向后移动一位,如果进行了插入操作,此时p指针所指向的结点已经变成了下一个结点,因此只需要使c指向p的下一个结点。循环结束,排序完成,返回虚拟头结点的下一个结点。
代码如下:
struct ListNode* insertionSortList(struct ListNode* head) {
struct ListNode *lhead = (struct ListNode *)malloc(sizeof(struct ListNode));
lhead->next=head; //设立虚拟头结点为了在头结点前插入时方便
struct ListNode *p,*c;
c=head->next;
p=head; //在插入排序当中,c指针所指向的为所要插入的结点位置,p指针为所要插入的前一个结点
while(c)
{
if(c->val < p->val)//当c指针所指向的结点数字比p结点数字小时,即代表c要进行插入操作
{
struct ListNode *m=lhead;
while(m) //m指针所指向的为插入点的前一个结点
{
if(m->next->val > c->val) //m的下一个结点的数字如果比c指针所指向的结点数字大时进行插入操作
{
p->next = c->next;
c->next=m->next;
m->next=c;
break;
}
else //当不满足以上情况时,时m指针向后移动一位
{
m = m->next;
}
}
c=p->next; //进行了插入操作,p结点的后一位发生了变化,所以此时只需要使c指针指向p的下一个结点
}
else //无需进行插入操作时,使c与p指针同时向后移一位
{
p=p->next;
c=c->next;
}
}
return lhead->next;
}
力扣35:搜索插入位置
原题链接:
此题考查数组的查找,查找数组当中有没有目标值,以及没有目标值进行插入的结点位置,采用遍历的解法完成。
代码如下:
int searchInsert(int* nums, int numsSize, int target) {
int i;
for(i=0;i<numsSize;i++)
{
if(nums[i] == target)
{
return i;
}
} //此循环是当目标值出现在数组当中,返回此时数组下标
for(i = 0;i<numsSize;i++)
{
if(nums[i]>target)
{
return i;
}
} //数组当中没有目标值时,即找它的插入点,返回插入点的位置
return numsSize; //都没有返回时代表数组中没有目标值,并且中间不进行插入,此时插入到结尾
}
力扣61:旋转链表
原题链接:
此题为链表题目,将链表进行旋转。如果头结点为空,即链表为空,则直接返回头结点,否则需要进行链表的旋转。在旋转链表时我们需要头结点的位置,因此建立一个虚拟头结点,使虚拟头结点指向头结点,再进入循环,查找链表共有几个结点,让所要循环次数与链表结点个数进行求余(即如果需要循环15次,而链表节点有四个,每循环四次都会返回成与原链表一样的链表,因此只需要循环3次即可,同样的如果链表结点个数有五个,则不需要进行循环,直接返回虚拟头结点的下一个结点),将链表旋转余数次,即将链表的后余数个结点移到头结点之前。移动完毕,返回虚拟头结点的下一个结点指针。
代码如下:
struct ListNode* rotateRight(struct ListNode* head, int k) {
if(head==NULL)
{
return head;
} //当头结点为空时,即链表为空,无需进行反转,直接返回头结点
struct ListNode *lhead=(struct ListNode *)malloc(sizeof(struct ListNode));
lhead->next = head; //建立虚拟头结点,来记住头结点的位置
int i;
struct ListNode *fast,*s;
s=lhead;
int n=0;
while(s->next)
{
s=s->next;
n++;
} //用循环来数链表共有几个结点
fast=lhead;
k=k%n; //使k对n(即结点个数)进行求余,因为旋转n次之后的链表与原链表一样
if(k != 0) //即需要旋转
{
for(i=0;i<n-k;i++)
{
fast=fast->next;
} //知道链表节点总个数与旋转几次,即可知道在那个结点使其成为头结点,将之后的链表插入到虚拟头结点与头结点之间
s->next = head;
lhead->next = fast->next;
fast->next =NULL;
}
return lhead->next; //返回虚拟头结点的下一个节点位置
}
力扣309:买卖股票的最佳时机含冷冻期
原题链接:
309. 买卖股票的最佳时机含冷冻期 - 力扣(LeetCode)
此题考查动态规划部分,也是买卖股票的经典题型,要将股票的持有阶段进行划分,具体划分代码标注所示。
代码如下:
int maxProfit(int* prices, int pricesSize) {
if(pricesSize == 0)
{
return 0;
}
int dp[pricesSize][4];
memset(dp, 0, sizeof(int) * pricesSize * 4); //对数组进行初始化
/*dp[i][0]代表持有股票的状态
dp[i][1]代表保持卖出股票的状态(卖出股票的第二天开始到下一次买股票之间)
dp[i][2]代表具体卖出股票的状态(卖出当天)
dp[i][3]代表处于冷冻期状态*/
dp[0][0] = -prices[0]; //持有股票只会是第一天买的
for(int i = 1; i < pricesSize; i++)
{
dp[i][0] = fmax(dp[i - 1][0], fmax(dp[i - 1][1] - prices[i], dp[i - 1][3] - prices[i]));
//持有股的状态为前一天就持有股票
//前一天处于卖出股票的状态,今天买了股票
//前一天为冷冻期,今天买股票
dp[i][1] = fmax(dp[i - 1][1], dp[i - 1][3]);
//前一天就处于卖出股票的状态
//前一天处于冷冻期
dp[i][2] = dp[i - 1][0] + prices[i];
//今天要卖出股票,则前一天应该处于持有股票的状态,前一天持有股票的金额加上今天卖出的钱
dp[i][3] = dp[i - 1][2];
//冷冻期即前一天刚卖出股票
}
return fmax(dp[pricesSize - 1][1], fmax(dp[pricesSize - 1][2], dp[pricesSize - 1][3]));
//手上金额最大时一定不持股,因此其余三种情况进行比较,选出最大值
}