Title Description
This is from niuke.com“JZ 56 delete duplicate nodes in the linked list“, difficulty is“More difficult” 。
Tag: “sword finger offer”, “linked list”, “single linked list”
In a sorted linked list, there are duplicate nodes. Please delete the duplicate nodes in the linked list. The duplicate nodes are not retained and the chain header pointer is returned.
For example, linked lists1->2->3->3->4->4->5
After treatment1->2->5
Example 1:
Input: {1,3,4,4,3}
Return value: {1,2,5}
requirement:
- Time: 1 s
- Space: 64 m
iterative method
First, a more “intuitive and general” idea is to adopt the method of “traversing while constructing”:
- Create a “virtual header node”
dummy
To reduce boundary judgment, the subsequent answer list will be connected todummy
Behind; - use
tail
Represents the end of the currently valid linked list; - Through original input
pHead
Scan the linked list with the pointer.
Traverse the original linked list. As long as the original linked list has not reached the end, we will repeat the following decision (keep / skip logic):
- retain:
pHead
There is no next node,pHead
Pointer that can be retained (inserted at the end of the answer)tail
Back);pHead
There is a node, but the value is the same aspHead
inequality,pHead
Can be retained; - Skip: when found
pHead
If the value is the same as the next node, you need to skip the “same continuous segment”.
For example, take the title as an example[1,2,3,3,4,4,5]
For example, use a graphical way to feel it.
- The values of current node and next node are different. The current node is reserved:
- The values of current node and next node are the same. Skip the same continuous segment. The current node cannot be retained:
code:
class Solution {
public ListNode deleteDuplication(ListNode pHead) {
ListNode dummy = new ListNode(-1);
ListNode tail = dummy;
while (pHead != null) {
//When entering the loop, make sure that the {phead} is not the same as the previous node
if (pHead.next == null || pHead.next.val != pHead.val) {
tail.next = pHead;
tail = pHead;
}
//If {phead} is the same as the next node, skip the same node (reach the last bit of "continuous same section")
while (pHead.next != null && pHead.val == pHead.next.val) pHead = pHead.next;
pHead = pHead.next;
}
tail.next = null;
return dummy.next;
}
}
- Time complexity:
- Space complexity:
Recursive solution
Compared with iterative solution, recursive solution has simpler code, but higher thinking difficulty.
First of all, whether it is a “linked list” topic or not, before implementing recursion, we need to clarify “what function we expect the recursive function to complete”, that is, design our recursive function signature.
Obviously, we want to have a recursive function: the incoming chain header node, delete the duplicate elements of the incoming chain list, and return the chain header node after the operation.
This function and topic are to be realized by usdeleteDuplication
Functions are the same, so we can directly use the original function as a recursive function.
Then consider “recursive exit” and “minimum operation of recursive link”:
- Recursive exit: consider the case where we no longer need the “delete” operation. Obviously, when you pass in parameters
pHead
Is empty, orpHead.next
If it is empty, there must be no duplicate element and it can be returned directlypHead
; - Minimum operation of recursive link: consider how to delete logic later:
- Obviously, when
pHead.val != pHead.next.val
When,pHead
Can be retained, so we just need topHead.next
Pass in a recursive function and take the return value aspHead.next
, then returnpHead
OK; - When
pHead.val == pHead.next.val
When,pHead
Cannot be reserved, we need to use temporary variablestmp
Skip andpHead.val
A continuous segment with the same value willtmp
The result obtained by passing in the recursive function is returned as this time.
code:
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
//Recursive exit: when the "input node is empty" or "there is no next node", it returns directly
if (pHead == null || pHead.next == null) return pHead;
if (pHead.val != pHead.next.val) {
//If the values of "current node" and "next node" are different, the current node can be retained
pHead.next = deleteDuplication(pHead.next);
return pHead;
} else {
//If the current node is the same as the next node, you need to skip a continuous segment with the same value
ListNode tmp = pHead;
while (tmp != null && tmp.val == pHead.val) tmp = tmp.next;
return deleteDuplication(tmp);
}
}
}
- Time complexity:
- Space complexity: ignoring the additional space overhead caused by recursion, the complexity is
expand
- If the problem becomes “keep one for the same node”, how to implement it?
The essence has not changed. Just grasp “when nodes can be retained during traversal”.
code:
class Solution {
public ListNode deleteDuplication(ListNode head) {
if (head == null) return head;
ListNode dummy = new ListNode(-109);
ListNode tail = dummy;
while (head != null) {
//If the values are not equal, they are appended to ensure that only the first node of the same node will be added to the answer
if (tail.val != head.val) {
tail.next = head;
tail = tail.next;
}
head = head.next;
}
tail.next = null;
return dummy.next;
}
}
- Time complexity:
- Space complexity:
last
This is the third article in our “selected sword fingers” seriesNo.56
The series began on July 1, 2021.
This series will cover all the classic and timeless topics in “sword finger offer”.
While providing the pursuit of “proof” & “ideas”, it also provides the most concise code.
Welcome to pay attention and make a friend ω ・´)