19. Remove Nth Node From End of List

题目描述(中等难度)

在这里插入图片描述
题目描述:给定一个链表,将倒数第 n个结点删除。

解法一

删除一个结点,无非是遍历链表找到那个结点前边的结点,然后改变下指向就好了。但由于它是链表,它的长度我们并不知道,我们得先遍历一遍得到它的长度,之后用长度减去 n 就是要删除的结点的位置,然后遍历到结点的前一个位置就好了。

Java

class ListNode {
    int val;
    ListNode next;
 
    ListNode(int val) {
        this.val = val;
    }
}

public class removeNthFromEnd {
	public static ListNode removeNthFromEnd(ListNode head, int n) {
	    int len = 0;
	    ListNode h = head;
	    while (h != null) {
	        h = h.next;
	        len++;
	    }
	    //长度等于 1 ,再删除一个结点就为 null 了
	    if (len == 1) return null;
	    
	    int rm_node_index = len - n;
	    //如果删除的是头结点
	    if (rm_node_index == 0) return head.next;					
	    //找到被删除结点的前一个结点
	    h = head;
	    for (int i = 0; i < rm_node_index - 1; i++) {
	        h = h.next;
	    }
	    //改变指向
	    h.next = h.next.next;
	    return head;
	}
	public static void main(String[] args) { 
		int n=2;
		ListNode l1 = new ListNode(1);
		ListNode p = l1; 
		p.next = new ListNode(2); 
		p = p.next; 
		p.next = new ListNode(3); 
		p = p.next; 
		p.next = new ListNode(4); 
		p=p.next;
		p.next=new ListNode(5);			
        ListNode ans=removeNthFromEnd(l1,n);
	    while(ans !=null) {
	    System.out.println(ans.val);
	    ans=ans.next;
	    }
	}
}

在这里插入图片描述
时间复杂度:假设链表长度是 L ,那么就第一个循环是 L 次,第二个循环是 L - n 次,总共 2L - n 次,所以时间复杂度就是 O(L)

空间复杂度O(1)

Python

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def removeNthFromEnd(self, head, n):
        length = 0
        h = head
        while(h!=None):
            h=h.next
            length +=1
        
        if(length == 1):
             return None

        rm_node_index=length-n
        if rm_node_index == 0:
            return head.next

        h=head
        for i in range(rm_node_index-1):
            h=h.next
        
        h.next=h.next.next
        return head

在这里插入图片描述

解法二 遍历一次链表

上边我们遍历链表进行了两次,我们如何只遍历一次呢。

想象一下,两个人进行 100m 赛跑,假设他们的速度相同。开始的时候,第一个人就在第二个人前边 10m ,这样当第一个人跑到终点的时候,第二个人相距第一个人依旧是 10m ,也就是离终点 10m。

对比于链表,我们设定两个指针,先让第一个指针遍历 n步,然后再让它俩同时开始遍历,这样的话,当第一个指针到头的时候,第二个指针就离第一个指针有 n的距离,所以第二个指针的位置就刚好是倒数第 n 个结点。

Java

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
       ListNode dummy = new ListNode(0);
       dummy.next=head;
       ListNode first = dummy;
       ListNode second = dummy;
       for(int i=1;i<=n+1;i++){
           first=first.next;
       }
       while(first!=null){
           first=first.next;
           second=second.next;
       }
       second.next=second.next.next;
       return dummy.next;
    }
}

在这里插入图片描述
时间复杂度:第一个指针从 0 到 n ,然后「第一个指针再从 n 到结束」和「第二个指针从 0 到倒数第 n 个结点的位置」同时进行。

而解法一无非是先从 0 到 结束,然后从 0 到倒数第 n 个结点的位置。

所以其实它们语句执行的次数其实是一样的,从 0 到倒数第 n 个结点的位置都被遍历了 2 次,所以总共也是 2L - n 次。只不过这个解法把解法一的两次循环合并了一下,使得第二个指针看起来是顺便遍历,想法很 nice。

所以本质上,它们其实是一样的,时间复杂度依旧是 O(n)。

空间复杂度:O(1)。

Python

class Solution(object):
    def removeNthFromEnd(self, head, n):
        dummy=ListNode(0)
        dummy.next=head
        first = dummy
        second = dummy
        for i in range(1,n+2):
            first=first.next
       
        while(first!=None):
            first=first.next
            second=second.next
       
        second.next=second.next.next
        return dummy.next

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安替-AnTi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值