- 反转单向链表
- 反转双向链表
- 判断一个链表是否是回文结构
- 将单向链表按某值划分成左边小、中间相等、右边大的形式
- 打印有序链表的公共部分
- 复制含有随机指针节点的链表
- 两个单链表相交的一系列问题
- 合并升序链表
- 两两交换相邻结点
- 链表相加
- 删除链表的倒数第 n 个结点
- 链表中环的入口节点
1.反转单向链表
要求:时间复杂度要求为O(N),额外空间 复杂度要求为O(1)
思路:
- next指针指向last
public class ReverseSingleList18 {
public static Node reverseSingleList(Node head){
Node pre = null;
Node cur = head;
Node next = null;
while (cur != null){
//保存下一个结点
next = cur.next;
//将当前结点链接至上一个结点
cur.next = pre;
//上一个结点指向当前结点
pre = cur;
//当前结点指向下一个结点
cur = next;
}
return pre;
}
}
public Node reverseList(Node head) {
//递归终止条件是当前为空,或者下一个节点为空
if(head==null || head.next==null) {
return head;
}
//这里的cur就是最后一个节点
Node cur = reverseList(head.next);
//这里请配合动画演示理解
//如果链表是 1->2->3->4->5,那么此时的cur就是5
//而head是4,head的下一个是5,下下一个是空
//所以head.next.next 就是5->4
head.next.next = head;
//防止链表循环,需要将head.next设置为空
head.next = null;
//每层递归函数都返回cur,也就是最后一个节点
return cur;
}
2.反转双向链表
思路
- last指针指向next
- next指针指向last
public class ReverseDoubleList19 {
public static DoubleNode reverseDoubleList(DoubleNode head) {
DoubleNode pre = null;
DoubleNode cur = head;
DoubleNode next = null;
while (cur != null){
//找到下一个结点
next = cur.next;
//last反转
cur.last = next;
//next反转
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
3.判断一个链表是否是回文结构
给定一个链表的头节点head,请判断该链表是否为回文(正念和反念是一样的)结构
方法:
(1)开一个栈,将所有数都倒进去,从头开始遍历,一个一个进行比对
空间复杂度O(N)
public class isPalindrome20_1 {
//判断是否是回文结构
public static boolean isPalindrome(Node head){
Stack<Integer> stack = new Stack<>();
boolean isPalin = true;
//将所有数依次倒进栈里
Node headnode = head;
while (headnode != null){
int value = headnode.getValue();
stack.push(value);
headnode = headnode.getNext();
}
//从头开始一一比较
Node firstNode = head;
while (firstNode != null){
if (firstNode.value == stack.pop()){
firstNode = firstNode.getNext();
}else {
isPalin = false;
break;
}
}
return isPalin;
}
}
(2)开一个栈,快指针走两步,慢指针走一步。从中间开始压栈,一个一个进行比对
空间复杂度O(2/N)
public class isPalindrome20_2 {
public static boolean isPalindrome(Node head){
boolean isPalin = true;
Stack<Integer> stack = new Stack<>();
if (head == null || head.next == null){
return true;
}
//快指针
Node fast = head;
//慢指针
Node slow = head;
//区分是链表结点是奇数还是偶数
while (fast.next != null && fast.next.next != null){
fast = fast.next.next;
slow = slow.next;
}
//慢指针来到了中间
slow = slow.next;
while (slow != null){
stack.push(slow.value);
slow = slow.next;
}
//一一比对
Node firstNode = head;
while (!stack.isEmpty()){
if (firstNode.value == stack.pop()){
firstNode = firstNode.next;
}else {
isPalin = false;
break;
}
}
return isPalin;
}
}
(3)快指针走两步,慢指针走一步。将后半部分逆序,从两端开始比较,比较结束都再逆序回来
空间复杂度O(1)
public class isPalindrome20_3 {
public static boolean isPalindrome(Node head){
boolean isPalin = true;
Node fast = head;
Node slow = head;
if (head == null || head.next == null){
return true;
}
//找到中间结点
while (fast.next != null && fast.next.next != null){
fast = fast.next.next;
slow = slow.next;
}
//反转单链表
Node pre = null;
Node next = null;
while (slow != null){
//找到下一结点
next = slow.next;
slow.next = pre;
pre = slow;
slow = next;
}
//一一比对
Node firstNode = head;
while (firstNode.next != null){
if (firstNode.value == pre.value){
firstNode = firstNode.next;
pre = pre.next;
}else {
isPalin = false;
break;
}
}
return isPalin;
}
}
4.将单向链表按某值划分成左边小、中间相等、右边大的形式
要求:
(1)给定一个单向链表的头节点head,节点的值类型是整型,再给定一个 整数pivot。实现一个调整链表的函数,将链表调整为左部分都是值小于 pivot 的节点,中间部分都是值等于pivot的节点,右部分都是值大于 pivot的节点。
(2)不作稳定性要求
思路:
(1)使用荷兰国旗问题求解,荷兰国旗问题做不到稳定性
(2)开创一个数组,将结点放到数组中
(3)使用荷兰国旗问题求解
public class listPartition_21arr {
//用数组实现荷兰国旗问题
private static Node arrPartition(Node head, int num) {
//判空
if (head == null){
return head;
}
//遍历一次找到单链表长度
Node sizeLink = head;
int size = 0;
while (sizeLink != null){
size++;
sizeLink = sizeLink.next;
}
//开创数组
Node firstNode = head;
Node[] arr = new Node[size];
for (int i = 0;i < size;i++){
arr[i] =firstNode;
firstNode = firstNode.next;
}
//荷兰国旗问题
//头指针
int first = -1;
//尾指针
int last = size;
//当前指针
int cur = 0;
while (cur != last){
//相等
// 指针下移
if (arr[cur].value == num){
cur++;
}else if (arr[cur].value < num){
//小于
//当前数与first下一个数交换,指针下移
swap(arr,cur++,++first);
}else {
//大于
//当前数与last前一个数交换,指针不动
swap(arr,cur,--last);
}
}
//将数组串成新链表
Node newHead = arr[0];
Node returnNode = newHead;
newHead.next = null;
for (int i = 1;i < size;i++){
newHead.next = arr[i];
newHead = arr[i];
newHead.next = null;
}
return returnNode;
}
private static void swap(Node[] arr, int cur, int i) {
Node tmp = arr[cur];
arr[cur] = arr[i];
arr[i] = tmp;
}
//实现单链表
public static class Node {
private int value;
private Node next;
public Node(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
}
要求:
(1)给定一个单向链表的头节点head,节点的值类型是整型,再给定一个 整数pivot。实现一个调整链表的函数,将链表调整为左部分都是值小于 pivot 的节点,中间部分都是值等于pivot的节点,右部分都是值大于 pivot的节点。
(2)实现稳定性
(3)时间复杂度请达到O(N),额外空间复杂度请达到O(1)
思路:
(1)创建3个链表分别是small equal big
(2)遍历原链表 若小于、等于、大于pivot则将结点取下分别放进small equal big链表
public class listPartition_21list {
private static Node listPartition(Node head, int num) {
//判空
if (head == null){
return null;
}
//小链表指针
Node small = null;
//小链表头
Node smallHead = null;
//相同链表指针
Node equal = null;
//相同链表头
Node equalHead = null;
//大链表指针
Node big = null;
//大链表头
Node bigHead = null;
//记录下一个结点
Node next = null;
while (head != null){
//保存下一个结点
next = head.next;
//将原结点从原链表上断开
head.next = null;
if (head.value < num){
//小于
if (small == null){
small = head;
smallHead = small;
}else {
small.next = head;
small = head;
}
}else if (head.value == num){
//等于
if (equal == null){
equal = head;
equalHead =equal;
}else {
equal.next = head;
equal = head;
}
}else {
//大于
if (big == null){
big = head;
bigHead = big;
}else {
big.next = head;
big = head;
}
}
head = next;
}
//返回结点
Node returnHead = null;
//将三个链表串起来 -> 有的链表可能为空
if (smallHead == null && equalHead == null){
returnHead = bigHead;
}else if (equalHead == null && bigHead ==null){
returnHead = smallHead;
}else if (smallHead == null && bigHead == null){
returnHead = equalHead;
}else if (smallHead == null && equalHead != null && bigHead != null){
equal.next = bigHead;
returnHead = equalHead;
}else if (smallHead != null &&equalHead == null && bigHead != null){
returnHead = smallHead;
small.next = bigHead;
}else if (smallHead != null && equalHead != null && bigHead == null){
returnHead = smallHead;
small.next = equalHead;
}else {
returnHead = smallHead;
small.next = equalHead;
equal.next = bigHead;
}
return returnHead;
}
//实现单链表
public static class Node {
private int value;
private Node next;
public Node(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
}
5.打印有序链表的公共部分
要求:给定两个有序链表的头指针head1和head2,打印两个链表的公共部分
思路:
(1)只用专注于一个链表,这个链表上是否有等同于另外一个链表的部分
(2)如果head1<head2,head1 下移
(3)如果head1>head2,head2 下移
(4)如果head1=head2,打印 head1、head2下移
public class printListCommonPart22 {
private static void printListCommonPart(Node head1, Node head2) {
if (head1 == null || head2 == null){
return;
}
while (head1 != null && head2 != null){
if (head1.value < head2.value){
head1 = head1.next;
}else if (head1.value > head2.value){
head2 = head2.next;
}else {
System.out.println("相同" + head1.value);
head1 = head1.next;
head2 = head2.next;
}
}
}
//实现单链表
public static class Node {
private int value;
private Node next;
public Node(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
}
6.复制含有随机指针节点的链表
题解:
一种特殊的链表节点类描述如下:
Node类中的value是节点值,next指针和正常单链表中next指针的意义 一 样,都指向下一个节点,rand指针是Node类中新增的指针,这个指针可能指向链表中的任意一个节点,也可能指向null。
要求:
给定一个由Node节点类型组成的无环单链表的头节点head,请实现一个函数完成这个链表中所有结构的复制,并返回复制的新链表的头节点。
方法1:
使用哈希表
需要额外控件O(N)
public class copyList_hashmap23 {
private static Node copyList_hashmap(Node head) {
if (head == null){
return null;
}
HashMap<Node,Node> hashMap = new HashMap<>();
//遍历一次复制结点
Node cur = head;
while (cur != null){
hashMap.put(cur,new Node(cur.value));
cur = cur.next;
}
//再遍历一次 复制next指针,rand指针
cur = head;
while (cur != null){
hashMap.get(cur).next = hashMap.get(cur.next);
hashMap.get(cur).rand = hashMap.get(cur.rand);
cur = cur.next;
}
return hashMap.get(head);
}
public static class Node {
public int value;
public Node next;
public Node rand;
public Node(int data) {
this.value = data;
}
}
}
方法2:
要求:
不使用额外的数据结构,只用有限几个变量,且在时间复杂度为 O(N) 内完成原问题要实现的函数
思路:
- 第一次遍历的时候加入新结点
- 第二次遍历赋值rand
- 第三次遍历赋值next,并分离结构
public class copyList_newList23 {
private static Node copyList_newList(Node head) {
if (head == null){
return null;
}
//遍历第一次创造新结点
Node cur = head;
Node next = null;
while (cur != null){
next = cur.next;
cur.next = new Node(cur.value);
cur.next.next = next;
cur = next;
}
//遍历第二次 赋值rand
cur = head;
Node copy = null;
while (cur != null){
next = cur.next.next;
copy = cur.next;
copy.rand = cur.rand != null ? cur.rand : null;
cur = next;
}
//遍历第三次分离结构 并 赋值next
cur = head;
Node returnNode = head.next;
copy = null;
while (cur != null){
next = cur.next.next;
copy = cur.next;
copy.next = cur.next.next != null ? next.next : null;
cur.next = next;
cur = next;
}
return returnNode;
}
public static class Node {
public int value;
public Node next;
public Node rand;
public Node(int data) {
this.value = data;
}
}
}
7.两个单链表相交的一系列问题
题解:
在本题中,单链表可能有环,也可能无环。给定两个单链表的头节点 head1和head2,这两个链表可能相交,也可能不相交。
请实现一个函数, 如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null 即可。
核心:
两个单链表若相交,要么都有环,要么都没有环
若相交只可能存在以下几种情况:
(1)两个无环单链表相交
(2)两个单链表先相交再成环
(3)两个单链表先成环再相交
思路:
- 先判断两个单链表是否有环,有则返回第一个入环结点
- -> 都没环 -> 判断最后一个结点是否相同(相同则相交,不相同则不相交)-> 相同则遍历找到第一个相交
- -> 都有环 -> 判断入环结点是否相同(相同则遍历找到第一个相交;不相同遍历去找,找到即相交,找不到即不想交)
- -> 一个有环一个没环 -> 不可能相交
只可能存在以下拓扑结构:
方法1:使用hashmap
//用hashmap实现
public class getIntersectNode24_hashmap {
public static void main(String[] args) {
//得到两个无环单链表
// Node[] arrNoNode = getNoLoopNode();
// Node intersectNode = getIntersectNode(arrNoNode[0], arrNoNode[1]);
// if (intersectNode == null){
// System.out.println("null");
// }else {
// System.out.println(intersectNode.value);
// }
//得到两个都有环单链表
Node[] arrBothNode = getBothLoopNode();
Node intersectNode = getIntersectNode(arrBothNode[0], arrBothNode[1]);
if (intersectNode == null){
System.out.println("null");
}else {
System.out.println(intersectNode.value);
}
}
public static Node getIntersectNode(Node head1,Node head2){
Node returnNode = null;
//判空
if (head1 == null || head2 == null){
return null;
}
//得到两个链表的第一个入环结点
Node loopNode1 = getLoopNode(head1);
Node loopNode2 = getLoopNode(head2);
//两个链表都有环
if (loopNode1 != null && loopNode2 != null){
returnNode = bothLoop(head1,loopNode1,head2,loopNode2);
}else if (loopNode1 == null && loopNode2 == null){
//两个链表都没有环
returnNode = noLoop(head1, head2);
}
return returnNode;
}
//两个有环单链表找第一个相交结点
private static Node bothLoop(Node head1, Node loopNode1, Node head2, Node loopNode2) {
HashSet<Node> hashSet = new HashSet<>();
//如果两个入环结点相同 -> 重复noLoop()
if (loopNode1 == loopNode2){
//存入head1 ~ (loopNode1 - 1)结点
Node head1Cur = head1;
while (head1Cur != loopNode1){
hashSet.add(head1Cur);
head1Cur = head1Cur.next;
}
//让head2 ~ (loopNode2 - 1)结点一一比对
Node head2Cur = head2;
while (head2Cur != loopNode2){
if (hashSet.contains(head2Cur)){
return head2Cur;
}
head2Cur = head2Cur.next;
}
return head1Cur;
}else {
//两个入环结点不相同 -> 可能有环也可能没环
//存入链表1 loopNode ~ loopNode结点
Node cur = loopNode1.next;
while (cur != loopNode1){
hashSet.add(cur);
cur = cur.next;
}
hashSet.add(loopNode1);
//一一比对
//先比较loopNode2
if (hashSet.contains(loopNode2)){
return loopNode1;
}
//再比较 (loopNode2 + 1) ~ (loopNode2 - 1)结点
cur = loopNode2.next;
while (cur != loopNode2){
if (hashSet.contains(cur)){
return loopNode1;
}
cur = cur.next;
}
return null;
}
}
//两个无环单链表找第一个相交结点
private static Node noLoop(Node head1, Node head2) {
HashSet<Node> hashSet = new HashSet<>();
//存入所有head1链表结点
Node head1Cur = head1;
while (head1Cur != null){
hashSet.add(head1Cur);
head1Cur = head1Cur.next;
}
//让head2链表结点一一比对
Node head2Cur = head2;
while (head2Cur != null){
if (hashSet.contains(head2Cur)){
return head2Cur;
}
head2Cur = head2Cur.next;
}
return null;
}
private static Node getLoopNode(Node head1) {
//用hashSet一直存放结点
//若有相等Node 则可以得到第一个入环结点
//若没有相等Node 则没有环
HashSet<Node> hashSet = new HashSet<>();
while (head1 != null){
if (hashSet.contains(head1)){
return head1;
}
hashSet.add(head1);
head1 = head1.next;
}
return null;
}
private static Node[] getNoLoopNode() {
//插入数据
Node head1 = new Node(0);
head1.setNext(null);
Node node11 = new Node(1);
head1.setNext(node11);
node11.setNext(null);
Node node12 = new Node(2);
node11.setNext(node12);
node12.setNext(null);
Node node13 = new Node(3);
node12.setNext(node13);
node13.setNext(null);
Node head2 = new Node(0);
head2.setNext(null);
Node node21 = new Node(1);
head2.setNext(node21);
node21.setNext(node13);
return new Node[]{head1,head2};
}
private static Node[] getBothLoopNode() {
//插入数据
Node head1 = new Node(0);
head1.setNext(null);
Node node11 = new Node(1);
head1.setNext(node11);
node11.setNext(null);
Node node12 = new Node(2);
node11.setNext(node12);
node12.setNext(null);
Node node13 = new Node(3);
node12.setNext(node13);
node13.setNext(null);
Node node14 = new Node(4);
node13.next = node14;
node14.next = node12;
Node head2 = new Node(5);
head2.setNext(null);
Node node21 = new Node(6);
head2.next = node21;
node21.next = node13;
return new Node[]{head1,head2};
}
//实现单链表
public static class Node{
private int value;
private Node next;
public Node(int value){
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
}
方法2:使用有限几个变量
要求:
如果链表1 的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外空间复杂度请达到O(1)。
public class getIntersectNode24_improve {
private static Node getIntersectNode(Node head1,Node head2) {
//记录返回结点
Node returnNode = null;
//判空
if (head1 == null || head2 == null){
return null;
}
//得到入环第一个结点
Node loopNode1 = getLoopNode(head1);
Node loopNode2 = getLoopNode(head2);
if (loopNode1 == null && loopNode2 == null){
//两个都没环
returnNode = noLoop(head1, head2);
}else if (loopNode1 != null && loopNode2 != null){
//两个有环
returnNode = bothLoop(head1,loopNode1,head2,loopNode2);
}
return returnNode;
}
private static Node bothLoop(Node head1, Node loopNode1, Node head2, Node loopNode2) {
//记录返回结点
Node returnNode = null;
//如果两个入环结点相同 -> 重复noLoop()
if (loopNode1 == loopNode2){
//记录单链表的差值
int num = 0;
//记录当前head1指针
Node curHead1 = head1;
//记录当前head2指针
Node curHead2 = head2;
//遍历一次得到单链表1的 (长度-1) 和 最后一个结点
while (curHead1.next != loopNode1){
num++;
curHead1 = curHead1.next;
}
//遍历第二次得到单链表2 与 单链表1 的差值 和 最后一个结点
while (curHead2.next != loopNode2){
num--;
curHead2 = curHead2.next;
}
curHead1 = head1;
curHead2 = head2;
//如果最后两个结点相交
if (num > 0){
//链表1长度 > 链表2长度
//单链表1 先走n步 与 单链表2 同长度
while (num != 0){
curHead1 = curHead1.next;
num--;
}
//一一比对
while (curHead1 != null){
if (curHead1 == curHead2){
returnNode = curHead1;
break;
}
curHead1 = curHead1.next;
curHead2 = curHead2.next;
}
}else {
//链表1长度 <= 链表2长度
num = Math.abs(num);
//单链表2 先走n步 与 单链表1 同长度
while (num != 0){
curHead2 = curHead2.next;
num--;
}
//一一比对
while (curHead1 != null){
if (curHead1 == curHead2){
returnNode = curHead1;
break;
}
curHead1 = curHead1.next;
curHead2 = curHead2.next;
}
}
}else {
//入过两个入环结点不相同 -> 可能有环也可能无环
Node curLoopNode1 = loopNode1.next;
while (curLoopNode1 != loopNode1){
if (curLoopNode1 == loopNode2){
returnNode = curLoopNode1;
break;
}
curLoopNode1 = curLoopNode1.next;
}
}
return returnNode;
}
private static Node noLoop(Node head1, Node head2) {
//记录返回的Node
Node returnNode = null;
//记录单链表的差值
int num = 0;
//记录当前head1指针
Node curHead1 = head1;
//记录当前head2指针
Node curHead2 = head2;
//遍历一次得到单链表1的 (长度-1) 和 最后一个结点
while (curHead1.next != null){
num++;
curHead1 = curHead1.next;
}
//遍历第二次得到单链表2 与 单链表1 的差值 和 最后一个结点
while (curHead2.next != null){
num--;
curHead2 = curHead2.next;
}
//如果最后两个结点不相同 说明没相交
if (curHead1 != curHead2){
return null;
}
curHead1 = head1;
curHead2 = head2;
//如果最后两个结点相交
if (num > 0){
//链表1长度 > 链表2长度
//单链表1 先走n步 与 单链表2 同长度
while (num != 0){
curHead1 = curHead1.next;
num--;
}
//一一比对
while (curHead1 != null){
if (curHead1 == curHead2){
returnNode = curHead1;
break;
}
curHead1 = curHead1.next;
curHead2 = curHead2.next;
}
}else {
//链表1长度 <= 链表2长度
num = Math.abs(num);
//单链表2 先走n步 与 单链表1 同长度
while (num != 0){
curHead2 = curHead2.next;
num--;
}
//一一比对
while (curHead1 != null){
if (curHead1 == curHead2){
returnNode = curHead1;
break;
}
curHead1 = curHead1.next;
curHead2 = curHead2.next;
}
}
return returnNode;
}
private static Node getLoopNode(Node head1) {
//快指针 -> 在没相遇前一次走两步,相遇后一次走一步
Node fast = head1;
//慢指针 -> 在没相遇前一次走一步,相遇后一次走一步
Node slow = head1;
//基本判是否为环
if (fast.next == null || fast.next.next == null){
return null;
}
//第一次遍历 -> 若fast指针找到空了说明没有环
do {
fast = fast.next.next;
slow = slow.next;
} while (fast.next != null && fast.next.next != null && fast != slow);
if (fast.next == null || fast.next.next == null){
return null;
}
//第二次遍历 -> fast指针指向头结点,fast,slow一次走一步,相遇即为第一个
fast = head1;
while (fast != slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
8.合并升序链表
题目:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
思路1
外排 + 辅助链表
//时间 100%
//空间 7%
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode help = new ListNode();
ListNode cur = help;
while (l1 != null && l2 != null){
if (l1.val < l2.val){
cur.next = l1;
l1 = l1.next;
cur = cur.next;
}else {
cur.next = l2;
l2 = l2.next;
cur = cur.next;
}
}
while (l1 != null){
cur.next = l1;
l1 = l1.next;
cur = cur.next;
}
while (l2 != null){
cur.next = l2;
l2 = l2.next;
cur = cur.next;
}
return help.next;
}
思路2
递归
//时间 100%
//空间 93%
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null){
return l2;
}
if (l2 == null){
return l1;
}
if (l1.val < l2.val){
l1.next = mergeTwoLists(l1.next,l2);
return l1;
}else {
l2.next = mergeTwoLists(l1,l2.next);
return l2;
}
}
9.两两交换相邻结点
题目:
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表
要求:
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换
思路1:
在原链表上操作
//空间 13%
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null){
return head;
}
ListNode cur = head;
ListNode last;
ListNode lastlast;
ListNode pre = cur;
boolean isFirst = true;
ListNode returnNode = cur.next;
while (cur != null && cur.next != null){
last = cur.next;
lastlast = cur.next.next;
if (isFirst){
last.next = cur;
cur.next = lastlast;
isFirst = false;;
}else {
last.next = cur;
cur.next = lastlast;
pre.next = last;
pre = cur;
}
cur = lastlast;
}
return returnNode;
}
思路2
递归
//空间 95%
public class _9_swapListPairs_2_leetcode {
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = head.next;
head.next = swapPairs(newHead.next);
newHead.next = head;
return newHead;
}
public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val; this.next = next;
}
}
}
- 链表相加
//时间 77.70%
//空间 79.04%
public ListNode addTwoNumbers_2(ListNode l1, ListNode l2) {
//方便读取数据
StringBuilder builder1 = new StringBuilder();
while (l1 != null){
builder1.append(l1.val);
l1 = l1.next;
}
StringBuilder builder2 = new StringBuilder();
while (l2 != null){
builder2.append(l2.val);
l2 = l2.next;
}
//指针
int i = builder1.length() - 1;
int j = builder2.length() - 1;
//判断是否将进位
int add = 0;
ListNode ans = null;
while (i >= 0 || j >= 0 || add != 0){
//判断是否补零
int x = i >= 0 ? builder1.charAt(i) - '0' : 0;
int y = j >= 0 ? builder2.charAt(j) - '0' : 0;
int cur = x+y+add;
//cur/10为进位
add = cur / 10;
//cur/10为位数
cur = cur % 10;
//头插法
ListNode curnode = new ListNode(cur);
curnode.next = ans;
ans = curnode;
i--;
j--;
}
return ans;
}
11.删除链表的倒数第 n 个结点
给定一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点
//时间 100
//空间 64.95
public ListNode removeNthFromEnd(ListNode head, int n) {
if (head == null || n <=0){
return head;
}
ListNode slow = head;
ListNode fast = head;
//快指针先走n步
for (int i = 0; i < n; i++) {
fast = fast.next;
}
//如果走完fast已经为空
//说明要删除头结点
//返回头结点下一个结点
if (fast == null){
return head.next;
}
//快慢指针各走一步
while (fast.next != null){
slow = slow.next;
fast = fast.next;
}
//断开
slow.next = slow.next.next;
return head;
}
12.链表中环的入口节点
//双指针改进
//时间 100
//空间 65.17
public ListNode detectCycle_3(ListNode head) {
if (head == null){
return head;
}
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
//慢指针一次走一步
//快指针一次走两步
slow = slow.next;
fast = fast.next.next;
//如果快慢指针相遇
//快指针回到头结点
//快慢指针一次走一步,相遇即为入环结点
if (slow == fast) {
fast = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
return null;
}