【链表专题】百度真题:环形链表分成三等份
本问题对应课程链接:剑指offer刷题第六期
要求:
1、请打卡你的解题代码,如果能简单说一下思路则简单说一下思路。
2、给出你代码所用的时间复杂度和空间复杂度
参考代码
下面是一个完整的代码,包括测试,你们可以直接粘贴运行。
import java.util.*;
public class GetThreeListNode {
// 核心方法
// 当节点是 3 的倍数,则均分,当不为3的倍数,比如 1 2 3 4 5 6 7,则分成
// l1:1 2 l2:3 4 l3:5 6 7
public static List getThreeListNode(ListNode head){
//只有一个节点
if(head.next==head){
List list = new ArrayList<>();
head.next = null;//防止返回一个环形链表
list.add(head);
list.add(null);
list.add(null);
return list;
}
// 只有两个节点
if(head.next.next == head){
List list = new ArrayList<>();
ListNode temp =head.next;
temp.next = null;
list.add(temp);
head.next = null;
list.add(head);
list.add(null);
return list;
}
ListNode l1 = head;
ListNode l2 = head.next;
ListNode l3 = head.next.next;
int count =1;
ListNode temp = head;
// 统计节点个数
while (head.next!=temp){
count++;
head = head.next;
}
// System.out.println(count);
List list= new ArrayList<>();
// 节点是3的倍数,三个指针,走一步,走两步,走三步来进行切分
if((count%3)==0){
while(l3.next!=temp){
l3 = l3.next.next.next;
l2 = l2.next.next;
l1 = l1.next;
}
ListNode a1 = l3.next;
ListNode a2 = l2.next;
ListNode a3 = l1.next;
l1.next = null;
l2.next = null;
l3.next = null;
list.add(a1);
list.add(a2);
list.add(a3);
}else{
int k = (int) Math.round(count*1.0/3)-1;
while (k!=0){
l2 = l2.next.next;
l1 = l1.next;
k--;
}
while(l3.next!=temp){
l3 = l3.next;
}
ListNode a1 = l3.next;
ListNode a2 = l2.next;
ListNode a3 = l1.next;
l1.next = null;
l2.next = null;
l3.next = null;
list.add(a1);
list.add(a3);
list.add(a2);
}
return list;
}
// 测试
public static void main(String[] args) {
ListNode l1 = new ListNode(0);
ListNode l2 = new ListNode(1);
ListNode l3 = new ListNode(2);
ListNode l4 = new ListNode(3);
ListNode l5 = new ListNode(4);
ListNode l6 = new ListNode(5);
ListNode l7 = new ListNode(6);
l1.next = l1;
//l2.next = l1;
// l3.next = l4;
// l4.next = l1;
// l5.next = l6;
// l6.next = l7;
// l7.next = l1;
List threeListNode = getThreeListNode(l1);
// 打印
for(int i = 0; i < threeListNode.size(); i++){
ListNode head = threeListNode.get(i);
System.out.println("链表 i = " + i);
while(head != null){
System.out.println(head.val);
head = head.next;
}
}
}
// ListNode 内部类,用来演示需要
public static class ListNode{
int val;
ListNode next;
public ListNode(int x){
this.val = x;
}
}
}
共以下 19 个回答
思路分析
复杂度分析
参考力扣725.分隔链表,k恒定为3即可。
时间复杂度:O(n方)
空间复杂度:O(n)
没看懂
C++完整版代码 获取步数及余数 对余数情况进行处理
#include
using namespace std;
#include
class ListNodea(3);
{
public:
int val;
ListNode next;
ListNode():val(0),next(nullptr){}
ListNode(int x):val(x),next(nullptr){}
ListNode(int x,ListNode *next):val(x),next(next){}
};
vector<ListNode >getthreenode(ListNode *head)
{
int num = 1;//获取节点总数
ListNode *temp = head;
while(temp->next!=head)
{
temp = temp->next;
num++;
}
int partsize = num/3;
int remainsize = num%3;
ListNode *p1 = head;
ListNode *p2 = head->next;
ListNode *p3 = head->next->next;
if(remainsize0)
{
for(int i =1;i<partsize;i++)
{
p1 = p1->next;
p2 = p2->next->next;
p3 = p3->next->next->next;
}
}
else if(remainsize1)
{
for(int i =1;i<partsize;i++)
{
p1 = p1->next;
p2 = p2->next->next;
p3 = p3->next->next->next;
}
p3 = p3->next;
}
else
{
for(int i =1;i<partsize;i++)
{
p1 = p1->next;
p2 = p2->next->next;
p3 = p3->next->next->next;
}
p3 = p3->next;
p2 = p2->next;
}
if(p3->nexthead)
{
cout<<“节点移动正确”<<endl;
}
ListNode *head1 = p3->next;
ListNode *head2 = p1->next;
ListNode *head3 = p2->next;
p3->next = nullptr;
p2->next = nullptr;
p1->next = nullptr;
vector
cout<<a.size()<<endl;
a[0] = head1;
a[1] = head2;
a[2] = head3;
cout<<a.size()<<endl;
return a;
}
int main()
{
}
java
class Solution {
public ListNode[] splitListToParts(ListNode head, int k) {
int n = 0;
ListNode temp = head;
while(temp != null){
n++;
temp = temp.next;
}
int quotient = n / k, remainder = n % k;
}
提交
思路:
1.先判断特殊情况,节点个数为1和2
2.节点个数为3的整数倍,使用三个快慢指针,循环直到最快的指针走到尾部时
3.节点个数不是3的整数倍,固定前两个链表的个数:节个数除3取整,最后一个链表循环到结束
4.每一个等分点的下一个节点是链表的开始,脱链
import java.util.*;
public class GetThreeListNode { getThreeListNode(ListNode head){
// 核心方法
// 当节点是 3 的倍数,则均分,当不为3的倍数,比如 1 2 3 4 5 6 7,则分成
// l1:1 2 l2:3 4 l3:5 6 7
public static List
//只有一个节点
if(head.nexthead){
List list = new ArrayList<>();
head.next = null;//防止返回一个环形链表
list.add(head);
list.add(null);
list.add(null);
return list;
}
// 只有两个节点
if(head.next.next head){
List list = new ArrayList<>();
ListNode temp =head.next;
temp.next = null;
list.add(temp);
head.next = null;
list.add(head);
list.add(null);
return list;
}
ListNode l1 = head;
ListNode l2 = head.next;
ListNode l3 = head.next.next;
int count =1;
ListNode temp = head;
// 统计节点个数
while (head.next!=temp){
count++;
head = head.next;
}
// System.out.println(count);
List list= new ArrayList<>();
// 节点是3的倍数,三个指针,走一步,走两步,走三步来进行切分
if((count%3)0){
while(l3.next!=temp){
l3 = l3.next.next.next;
l2 = l2.next.next;
l1 = l1.next;
}
ListNode a1 = l3.next;
ListNode a2 = l2.next;
ListNode a3 = l1.next;
l1.next = null;
l2.next = null;
l3.next = null;
list.add(a1);
list.add(a2);
list.add(a3);
}else{
int k = (int) Math.round(count*1.0/3)-1; // 长度能整出于3的最大的结果
while (k!=0){
l2 = l2.next.next;
l1 = l1.next;
k–;
}
while(l3.next!=temp){
l3 = l3.next;
}
ListNode a1 = l3.next;
ListNode a2 = l2.next;
ListNode a3 = l1.next;
l1.next = null;
l2.next = null;
l3.next = null;
list.add(a1);
list.add(a3);
list.add(a2);
}
// l4.next = l5;
// l5.next = l6;
// l6.next = l7;
// l7.next = l1;
l4.next=l1;
}
留坑,后续再学。
时间复杂度: O(n)
空间复杂度: O(n)
“`c++
struct Node {
int val;
Node *next;
Node(int val): val(val), next(nullptr) {}
Node(): val(0), next(nullptr) {}
};
class ThreeNodes {
public:
Node l1;
Node *l2;
Node *l3;
ThreeNodes() {
this->l1 = new Node(0);
this->l2 = new Node(0);
this->l3 = new Node(0);
}
ThreeNodes(Node l1, Node* l2, Node* l3): l1(l1), l2(l2), l3(l3) {}
~ThreeNodes() { delete l1, l2, l3; }
};
“`
import java.util.*;
public class GetThreeListNode {
// 核心方法
// 当节点是 3 的倍数,则均分,当不为3的倍数,比如 1 2 3 4 5 6 7,则分成
// l1:1 2 l2:3 4 l3:5 6 7
public static List getThreeListNode(ListNode head){
//只有一个节点
if(head.nexthead){
List list = new ArrayList<>();
head.next = null;//防止返回一个环形链表
list.add(head);
list.add(null);
list.add(null);
return list;
}
// 只有两个节点
if(head.next.next head){
List list = new ArrayList<>();
ListNode temp =head.next;
temp.next = null;
list.add(temp);
head.next = null;
list.add(head);
list.add(null);
return list;
}
ListNode l1 = head;
ListNode l2 = head.next;
ListNode l3 = head.next.next;
int count =1;
ListNode temp = head;
// 统计节点个数
while (head.next!=temp){
count++;
head = head.next;
}
// System.out.println(count);
List list= new ArrayList<>();
// 节点是3的倍数,三个指针,走一步,走两步,走三步来进行切分
if((count%3)0){
while(l3.next!=temp){
l3 = l3.next.next.next;
l2 = l2.next.next;
l1 = l1.next;
}
ListNode a1 = l3.next;
ListNode a2 = l2.next;
ListNode a3 = l1.next;
l1.next = null;
l2.next = null;
l3.next = null;
list.add(a1);
list.add(a2);
list.add(a3);
}else{
int k = (int) Math.round(count*1.0/3)-1;
while (k!=0){
l2 = l2.next.next;
l1 = l1.next;
k–;
}
while(l3.next!=temp){
l3 = l3.next;
}
ListNode a1 = l3.next;
ListNode a2 = l2.next;
ListNode a3 = l1.next;
l1.next = null;
l2.next = null;
l3.next = null;
list.add(a1);
list.add(a3);
list.add(a2);
}
// l3.next = l4;
// l4.next = l1;
// l5.next = l6;
// l6.next = l7;
// l7.next = l1;
List threeListNode = getThreeListNode(l1);
// 打印
for(int i = 0; i < threeListNode.size(); i++){
ListNode head = threeListNode.get(i);
System.out.println(“链表 i = ” + i);
while(head != null){
System.out.println(head.val);
head = head.next;
}
}
}
}
时间o(n) 空间o(1)
//仅为思路实现,未进行验证();
//!!!此方法只需要一次遍历!!!
//使用四个指针。三个指针分别是快中慢三种速度,第四个指针在最快指针之后再多跑三格。
class Solution {
public static List getThreeListNode(ListNode head){
List ans = new ArrayList
ListNode ptr = head;
ListNode fastPtr = headPtr;//探路指针,比最快的指针多探两格
ListNode headPtr = head;
ListNode midPtr = head;
ListNode tailPtr = head;
while(true){
tailPtr = tailPtr.next;
midPtr = midPtr.next.next;
headPtr = fastPtr.next.next.next;
fastPtr = headPtr;
if(fastPtr.next head){//下一格就是循环链表头,则说明刚好被三整除,直接断开
break;
}
if(fastPtr.next.next head){//下下格就是循环链表头,则最快指针需要多进一格
headPtr = headPtr.next;
break;
}
if(fastPtr.next.next.next head){//下下下格就是循环链表头,则中间指针需要多进一格,最快指针需要多进两格
headPtr = headPtr.next.next;
midPtr = midPtr.next;
break;
}
}
ans.add(headPtr.next);
ans.add(midPtr.next);
ans.add(fastPtr.next);
//断开链表
headPtr.next = null;
midPtr.next = null;
fastPtr.next = null;
return ans;
}
}
时间复杂度o(2n)
空间复杂度o(1)
“`CPP
时间复杂度O(n),空间复杂度O(1)。
重点在于理解题意,首先是环形链表,看解答的意思是首尾相接的环形链表,而不是存在环的链表,这点需要注意下。若非环形链表,分成三等分只需要两个指针就可以了,若是环形链表,则需要三个,因为需要一个指针断开环路(非环尾节点指向NULL)。题目中l3就是者这个目的。
还有就是int k = (int) (Math.round(count * 1.0 / 3) – 1); k为count除以3再取四舍五入后-1
这里让l1和l2先走k步先到达目标位置,接着让l3再走到尾节点。
打卡
时间复杂度O(N)
空间复杂度O(1)