目录
- 1.链表指定区间反转
- 题目描述
- 输入格式:
- 输出格式:
- 输入样例:
- 输出样例:
- 题目分析
- 代码实现
- 2.hxj和他的甜品盲盒I
- 输入格式:
- 输入样例:
- 输出样例:
- 样例解释
- 输入样例:
- 输出样例:
- 样例解释
- 题目分析
- Java代码实现
- 3.First 50 Prime Numbers
- 输入格式
- 输出格式
- 输入样例
- 输出样例
- 题目解析
- 代码实现
1.链表指定区间反转
题目描述
将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度O(n),空间复杂度O(1)。
输入格式:
输入三行(多组实例测试)
第一行size(表示链表长度,0<size<=1000
)
第二行输入size个数,为每个节点对应值val(|val|<=1000
)
第三行为m,n(为反转区间的起止位置,0<m<=n<=size
)
输出格式:
输出若干行,每行为每次区间反转后的结果
输入样例:
5
1 2 3 4 5
1 3
5
1 2 3 4 5
2 4
输出样例:
3 2 1 4 5
1 4 3 2 5
题目分析
本题要求多组数据输入且每组数据让我们先输入一个size,我们考虑使用scanf("%d", &size) != EOF
这样的一个结构来控制循环。
题目思路:首先我们可以先想想整条链表如果要反转应该怎么做,我们可以先创建3个节点指针,n1指向空,n2指向头结点,n3指向n2的下一个节点,然后我们让n2指向n1,让n1到n2位置,n2到n3位置,n3指向n2的下一个节点。以此循环当n2为空时或者循环节点数次时我们结束循环。图片解析如下所示:
此方法并不唯一,也有其他方法。接下来我们用这个方法来解答指定区间反转问题。
我们可以将n2指向反转区间的头结点,n1继续为空,最后循环次数为(n-m)+1次,n为区间头,m为区间尾。循环结束之后,n1指向区间尾节点,n2指向尾部断开的下一个节点,在通过链接就完成了区间倒转。 图片解析如下所示:
代码实现
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef struct ListNode {
int val;
struct ListNode* next;
}L;//节点
void CreateL(L** phead, int x)//创建链表
{
L* newNode = (L*)malloc(sizeof(L));
if (newNode == NULL) {
perror("malloc fail!");
return;
}
newNode->val = x;
newNode->next = NULL;
if (*phead == NULL) {
*phead = newNode;
return;
}
L* pcur = *phead;
while (pcur->next) {
pcur = pcur->next;
}
pcur->next = newNode;
}
void PrintL(L* phead)//打印链表
{
assert(phead);
L* pcur = phead;
while (pcur) {
printf("%d ", pcur->val);
pcur = pcur->next;
}
printf("\n");
}
void InvertL(L** phead,int m,int n)//反转链表
{
L* n1 = NULL, * n2 = *phead, * n3 = NULL;
L* pcur = *phead;
L* phead1 = *phead;//区间开始节点
for (int i = 1; i < m-1; i++)
{
pcur=pcur->next;//区间节点前一个节点
}
if(m!=1)phead1 = pcur->next;
n2 = phead1;//插入区间节点的头结点
n3 = n2->next;
for (int i = 0; i <= (n - m); i++) {//指定区间反转循环
n2->next = n1;
n1 = n2;
n2 = n3;
if(n2!=NULL)n3 = n2->next;//n2不是空,n3才能指向n2的next
}
if (m==1) {
*phead = n1;
phead1->next = n2;
}
else
{
pcur->next = n1;
phead1->next = n2;
}
}
int main()
{
int size;
while (scanf("%d", &size) != EOF)
{
L* plist = NULL;
for (int i = 0; i < size; i++) {
int x; scanf("%d", &x);
CreateL(&plist, x);
}
int m, n;
scanf("%d %d", &m, &n);
InvertL(&plist, m, n);
PrintL(plist);
}
return 0;
}
2.hxj和他的甜品盲盒I
hxj很爱吃甜品。有一天,他买了一个甜品盲盒,盲盒有x个小盒子(依次编号为1、2、3……x),每个小盒子排成一排,每个小盒子里都有一个甜品,每个甜品都有一个对应的幸福值。
由于需要控制每天糖分的摄入量,他给自己设下规矩:不能选择相邻的甜品。请你帮他计算一下他能获得的最大幸福值。
输入格式:
输入两行
第一行为x(小盒子数量,1<=x<=100
)
第二行为x个值,每个值分别代表每个小盒子中甜品可获得的幸福值。(0<=幸福值<=400
)
输入样例:
4
1 2 3 1
输出样例:
4
样例解释
hxj选择吃1号甜品 (幸福值 = 1) ,然后选择吃 3 号甜品 (幸福值 = 3)。获得到的最高幸福值 = 1 + 3 = 4 。
输入样例:
5
2 7 9 3 1
输出样例:
12
样例解释
hxj选择吃 1 号甜品(幸福值 = 2),选择3 号甜品 (幸福值 = 9),接着吃 5 号甜品 (幸福值 = 1)。 最后获得到的最大幸福值= 2 + 9 + 1 = 12 。
题目分析
本题是一道动态规划题
我们可以创建两个dp表,f和g,每个dp表中有x(盲盒数量)个元素。
接下来,我们开始考虑往f表和g表中填入数据
f[i]用来表示吃nums[i]甜品获得最大的幸福值,g用来表示不吃nums[i]甜品获得的幸福值。接下来我们就可以得到状态方程:
(1)f[i]=nums[i]+g[i-1](吃nums[i]甜品就不能吃nums[i-1]甜品)
(2)g[i]=max(f[i-1],g[i-1])(不吃nums[i]甜品我们可能吃nums[i-1]甜品,不一定要吃,所以我们选择吃或者不吃nums[i-1]甜品的最大值)
根据上面的状态方程我们就可以填写f和g两个dp表了,最后取吃nums[n-1]和不吃nums[n-1]甜品的最大值,即取f[n-1]和g[n-1]的最大值。(取n-1原因:数组下标从0开始)。
Java代码实现
import java.util.Scanner;
class Solution
{
public int happy(int[] nums) {
if(0 > nums.length-1) return 0;
int n = nums.length;
int[] f= new int[n];//创建f和g表
int[] g= new int[n];
f[0]=nums[1];
g[0]=0;//两个表初始值写入
for(int i = 1; i <= n-1; i++)//按顺序填表
{
f[i] = g[i - 1] + nums[i];
g[i] = Math.max(g[i - 1], f[i - 1]);
}
return Math.max(f[n-1], g[n-1]);//返回最大幸福值
}
}
public class Main {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int x= scan.nextInt();
int[] nums=new int[x];
for (int i = 0; i < x; i++) {
nums[i]= scan.nextInt();
}
Solution solution=new Solution();
int ret=solution.happy(nums);
System.out.println(ret);
}
}
3.First 50 Prime Numbers
Your program reads one natural numbers n in, and prints out the sum of the first n prime numbers starting from 2.
输入格式
A positive whole numbers n, which is less than 1000
输出格式
A number which is the sum of all the first n prime numbers.
输入样例
10
输出样例
129
题目解析
本题意思为:输入一个自然数n,将前n个素数相加,输出相加的结果。
代码实现
#include<stdio.h>
int main()
{
int add=0;
int n;
scanf("%d",&n);
for(int i=2;n>0;i++)
{
if(i==2)//2为特殊值,单拉出来考虑,不在循环前考虑防止n为0的情况
{
add+=2;
n--;
continue;
}
int flag=1;
//下面循环语句判断素数
for(int j=2;j<i;j++)
{
if(i%j==0)
{
flag=0;
break;
}
}
//如果为素数就加起来,并让n减1
if(flag&&n>0)
{
add+=i;
n--;
}
}
printf("%d\n",add);
return 0;
}