1.删除链表中的节点
1.1解答

/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/class Solution {public void deleteNode(ListNode node) {//把要删除结点的下一个结点的值赋给要删除的结点node.val = node.next.val;//然后删除下一个结点node.next = node.next.next;}}
2.单向反转链表
2.1使用递归解决√
public ListNode reverseList(ListNode head) {//终止条件if (head == null || head.next == null)return head;//保存当前节点的下一个结点ListNode next = head.next;//从当前节点的下一个结点开始递归调用ListNode reverse = reverseList(next);/*reverse是反转之后的链表,因为函数reverseList表示的是对链表的反转,所以反转完之后next肯定是链表reverse的尾结点,然后我们再把当前节点*///head挂到next节点的后面就完成了链表的反转。next.next = head;//这里head相当于变成了尾结点,尾结点都是为空的,//否则会构成环head.next = null;return reverse;}-------------------------------------------------------------自己的想法:/*** Definition for singly-linked list.* 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; }* }*/class Solution {public ListNode reverseList(ListNode head) {//定位到末结点if(head.next==null||head==null)return head;//3->4->5->1 假如当前head=node3,reverseList(head.next)=reverseList(node4)=node4=newHeadListNode newHead = reverseList(head.next);head.next.next = head;//即node4.next=node3head.next=null;//即node3.next=null 实现: node4->node3->nullreturn newHead;}}
2.2尾递归*
public ListNode reverseList(ListNode head) {return reverseListInt(head, null);}private ListNode reverseListInt(ListNode head, ListNode newHead) {if (head == null)return newHead;ListNode next = head.next;head.next = newHead;return reverseListInt(next, head);}
2.3使用栈解决

class Solution {public ListNode reverseList(ListNode head) {Stack<ListNode> stack = new Stack<>();//将每个结点放入栈中while(head!=null){stack.push(head);head = head.next;}//若栈为空,即没有结点,返回nullif (stack.isEmpty())return null;//以第一个弹出的结点为头结点ListNode node = stack.pop();ListNode newHead = node;//依次弹栈接入头结点尾后while(!stack.isEmpty()){ListNode temp = stack.pop();node.next=temp;node = node.next;}//让尾结点的next为nullnode.next = null;return newHead;}}
2.4双链表求解

class Solution {public ListNode reverseList(ListNode head) {ListNode newHead = null;while(head!=null){//先保存访问的节点的下一个节点,保存起来留着下一步访问的ListNode temp = head.next;//每次访问的原链表节点都会成为新链表的头结点,其实就是把新链表挂到访问的原链表节点的后面就行了head.next = newHead;//更新新链表newHead = head;//重新赋值,继续访问head = temp;}return newHead;}}----------------------------------------------------------------class Solution {public ListNode reverseList(ListNode head) {ListNode newHead = null;while(head!=null){ListNode temp = head.next;head.next=newHead;//核心newHead=head;head=temp;}return newHead;}}
3.合并两个有序链表
3.1解法一√
因为链表是升序的,我们只需要遍历每个链表的头,比较一下哪个小就把哪个链表的头拿出来放到新的链表中,一直这样循环,直到有一个链表为空,然后我们再把另一个不为空的链表挂到新的链表中。
以3→4→7→9和2→5→6两个链表来画个图看一下是怎么合并的。
public ListNode mergeTwoLists(ListNode linked1, ListNode linked2) {if (linked1 == null)return linked2;if (linked2 == null)return linked1;ListNode dummy = new ListNode(0);ListNode curr = dummy;//两结点地址相同,修改curr的后续就相当于修改dummy的后续while (linked1 != null && linked2 != null) {//比较一下,哪个小就把哪个放到新的链表中if (linked1.val <= linked2.val) {curr.next = linked1;linked1 = linked1.next;} else {curr.next = linked2;linked2 = linked2.next;}curr = curr.next;}//然后把那个不为空的链表挂到新的链表中curr.next = linked1 == null ? linked2 : linked1;return dummy.next;}
3.2解法二递归(难理解)

public ListNode mergeTwoLists(ListNode linked1, ListNode linked2) {if (linked1 == null)return linked2;if (linked2 == null)return linked1;if (linked1.val < linked2.val) {linked1.next = mergeTwoLists(linked1.next, linked2);return linked1;} else {linked2.next = mergeTwoLists(linked1, linked2.next);return linked2;}}--------------------------------------------------------------public ListNode mergeTwoLists(ListNode linked1, ListNode linked2) {if (linked1 == null || linked2 == null)return linked2 == null ? linked1 : linked2;ListNode first = (linked2.val < linked1.val) ? linked2 : linked1;first.next = mergeTwoLists(first.next, first == linked1 ? linked2 : linked1);return first;}
4.判断回文链表
4.1使用栈解决(简易)
class Solution {public boolean isPalindrome(ListNode head) {Stack<Integer> stack = new Stack<>();ListNode temp = head;while(temp!=null){stack.push(temp.val);temp=temp.next;}boolean flag = true;while(head!=null){if(head.val!=stack.pop()){flag=false;}head=head.next;}return flag;}}
这里相当于链表从前往后全部都比较了一遍,其实我们只需要拿链表的后半部分和前半部分比较即可,没必要全部比较,所以这里可以优化一下
public boolean isPalindrome(ListNode head) {if (head == null)return true;ListNode temp = head;Stack<Integer> stack = new Stack();//链表的长度int len = 0;//把链表节点的值存放到栈中while (temp != null) {stack.push(temp.val);temp = temp.next;len++;}//len长度除以2len >>= 1;//然后再出栈while (len-- >= 0) {if (head.val != stack.pop())return false;head = head.next;}return true;}
4.2反转后半部分链表(较难)
/*** Definition for singly-linked list.* 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; }* }*/class Solution {public boolean isPalindrome(ListNode head) {ListNode fast = head, slow = head;//假设链表为1->2->3->4->3->2->1//通过快慢指针找到中点while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;//1->2->3->4->3->2->1 fast=3 slow=2 - fast=3 slow=3 - fast=1 slow=4 fasst.next=null 结束循环}//如果fast不为空,说明链表的长度是奇数个if (fast != null) {//fast=node7 !=null 长度为奇数,slow=slow.next=node5slow = slow.next;}//反转后半部分链表slow = reverse(slow);//反转后结果为1->2->3->nullfast = head;//将快指针重新指向head 用于判断前半部分与后半部分是否相同while (slow != null) {//然后比较,判断节点值是否相等if (fast.val != slow.val)return false;fast = fast.next;slow = slow.next;}return true;}//反转链表public ListNode reverse(ListNode head) {//假如后半部分传来的链表为3->2->1->nullwhile(head==null||head.next==null){return head;}ListNode newHead = reverse(head.next);//2.next!=null 当前为head2 newHead=1head.next.next=head;//1->2head.next=null;//1->2->nullreturn newHead;}}
总结:通过快慢指针找到后半部分链表,反转后半部分链表(也是可以考虑用栈的思想),将前后部分链表进行对比,如果结点都相同,则该链表为回文链表。
5.判断环形链表
5.1快慢指针
public boolean hasCycle(ListNode head) {if(head==null){return false;}ListNode slow = head;ListNode fast = head;while(fast!=null&&fast.next!=null){slow=slow.next;fast=fast.next.next;if(slow==fast){return true;}}return false;}
