Title Description (Medium Difficulty)
Given a list of chains, delete the nth last node.
My Solution
Deleting a node is all about traversing the list to find the node in front of that node and changing the downward direction.However, since it is a chain list, we don't know its length. We have to traverse it once to get its length, then subtract n from the length to delete the location of the node, and then traverse to the previous location of the node.
public ListNode removeNthFromEnd(ListNode head, int n) { int len = 0; ListNode h = head; while (h != null) { h = h.next; len++; } //Length equals 1, deleting another node is null if (len == 1) { return null; } int rm_node_index = len - n; //If the header node is deleted if (rm_node_index == 0) { return head.next; } //Find the previous node of the deleted node h = head; for (int i = 0; i < rm_node_index - 1; i++) { h = h.next; } //Change Point h.next = h.next.next; return head; }
Time Complexity: Assuming the chain table length is L, then the first cycle is L times, and the second is L - n times, totaling 2 L - n times, so the time complexity is O (L).
Spatial complexity: O (1).
We see that if the length equals 1 and the head node is deleted, we need to make a separate judgment. In fact, we only need to add an empty node in front of the head to avoid making a separate judgment.
public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0); dummy.next = head; int length = 0; ListNode first = head; while (first != null) { length++; first = first.next; } length -= n; first = dummy; while (length > 0) { length--; first = first.next; } first.next = first.next.next; return dummy.next; }
Solution Two Traverses a Chain List
We've traversed the list twice above. How can we traverse it only once?
See leetcode Explanation of.
Imagine two people running a 100m race, assuming they are at the same speed.At the beginning, the first person is 10m in front of the second person, so when the first person runs to the end point, the second person is still 10m from the first person, that is, 10m from the end point.
In contrast to the list of chains, we set two pointers, let the first pointer traverse n steps first, then let them start traversing at the same time, so when the first pointer ends, the second pointer is n away from the first pointer, so the second pointer is positioned exactly at the nth node from the bottom.
public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0); dummy.next = head; ListNode first = dummy; ListNode second = dummy; //The first pointer moves n steps first for (int i = 1; i <= n + 1; i++) { first = first.next; } //The first pointer reaches the end and stops traversing while (first != null) { first = first.next; second = second.next; } second.next = second.next.next; return dummy.next; }
Time Complexity:
The first pointer goes from 0 to n, then the first pointer goes from n to end and the second pointer goes from 0 to the position of the last nth node.
The solution is to go from 0 to the end, then from 0 to the position of the nth last node.
So in fact, their statements execute the same number of times, from 0 to the position of the last nth node has been traversed twice, so the total is also 2L - n times.But this solution combines the two loops of the solution one and makes the second pointer look like it's traversing conveniently, which is a nice idea.
So essentially, they are the same, and the time complexity is still O(n).
Spatial complexity: O (1).
Solution 3
Without looking at the explanation, discuss with your roommate how to traverse the list only once.My roommate gave me an idea that I can't even refute. Ha-ha-ha.
The first time you traverse the list to determine the length, you will save each node in an array, so you don't need to traverse the list again when you find the node, space changes time???Ha Ha Ha Ha Ha Ha Ha Ha.
public ListNode removeNthFromEnd(ListNode head, int n) { List<ListNode> l = new ArrayList<ListNode>(); ListNode h = head; int len = 0; while (h != null) { l.add(h); h = h.next; len++; } if (len == 1) { return null; } int remove = len - n; if (remove == 0) { return head.next; } //Get it directly, no more traversal ListNode r = l.get(remove - 1); r.next = r.next.next; return head; }
Time complexity: O (L).
Spatial Complexity: O(L).
total
It's really wonderful to use two pointers to fix the interval first and then walk through it at the same time!Also, your roommate's idea is great. Ha-ha-ha-ha.
More detailed explanation of popular topics leetcode.wang .