PAT乙级 链表题-1025、1075、1105、1110

题目:

PAT乙级1025 反转链表

https://pintia.cn/problem-sets/994805260223102976/exam/problems/994805296180871168

PAT乙级1075 链表元素分类

https://pintia.cn/problem-sets/994805260223102976/exam/problems/994805262953594880

PAT乙级1105 链表合并

https://pintia.cn/problem-sets/994805260223102976/exam/problems/1478634321389170688

PAT乙级1110 区块反转

https://pintia.cn/problem-sets/994805260223102976/exam/problems/1478634682663895040

总体分析:

1、几道题思路基本一致,都是用较大的数组模拟链表行为。

list数组下标作为节点地址,数组元素记录数据和下一节点地址。

struct Node
{
    int addr;
    int data;
    int next;
}list[100001];

2、可以转到提取有效节点到新数组处理链表(1025、1075),也可以在大数组中直接处理(1105、1110)。

    //按顺序提取链表到新数组
	while(ptr != -1)
    {
        list1[length] = list[ptr];
        list1[length].id = length;
        length++;
        ptr = list[ptr].next;
    }
	//链表的反转--直接在大数组处理
	ptr2 = -1; int ptr2_next = head2;
	while(ptr2_next != -1)
	{
	  int temp = list[ptr2_next].next;
	  list[ptr2_next].next = ptr2;
	  ptr2 = ptr2_next;
	  ptr2_next = temp;
	}

代码及分析:

PAT乙级1025 反转链表:

完成部分节点的反转,直接对部分节点进行排序比较清晰,因此在获取节点正确顺序后可以加入节点排序数据id。

根据k使用sort函数反转部分链表,反转后首尾节点的地址需要更新。

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;

struct Node
{
    int addr;
    int data;
    int next;
    int id = 0;
}list[100001];

bool cmp(Node n1, Node n2)
{
    return n1.id > n2.id;
}

int main()
{
    int head, n, k;
    cin >> head >> n >> k;
    for(int i = 0; i < n; i++)	//数据输入
    {
        int addr;
        cin >> addr;
        list[addr].addr = addr;
        cin >> list[addr].data >> list[addr].next;
    }
    Node list1[n];
    int ptr = head, length = 0;
    while(ptr != -1)	//将链表转移至小数组(只有有效节点被记录)
    {
        list1[length] = list[ptr];
        list1[length].id = length;		//为方便反转,添加一个id数据
        length++;
        ptr = list[ptr].next;
    }
    for(int i = 0;i < length; i += k)	//根据id降序排列,即完成链表部分反转
    {
        if(i + k <= length)
        {
            sort(list1 + i, list1 + i + k, cmp);
        }
    }
    for(int i = 0; i < length; i++)		//输出反转后新的下一节点地址
    {
        printf("%05d %d ", list1[i].addr, list1[i].data);        
        if(i == length - 1) printf("-1\n");
        else printf("%05d\n", list1[i+1].addr);
    }
    return 0;
}

PAT乙级1075 链表元素分类:

最开始的思路是将有效节点集中到一个数组后,根据特定规则排序;

cmp中:一个节点的数据>=0、一个<0的时候,则升序排;如果一个在[0,k]内,一个不在,则升序排;其他情况全不排。

bool cmp(Node n1, Node n2)
{
    if((n1.data < 0 && n2.data >= 0) || (n1.data >= 0 && n2.data < 0))
        return n1.data < n2.data;
    else if((n1.data >= 0 && n1.data <= k && n2.data > k) ||
           (n1.data > k && n2.data >= 0 && n2.data <= k))
        return n1.data < n2.data;
    else return false;
}

但是测试点5一直答案错误,未发现原因,后更改为将不同类型的节点一次存入三个数组,再按顺序输出即可。

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;

struct Node
{
    int addr;
    int data;
    int next;
}list[100001];
int head, n, k;

int main()
{
    cin >> head >> n >> k;
    for(int i = 0; i < n; i++)
    {
        int addr;
        cin >> addr;
        list[addr].addr = addr;
        cin >> list[addr].data >> list[addr].next;
    }
    int ptr = head;
    Node list1[n], list2[n], list3[n];
    int length1 = 0, length2 = 0, length3 = 0;
    while(ptr != -1)	//对不同的节点分类,存储到不同的数组去
    {
        if(list[ptr].data < 0)
        {
            list1[length1] = list[ptr];
            length1++;
        }
        else if(list[ptr].data >= 0 && list[ptr].data <= k)
        {
            list2[length2] = list[ptr];
            length2++;            
        }
        else
        {
            list3[length3] = list[ptr];
            length3++;                
        }
        ptr = list[ptr].next;
    }
  	//顺序输出三个数组
    for(int i = 0; i < length1; i++)
    {
        printf("%05d %d ", list1[i].addr, list1[i].data);
        if(i != length1 - 1) printf("%05d\n", list1[i + 1].addr);
        else if(length2 == 0 && length3 == 0) printf("-1\n");
    }
    for(int i = 0; i < length2; i++)
    {
        if(i == 0 && length1 != 0) printf("%05d\n", list2[0].addr);
        printf("%05d %d ", list2[i].addr, list2[i].data);
        if(i != length2 - 1) printf("%05d\n", list2[i + 1].addr);
        else if(length3 == 0) printf("-1\n");
    }
    for(int i = 0; i < length3; i++)
    {
        if(i == 0 && (length1 != 0 || length2 != 0)) printf("%05d\n", list3[0].addr);
        printf("%05d %d ", list3[i].addr, list3[i].data);
        if(i != length3 - 1) printf("%05d\n", list3[i + 1].addr);
        else printf("-1\n");
    }
    return 0;
}

PAT乙级1105 链表合并:

思路:比较两个链表长度,反转短链表,长链表每两个节点间加入一个短链表节点。

直接在大数组中操作,行为和实际链表类似,新节点连接到长链表上一节点next,断掉新节点next指针,指向长链表下一节点。

#include<iostream>
#include<stdio.h>
using namespace std;

struct Node
{
    int addr;
    int data;
    int next;
}list[100001];

int main()
{
    int head1, head2, n;
    cin >> head1 >> head2 >> n;
    for(int i = 0; i < n; i++)
    {
        int addr;
        cin >> addr;
        list[addr].addr = addr;
        cin >> list[addr].data >> list[addr].next;
    }
    int length1 = 0, length2 = 0;
    int ptr1 = head1, ptr2 = head2;
    while(ptr1 != -1 || ptr2 != -1)		//记录比较两个链表长度
    {
        if(ptr1 != -1)
        {
            length1++;
            ptr1 = list[ptr1].next;
        }
        if(ptr2 != -1)
        {
            length2++;
            ptr2 = list[ptr2].next;
        }
    }
    if(length1 < length2)   //保证1长2短
    {
        int temp = head1; head1 = head2; head2 = temp;
        temp = length1; length1 = length2; length2 = temp;
    }
    if(length2 > 1)		//短链表反转
    {
        ptr2 = -1; int ptr2_next = head2;
        for(int i = 0; i < length2; i++)
        {
            int temp = list[ptr2_next].next;
            list[ptr2_next].next = ptr2;
            ptr2 = ptr2_next;
            ptr2_next = temp;
        }
        head2 = ptr2;
    }
    int cnt = 0; ptr1 = head1; ptr2 = head2;
    while(ptr1 != -1)	//长链表每两节点中间接入一个短链表节点,直接在大数组中操作
    {
        if(cnt == 1)
        {
            if(ptr2 != -1)
            {
                int temp = list[ptr1].next;
                list[ptr1].next = list[ptr2].addr;
                int temp2 = list[ptr2].next;
                list[ptr2].next = temp;
                ptr2 = temp2;
                ptr1 = temp;
            }
            cnt = 0;
        }
        else 
        {
            cnt++;
            ptr1 = list[ptr1].next;
        }
    }
    ptr1 = head1;
    while(ptr1 != -1)
    {
        printf("%05d %d ", list[ptr1].addr, list[ptr1].data);
        if(list[ptr1].next == -1) printf("-1\n");
        else printf("%05d\n", list[ptr1].next);
        ptr1 = list[ptr1].next;
    }
    return 0;
}

PAT乙级1110 区块反转:

每k个节点,断掉尾节点,并移位保存首节点和上一首节点地址,尾节点指向上一首节点。最后k(或者不到k)个节点的首节点,即为新链表的head。

#include<iostream>
#include<string>
using namespace std;

struct Node
{
    int address;
    int data;
    int next_address;
}list[100001];

int main()
{
    int head_address, n, k;
    cin >> head_address >> n >> k;
    for(int i = 0; i < n; i++)
    {
        int idx;
        cin >> idx;
        list[idx].address = idx;
        cin >> list[idx].data >> list[idx].next_address;
    }
    int ptr_address = head_address;
    int lastfirst = -1, first = -1;
    int cnt = 0;
    while(ptr_address != -1)	//每k个节点,断掉尾节点next,指向上一部分k个节点的首节点
    {	
        if(cnt == 0)
        {
            lastfirst = first;
            first = ptr_address;
        }
        int temp_nextaddr;
        if(cnt == k - 1 || list[ptr_address].next_address == -1)
        {
			temp_nextaddr = list[ptr_address].next_address;     
            list[ptr_address].next_address = lastfirst;
            ptr_address = temp_nextaddr;
            cnt = 0;
            if(ptr_address == -1)
            	head_address = first;
        }
        else
		{
			cnt++;
			ptr_address = list[ptr_address].next_address;
		}
    }
    ptr_address = head_address;
    while(ptr_address != -1)
    {
        printf("%05d %d ", list[ptr_address].address, list[ptr_address].data);
        if(list[ptr_address].next_address != -1) printf("%05d\n", list[ptr_address].next_address);
        else printf("-1\n");
        ptr_address = list[ptr_address].next_address;
    }
    return 0;
}

#刷题记录#
PAT乙级 文章被收录于专栏

PAT乙级(Basic)刷题记录

全部评论

相关推荐

有趣的牛油果开挂了:最近这个阶段收到些杂七杂八的短信是真的烦
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务