Leetcode刷题记录Day5(C#)

876、链表的中间结点

题目描述:给定一个头结点为 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

解题:

链表一下子没有想法,于是看了一下评论,发现常用的一个方法是快慢指针

于是去查了一下快慢指针的原理:

 快慢指针找中间值的原理,其实就跟跑步一样,设置快慢两个指针。最开始,slow与fast指针都指向链表第一个节点,然后slow每次移动一个指针,fast每次移动两个指针,这样当快指针遍历完链表以后,慢指针刚遍历到一半,从而返回中间结点。

这也是本体的解题思路,代码如下:

/** //定义链表结点
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int val=0, ListNode next=null) {
 *         this.val = val;
 *         this.next = next;
 *     }
 * }
 */
public class Solution {
    public ListNode MiddleNode(ListNode head) {
        // 快慢指针
        ListNode fast = head, slow = head;
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

运行结果:

此外快慢指针还可以检查链表中是否有环,因为fast每次比slow多走一格,那么如果有环,fast和slow终究会相遇,只要相遇,必定有环。

总的来说,快慢指针擅长的场景,就是寻找链表中的某个节点。

然后对于这里链表的定义,我一开始有些不理解,但是经过琢磨,大体有了点眉目:

/** 链表结点的定义(递归定义)

* Definition for singly-linked list.

* public class ListNode {

* public int val;

* public ListNode next;

* public ListNode(int val=0, ListNode next=null) {

* this.val = val;

* this.next = next;

* }

* }

*/

对于每一个结点,都定义了该节点的值和下一个结点。

19. 删除链表的倒数第 N 个结点

题目描述:

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

进阶:你能尝试使用一趟扫描实现吗?

未进阶版本:

两次遍历,第一次遍历知道链表的长度,知道长度以后,再遍历到指定的结点,将之删除。代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int val=0, ListNode next=null) {
 *         this.val = val;
 *         this.next = next;
 *     }
 * }
 */
public class Solution {
    public ListNode RemoveNthFromEnd(ListNode head, int n) {
        ListNode fast = head ;
        int index=0;
        while(fast!=null){  //先遍历一遍链表,index是链表的长度
            fast = fast.next;
            index++;
        }
        if(index-n==0){
            if (index==1){
                head = null;
            }
            else {
                head = head.next;
            }
        }
        else{
            fast = head;
        for (int i = 0;i<index-n-1;i++){
            fast = fast.next;   //此时fast指向的是倒数第n个数的前一个数
        }
            fast.next = fast.next.next;    
        }
        return head;
    } 
}

过是过了,但是结果并不是特别好

 换了一个思路,采用一次遍历的方式,原理就是快慢双指针,fast指针比slow指针超前n个结点

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int val=0, ListNode next=null) {
 *         this.val = val;
 *         this.next = next;
 *     }
 * }
 */
public class Solution {
    public ListNode RemoveNthFromEnd(ListNode head, int n) {
        ListNode fast = head ;
        ListNode slow = head;
        for(int i =0;i<n;i++){
            fast = fast.next;
        }
        if (fast == null){
            head = head.next;
        }
        else {
            if (fast.next == null){
                head.next = head.next.next;
            }
            else {
               // fast = fast.next;
            while(fast.next != null){
                fast = fast.next;
                slow = slow.next;  //最终slow指向要删除结点的前一个结点
            }
            slow.next = slow.next.next;
            }
        }
        return head;
    }
}

结果却更加不好了。。。

 同样的思路,大神的代码又是比我简洁亿点点:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int val=0, ListNode next=null) {
 *         this.val = val;
 *         this.next = next;
 *     }
 * }
 */
public class Solution {
    public ListNode RemoveNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        ListNode first = head;
        ListNode second = dummy;
        for (int i = 0; i < n; ++i) {
            first = first.next;
        }
        while (first != null) {
            first = first.next;
            second = second.next;
        }
        second.next = second.next.next;
        ListNode ans = dummy.next;
        return ans;
    }
}

其实大神和我的差距,就是一个哑结点(dummy ListNode)而已。。。

在对链表进行操作时,一种常用的技巧是添加一个哑节点(dummy node),它的next 指针指向链表的头节点(即头结点的前驱结点就是哑结点)。这样一来,我们就不需要对头节点进行特殊的判断了,只需要考虑通用的情况即可。

在本题中,通过添加哑结点,在移动后,需要删除的结点就是second指针指向结点的后一个结点,所有情况都是。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值