PAT乙级 —— 1015 反转链表 (25)

  • 题目链接:反转链表 (25)

  • 题目描述

    给定一个常数K以及一个单链表L,请编写程序将L中每K个结点反转。例如:给定L为1→2→3→4→5→6,K为3,则输出应该为3→2→1→6→5→4;如果K为4,则输出应该为4→3→2→1→5→6,即最后不到K个元素不反转。

  • 输入描述:

    每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址、结点总个数正整数N(<= 105)、以及正整数K(<=N),即要求反转的子链结点的个数。结点的地址是5位非负整数,NULL地址用-1表示。

  • 接下来有N行,每行格式为:

    Address Data Next
    其中Address是结点地址,Data是该结点保存的整数数据,Next是下一结点的地址。

  • 输出描述:

    对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。

  • 输入例子:

    00100 6 4
    00000 4 99999
    00100 1 12309
    68237 6 -1
    33218 3 00000
    99999 5 68237
    12309 2 33218

  • 输出例子:

    00000 4 33218
    33218 3 12309
    12309 2 00100
    00100 1 99999
    99999 5 68237
    68237 6 -1

  • 超时代码

    • 一开始思路很简单,用一个结构体node描述链表节点(地址可以用int存),用vector<node>存储链表。先把所有数据输入辅助vector temp中,通过多次遍历找到正确的顺序存入另一个vector list,翻转list输出即可

    • 代码如下

      #include<iostream>
      #include<string> 
      #include<vector>
      #include<algorithm>
      using namespace std;
      
      typedef struct NODE
      {
      	int addr;
      	int next;
      	int value;
      }NODE;
      
      vector<NODE> temp;		//辅助容器
      vector<NODE> list;		//原始链表
      
      int main()
      {
          int addr,N,K,len=0;	//len是真实链表长度,可能有些节点不在链表中
          cin>>addr>>N>>K;
      	
      	//输入原始数据
      	for(int i=0;i<N;i++)
      	{
      		NODE t;
      		cin>>t.addr>>t.value>>t.next;
      		temp.push_back(t);
      	}
      	
      	//找出原始链表
      	while(!temp.empty())
      	{
      		for(int i=0;i<temp.size();i++)
      		{
      			if(temp[i].addr == addr)
      			{
      				list.push_back(temp[i]);
      				len++;
      				addr = temp[i].next;
      				temp.erase(temp.begin()+i,temp.begin()+i+1);
      				break;
      			}
      		}
      	}
      	
      	//翻转元素
      	for(int i = 0; i + K<=len; i += K) 
      		reverse(list.begin() + i, list.begin() + i + K);
      
      	//输出
      	for(int i=0;i<len-1;i++)
      	{
      		NODE t;
      		printf("%05d %d %05d\n",list[i].addr,list[i].value,list[i+1].addr);
      	}
      	printf("%05d %d %d\n",list[len-1].addr,list[len-1].value,-1);
      
         	return 0;
      }
      
    • 这个代码会超时

  • 满分代码

    • 改变思路,遍历找原链表的过程太慢了,用散列空间换时间。开一个大数组,数组下标代表地址,这样就能快速找出原始链表

    • 满分代码

      #include<iostream>
      #include<string> 
      #include<vector>
      #include<algorithm>
      using namespace std;
      
      typedef struct NODE
      {
      	int addr;
      	int next;
      	int value;
      }NODE;
      
      NODE temp[100010];
      vector<NODE> list;
      
      
      int main()
      {
          int head,N,K,len=0;
          cin>>head>>N>>K;
      	
      	int addr;
      	for(int i=0;i<N;i++)
      	{
      		cin>>addr;
      		temp[addr].addr = addr;
      		cin>>temp[addr].value>>temp[addr].next;
      	}
      	
      	addr = head;
      	while(addr!=-1)
      	{
      		list.push_back(temp[addr]);
      		len++;
      		addr = temp[addr].next;
      	}
      
      	for(int i = 0; i + K<=len; i += K) 
       	 	reverse(list.begin() + i, list.begin() + i + K);
       
      
      	//cout<<endl<<endl;
      	for(int i=0;i<len-1;i++)
      		printf("%05d %d %05d\n",list[i].addr,list[i].value,list[i+1].addr);
      	printf("%05d %d %d\n",list[len-1].addr,list[len-1].value,-1);
      	
         	return 0;
      }
      
  • 坑点小结

    1. 如果超时了,考虑散列用空间换时间
    2. 给出的节点中可能有些不在链表中,要重新找链表真实长度
    3. 注意看题,题目要求是每K个数都要翻转,不是只翻转前K个数
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云端FFF

所有博文免费阅读,求打赏鼓励~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值