1.反转单向链表
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static Node reverseList(Node head) {
Node pre=null;
Node next=null;
while(head!=null){
next=head.next;
head.next=pre;
pre=head;
head=next;
}
return pre;//注意return的是pre
}
2.反转双向向链表(自己想的时候一开始逻辑都是错的)
public static DoubleNode reverseList(DoubleNode head) {
DoubleNode pre=null;
DoubleNode next=null;
while(head!=null){
next=head.next;
head.next=pre;
head.last=next;
pre=head;
head=next;
}
return pre;
}
3.两个链表公共部分
public static void printCommonPart(Node head1, Node head2) {
System.out.print("Common Part: ");
while(head1!=null&&head2!=null){
if(head1.value==head2.value){
System.out.print(head1.value+" ");
head1=head1.next;
head2=head2.next;
}else if(head1.value>head2.value){
head2=head2.next;
}else{
head1=head1.next;
}
}
}
4.判断是否是回文链表
//最简单的方式,使用栈存储
public static boolean isPalindrome1(Node head) {
Stack<Integer> stack=new Stack();
Node p=head;
while(p!=null){
stack.push(p.value);
p=p.next;
}
p=head;
while(!stack.isEmpty()){
int pop=stack.pop();
if(p.value!=pop){
return false;
}
p=p.next;
}
return true;
}
//升级版1:使用栈存一半的数组
public static boolean isPalindrome2(Node head) {
if(head==null||head.next==null){
return true;
}
Node h=head;
Node slow=h;
Node fast=h;
Stack<Integer> stack = new Stack<>();
int num=0;
while(h!=null){
num++;
h=h.next;
}
if(num%2==0){
while(fast!=null){
slow=slow.next;
fast=fast.next.next;
}
}
if(num%2==1){
while(fast.next!=null) {
slow = slow.next;
fast = fast.next.next;
}
}
Node slow1=slow;
while(slow1!=null){
stack.push(slow1.value);
slow1=slow1.next;
}
while(!stack.isEmpty()){
if(head.value!=stack.pop()){
return false;
}
head=head.next;
}
return true;
}
//升级版2:使用O(1)的复杂度
public static boolean isPalindrome3(Node head) {
if(head==null||head.next==null){
return true;
}
//找到中点
Node h=head;
Node slow=h;
Node fast=h;
while(fast.next!=null&&fast.next.next!=null){
slow=slow.next;
fast=fast.next.next;
}
//反转右半部分链表
Node next=null;
Node pre=null;
while(slow!=null){
next=slow.next;
slow.next=pre;
pre=slow;
slow=next;
}
Node h2=pre;
//判断是否是回文
while(h!=null&&pre!=null){
if(h.value!=pre.value){
return false;
}
h=h.next;
pre=pre.next;
}
//在反转回原来的
h=head;
while(h.next!=null){
h=h.next;
}
Node per2=null;
Node next2=null;
while(pre!=null){
next2=pre.next;
pre.next=per2;
per2=pre;
pre=next2;
}
return true;
}
5.将单向列表分为左边小,中间相等,右边大的形式
//法一:放进node数组中,然后partition
public static Node listPartition1(Node head, int pivot) {
if(head==null||head.next==null){
return head;
}
//将节点全部放入node数组中
List<Node> nodeList=new ArrayList<>();
Node h=head;
while(h!=null){
nodeList.add(h);
h=h.next;
}
//partition划分
arrPartition(nodeList, pivot);
//链表的重连
head=h=nodeList.get(0);
for (int i=1;i<nodeList.size();i++){
h.next=nodeList.get(i);
h=h.next;
}
h.next=null;
return head;
}
public static void arrPartition(List<Node> nodeArr, int pivot) {
int left=-1;
int right=nodeArr.size();
for(int i=0;i<right;i++){
if(nodeArr.get(i).value< pivot){
swap(nodeArr,++left,i);;
}else if(nodeArr.get(i).value> pivot){
swap(nodeArr,--right,i);
}
}
}
public static void swap(List<Node> nodeArr, int a, int b) {
Node temp = nodeArr.get(a);
nodeArr.set(a,nodeArr.get(b));
nodeArr.set(b,temp);
}
//法二:分成三个链表,然后重组
public static Node listPartition2(Node head, int pivot) {
Node sH=null;
Node sT=null;
Node mH=null;
Node mT=null;
Node lH=null;
Node lT=null;
Node h=head;
while(h!=null){
if(h.value<pivot){
if(sH==null){
sH=h;
sT=h;
}else{
sT.next=h;
sT=sT.next;
}
}
if(h.value==pivot){
if(mH==null){
mH=h;
mT=h;
}else{
mT.next=h;
mT=mT.next;
}
}
if(h.value>pivot){
if(lH==null){
lH=h;
lT=h;
}else{
lT.next=h;
lT=lT.next;
}
}
h=h.next;
}
if(sH!=null&&mH!=null&&lH!=null){
sT.next=mH;
mT.next=lH;
lT.next=null;
return sH;
}
if(sH==null&&mH!=null&&lH!=null){
mT.next=lH;
lT.next=null;
return mH;
}
if(sH!=null&&mH==null&&lH!=null){
sT.next=lH;
lT.next=null;
return sH;
}
if(sH!=null&&mH!=null&&lH==null){
sT.next=mH;
mT.next=null;
return sH;
}
if(sH==null&&mH==null&&lH!=null){
lT.next=null;
return lH;
}
if(sH!=null&&mH==null&&lH==null){
sT.next=null;
return sH;
}
return null;
}
6.复制含有随机指针节点的链表
//法一:利用hashmap存储节点
public static class Node {
public int value;
public Node next;
public Node rand;
public Node(int data) {
this.value = data;
}
}
public static Node copyListWithRand1(Node head) {
HashMap<Node,Node> hashMap=new HashMap<>();
Node h=head;
while(h!=null){
hashMap.put(h,new Node(h.value));
h=h.next;
}
h=head;
while (h!=null){
Node now=hashMap.get(h);
Node next=hashMap.get(h.next);
now.next=next;
Node rand=hashMap.get(h.rand);
now.rand=rand;
h=h.next;
}
return hashMap.get(head);
}
//法二:复制节点连接成新链表,再拆开(不能同时连接next和rand,也就是不能把第一步和第二步和起来)
public static Node copyListWithRand2(Node head) {
if(head==null){
return null;
}
Node h=head;
//连接成了新链表
while(h!=null){
Node next=h.next;
Node newNode=new Node(h.value);
newNode.next=next;
h.next=newNode;
h=next;
}
//复制rand节点
h=head;
while(h!=null){
if(h.rand!=null){
h.next.rand=h.rand.next;
}else {
h.rand=null;
}
h=h.next.next;
}
//将两个链表分开
Node h1=head;
Node head2=head.next;
Node h2=head2;
while(h1.next.next!=null&&h2.next!=null){
h1.next=h1.next.next;
h1=h1.next;
h2.next=h2.next.next;
h2=h2.next;
}
h1.next=null;
h2.next=null;
return head2;
}
7.两个可能有环也可能无环的节点,若两个链表相交,则返回相交的第一个节点
public class Code07_FindFirstIntersectNode {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
//主要函数
public static Node getIntersectNode(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
//获取两个链表的入环节点
Node loop1 = getLoopNode(head1);
Node loop2 = getLoopNode(head2);
if (loop1 == null && loop2 == null) {
return noLoop(head1, head2);
}
if (loop1 != null && loop2 != null) {
return bothLoop(head1, loop1, head2, loop2);
}
return null;
}
//一个链表,判断是否有环,有:返回节点,无:null
public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node slow = head.next;
Node fast = head.next.next;
while (slow != fast) {
slow = slow.next;
fast = fast.next.next;
//若走到头了,说明无环
if (slow.next == null || fast.next == null || fast.next.next == null) {
return null;
}
}
fast = head;
//求入环节点
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
//如果两个链表都无环
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int length1 = 0;
int length2 = 0;
//分别求出两个节点的长度
while (cur1.next != null) {
length1++;
cur1 = cur1.next;
}
while (cur2.next != null) {
length2++;
cur2 = cur2.next;
}
if (cur1 != cur2) {
return null;
} else {
int go = Math.abs(length2 - length1);
cur1 = head1;
cur2 = head2;
//让长的链表先走
if (length1 >= length2) {
for (int i = 0; i < go; i++) {
cur1 = cur1.next;
}
} else {
for (int i = 0; i < go; i++) {
cur2 = cur2.next;
}
}
//走到第一个相加的节点
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
}
//如果两个链表都有环
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
Node cur1 = null;
Node cur2 = null;
if (loop1 == loop2) {
//若入环节点是同一个(和上面两个无环的情况类似)
cur1 = head1;
cur2 = head2;
int length1 = 0;
int length2 = 0;
while (cur1 != loop1) {
length1++;
cur1 = cur1.next;
}
while (cur2 != loop1) {
length2++;
cur2 = cur2.next;
}
int go = Math.abs(length2 - length1);
cur1 = head1;
cur2 = head2;
if (length1 >= length2) {
for (int i = 0; i < go; i++) {
cur1 = cur1.next;
}
} else {
for (int i = 0; i < go; i++) {
cur2 = cur2.next;
}
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
} else {
//若入环节点不是同一个,让loop1节点转一圈,若能遇到loop2,说明有相交
cur1 = loop1.next;
while (cur1 != loop1) {//让cur1停的条件是转了一圈
if (cur1 == loop2) {
return cur1;
}
cur1 = cur1.next;
}
}
return null;
}
public static void main(String[] args) {
// 1->2->3->4->5->6->7->null
Node head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
// 0->9->8->6->7->null
Node head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
// 1->2->3->4->5->6->7->4...
head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
head1.next.next.next.next.next.next = head1.next.next.next; // 7->4
// 0->9->8->2...
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next; // 8->2
System.out.println(getIntersectNode(head1, head2).value);
// 0->9->8->6->4->5->6..
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
}
}
本文介绍多种链表操作方法,包括反转链表、寻找公共部分、判断回文链表、链表分区、复制含随机指针的链表及查找相交链表等。提供多种实现方案并详细解释其原理。
737





