话不多说我们直接上题

链表的中间节点

给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。

输入:[1,2,3,4,5,6]
输出:此列表中的结点 4
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

示例节点

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode() {}
  7. * ListNode(int val) { this.val = val; }
  8. * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
  9. * }
  10. */

因为是这种节点形式,我们不能直接的去调用方法,需要我们自己进行编写
首先,我们用最简单的做法去做一下这道题,我们直接将链表转化成数组,取中间值输出即可

  1. public ListNode middleNode(ListNode head) {
  2. ListNode [] A=new ListNode[100];
  3. int a=0;
  4. while (head!=null){
  5. A[a++]=head;
  6. head=head.next;
  7. }
  8. return A[a/2];
  9. }

优化1

当我们利用数组做完这道题的时候,我们再仔细地去想一想我们可以省略数组,我们进行两边遍历,第一次统计元素个数N,第二次遍历到N/2是时我们输出即可。

  1. public ListNode middleNode(ListNode head) {
  2. int n = 0;
  3. ListNode list = head;
  4. while (list != null) {
  5. n++;
  6. list = list.next;
  7. }
  8. int k = 0;
  9. list = head;
  10. while (k < n / 2) {
  11. k++;
  12. list = list.next;
  13. }
  14. return list;
  15. }

优化2

但这一次优化我们进行了两遍遍历,我们找链表的点是一个比较特殊的一个点,在二分之一处,使用双指针中的快慢指针,一前一后,当快指针到达链表尾部时,满指针一定在链表中间位置

  1. public ListNode middleNode(ListNode head) {
  2. ListNode slow = head, fast = head;
  3. while (fast != null && fast.next != null) {
  4. slow = slow.next;
  5. fast = fast.next.next;
  6. }
  7. return slow;
  8. }

删除链表倒数第n个节点

示例节点

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode() {}
  7. * ListNode(int val) { this.val = val; }
  8. * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
  9. * }
  10. */

因为经过上面那道题之后,思路十分明确就是先进行一遍遍历之后确定链表长度,之后在进行一遍遍历之后,删除节点,所以这道问题很简单的就解决了

  1. //删除节点函数
  2. public ListNode removeNthFromEnd(ListNode head, int n) {
  3. ListNode d=new ListNode(0,head);
  4. int lenght=get(head);
  5. ListNode c=d;
  6. for (int i=1;i<lenght-n+1;i++){
  7. c=c.next;
  8. }
  9. c.next=c.next.next;
  10. return d.next;
  11. }
  12. //获取链表长度函数
  13. public int get(ListNode head){
  14. int lenght=0;
  15. while (head!=null){
  16. lenght++;
  17. head=head.next;
  18. }
  19. return lenght;
  20. }

优化

相较于前一道题,前一道是找到中间位置,本题是指定位置,我们还是可以利用双指针,只不过之前属于定比,此题属于定差,我们只需要保证指针的距离为n,当前指针到达链表尾部是,后指针就处于n的位置

  1. public ListNode removeNthFromEnd(ListNode head, int n) {
  2. ListNode dummy = new ListNode(0, head);
  3. ListNode first = head;
  4. ListNode second = dummy;
  5. for (int i = 0; i < n; ++i) {
  6. first = first.next;
  7. }
  8. while (first != null) {
  9. first = first.next;
  10. second = second.next;
  11. }
  12. second.next = second.next.next;
  13. ListNode ans = dummy.next;
  14. return ans;
  15. }