题目描述:
题目分析解读:
通过分析我们知道:
(1)如果k大于链表的长度len,那么返回的数组的前len项的每个链表都只有一个结点,后面的len+1~k项元素都是NULL;
(2)如果k小于链表的长度len,那么返回的数组可以分为k个部分,其中前(len%k)项每个数组元素的链表中的结点数为(len/k +1),后面部分的每个数组元素中的链表的结点个数为(len/k)个。
在解这道题的时候,由于本科期间代码能力的缺乏导致很多代码不会写,甚至百度出来解题答案也看不懂,感谢宁同学的悉心指导,总算是明白了。
首先再次明确这道题让干什么,就是说你先创建一个链表,然后再输入一个整数k,将链表划分为k个连续的部分,而且每一部分之间的长度差距不能超过1,。那么我们先来写主函数:
int main(){
ListNode *root=createByTail();
int k;
cin>>k;
vector<ListNode *> inVec=Solution().splitListToParts(root,k);
display(inVec);
return 0;
}
在主函数里,从cin>>k往下我都没想起来,也就是说我们将算法的主要思想即将链表划分为k个连续的部分这个函数的返回值保存在ListNode类型的vector中,这一点我确实是根本就想不到,白话一点来讲,有一个数组inVec,是ListNode类型的,inVec里面存放的都是ListNode类型的数据,我们将splitListToParts函数返回到这样的一个数组中,就可以通过访问数组的形式将链表读出来。在这里奉上宁同学为我讲解时花的一张图:
主函数写好了,那我们就来实现主要的函数吧:
splitListToParts(head,k),也就是说我们现在要用这个函数实现
(1)如果k>链表的长度len,那么inVec数组里面是一个个的结点(这里的一个个指的是每个结点后面不再有其他结点)以及NULL结点
(2)如果k<链表的长度Len,那么inVec数组里面中的每个结点后面还会有其他结点,具体一点来讲,就是前(len%k)项中一共有(len/k +1)个结点,后面的项中一共有(len/k)个结点。
具体代码如下:
//splitListToParts函数的返回类型就是vector类型的,以便更好的访问划分后的链表
vector<ListNode *> splitListToParts(ListNode *head,int k){
//首先先声明一个ListNode的数组,其中数组大小为k
vector<ListNode *> res(k,NULL);
if(root==NULL){
return res;
}
//求链表的长度
ListNode *p=root;
int len=0;
while(p!=NULL){
len++;
p=p->next;
}
//(1)当k>len时,res里面都是单独的结点,以及NULL结点
ListNode *q;
if(k>len){
p=root;
q=p;
for(int i=0;i<len;i++){
q=p->next;
p->next=NULL;
res[i]=p;
p=q;
}
}
//(2)当k<len,那么res里面虽然还是一个一个的结点,但此时每一个结点的后面还有结点
//具体来讲,前int m=(len%k)项中有(len/k + 1)个结点
//后面的项中有int n=(len/k)个结点
ListNode *head1;
else{
int m=len % k;
int n=len /k;
p=root;
q=root;
int i=0;
while(p!=NULL){
head1=p;
if(i<m){//表示前m项是每一项都有n+1个结点
for(int j=0;j<n;j++){
p=p->next;
}
}
else{//后面的项每一项都有n个结点
head1=p;
for(int j=0;j<n-1;j++){
p=p->next;
}
}
q=p->next;
p->next=NULL;
p=q;
res[i]=head1;
i++;
}
}
终于给上面的代码思路整明白了,那现在就看看我们的display函数吧
void display(vector<ListNode *> res){
for(int i=0;i<res.size();i++){
ListNode *p;
p=res[i];
cout<<"head-->";
while(p!=NULL){
cout<<p->val<<"-->";
p=p->next;
}
cout<<"tail\n";
}
}
//整个输出在for循环中进行,所以说res多大就输出多少个链表,也就是我们开头说的k。
完整代码:
#include<iostream>
#include<vector>
using namespace std;
//题目解析:
//通过分析我们知道:
//如果k大于链表的长度len,那么返回的 数组的前len项的每个链表都只有一个结点,后面的len+1~k项元素都是null
//如果k小于链表的长度len,那么返回的数组可以分为k个部分,
//其中前(len%k)项每个数组元素的链表中的结点数为(len/k+1)
//后面部分的每个数组元素中的结点个数为(len/k)个
struct ListNode{
int val;
ListNode *next;
ListNode():val(0),next(NULL){}
ListNode(int x,ListNode *next):val(x),next(next){}
};
ListNode *createByTail(){
ListNode *head;
ListNode *p;
ListNode *tail;
int len;
cin>>len;
int n=0,num;
head=NULL;
while(n<len && cin>>num){
p=new ListNode();
p->val=num;
p->next=NULL;
n=n+1;
if(n==1){
head=p;
}
else{
tail->next=p;
}
tail=p;
}
return head;
}
class Solution{
public:
vector<ListNode *> splitListToParts(ListNode *root,int k){
vector<ListNode *> res(k,NULL);
if(root==NULL){
return res;
}
//求链表的长度
ListNode *p=root;
ListNode *q;
ListNode *head1;
int len=0;
while(p!=NULL){
len++;
p=p->next;
}
//当k>len时
if(k>len){
p=root;
q=p;
//前面k个数组元素都存在一个结点
for(int i=0;i<len;i++){
q=p->next;
p->next=NULL;
res[i]=p;
p=q;
}
}
//当k<len时
else{
int m=len % k;
int n=len / k;
p=root;
q=root;
//前m个链表有n+1个结点,后边的链表都有n个结点
int i=0;
while(p!=NULL){
//head1记录头结点
head1=p;
if(i<m){
for(int j=0;j<n;j++){
p=p->next;
}
}
else{
head1=p;
for(int j=0;j<n-1;j++){
p=p->next;
}
}
q=p->next;
p->next=NULL;
p=q;
res[i]=head1;
i++;
}
}
return res;
}
};
void display(vector<ListNode *> inVec){
for(int i=0;i<inVec.size();i++){
ListNode *p;
p=inVec[i];
cout<<"head-->";
while(p!=NULL){
cout<<p->val<<"-->";
p=p->next;
}
cout<<"tail\n";
}
}
int main(){
int k;
ListNode *root=createByTail();
cin>>k;
vector<ListNode *> inVec=Solution().splitListToParts(root,k);
display(inVec);
return 0;
}