考核题(力扣算法题)

文章目录

力扣125:验证回文串

力扣73:矩阵置零

力扣21:合并两个有序链表

力扣147:对链表进行插入排序

力扣35:搜索插入位置

力扣61:旋转链表

力扣309:买卖股票的最佳时机含冷冻期

力扣125:验证回文串

题目链接:

125. 验证回文串 - 力扣(LeetCode)

由题目可知先去掉除字母与数字以外的字符,还要将大写的字符转换成小写的字符,再对这个新的字符串进行回文验证。在做此题时先用循环遍历一遍字符串,将小写字符与数字直接放在字符串当中,当遇到大写字符时转换成小写字符再放在字符串当中。最后进行回文验证,一个从字符串的开头出发,一个从末尾出发,看两个指针所指字符是否一样,不一样返回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:矩阵置零

原题链接:

73. 矩阵置零 - 力扣(LeetCode)

此题考查二维数组,要使为零的那一行及列都改为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:合并两个有序链表

原题链接:

21. 合并两个有序链表 - 力扣(LeetCode)

此题考查链表的操作,将已经排序好的两个链表合并成一个有序链表。当一个链表为空时,直接返回另一个链表,当两个链表都不为空,进行链表的合并,先设立一个虚拟头结点,进入循环,使其都位于头结点的位置,比较两结点的数字大小,将小的数字结点接在我们所设立的链表之后,再让此数字的指针指向此链表的下一个结点,不断循环,只当有一个指针指向为空,即代表有一个链表为空,退出循环。将不为空的链表直接接在新的链表之后,返回新链表的头结点的下一个结点的指针。

代码如下:

​
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:对链表进行插入排序

原题链接:

147. 对链表进行插入排序 - 力扣(LeetCode)

此题为单链表的排序,题目要求插入排序,插入排序先定一个被插入的数字,此数字应该从头结点开始,使它与前一个结点进行比较,如果它比前一个结点的数字小,则它需要进行插入操作,至少会插入到前一个结点之前,为了防止插入到头结点之前,因此需要设立一个虚拟头结点,使其指向头结点。在插入结点时需要一次循环操作,查询它要被插入到哪里。如果无需进行插入操作,则直接使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:搜索插入位置

原题链接:

35. 搜索插入位置 - 力扣(LeetCode)

此题考查数组的查找,查找数组当中有没有目标值,以及没有目标值进行插入的结点位置,采用遍历的解法完成。

代码如下:

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:旋转链表

原题链接:

61. 旋转链表 - 力扣(LeetCode)

此题为链表题目,将链表进行旋转。如果头结点为空,即链表为空,则直接返回头结点,否则需要进行链表的旋转。在旋转链表时我们需要头结点的位置,因此建立一个虚拟头结点,使虚拟头结点指向头结点,再进入循环,查找链表共有几个结点,让所要循环次数与链表结点个数进行求余(即如果需要循环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]));
    //手上金额最大时一定不持股,因此其余三种情况进行比较,选出最大值
}

  • 35
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值